Compare commits
123 Commits
ashwin/err
...
0.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d567ff37e8 | ||
|
|
2e4eedc6ef | ||
|
|
56ec9befd9 | ||
|
|
360d090ac9 | ||
|
|
fda05836cb | ||
|
|
dac692e638 | ||
|
|
7e4b276f7f | ||
|
|
668448b047 | ||
|
|
4352c93660 | ||
|
|
22bf78720b | ||
|
|
9196c1ddaf | ||
|
|
dfc10488b2 | ||
|
|
78182eab10 | ||
|
|
7dbaee47a2 | ||
|
|
03193a9dc4 | ||
|
|
60dea9a868 | ||
|
|
1341d73775 | ||
|
|
f73770b143 | ||
|
|
33ab8dbd97 | ||
|
|
2d5c866f82 | ||
|
|
232d5ffcf6 | ||
|
|
4f930a61ab | ||
|
|
f684d2e891 | ||
|
|
676de45bab | ||
|
|
9a560e3f06 | ||
|
|
64d2fea0f1 | ||
|
|
1843562dce | ||
|
|
31630b2870 | ||
|
|
7c04df5e2e | ||
|
|
f8e26479d9 | ||
|
|
0c6b1ad1d2 | ||
|
|
b97acb9b76 | ||
|
|
1b06e50203 | ||
|
|
83abe4e00f | ||
|
|
75bc2d3f26 | ||
|
|
b127ba177a | ||
|
|
ce350433f9 | ||
|
|
c1a56810fb | ||
|
|
abff2486c1 | ||
|
|
b096f3f991 | ||
|
|
e97ec8dbc7 | ||
|
|
05c22f6367 | ||
|
|
3b3a7e6015 | ||
|
|
8986c32bb4 | ||
|
|
69b25300da | ||
|
|
6e72c7583e | ||
|
|
d1c9acffc2 | ||
|
|
d91d7e8ae0 | ||
|
|
6c27f5a263 | ||
|
|
2bf84a3ef3 | ||
|
|
8aad8b4aac | ||
|
|
06267d28f4 | ||
|
|
c1c8fc2f42 | ||
|
|
7a350785fe | ||
|
|
41f8ec0868 | ||
|
|
09d66ab704 | ||
|
|
e4faa19acb | ||
|
|
f7385dd961 | ||
|
|
54012aca6a | ||
|
|
0cf344bb6a | ||
|
|
a507bafc3e | ||
|
|
93b1ec4d61 | ||
|
|
bf2ddc9b7b | ||
|
|
da2ac8d423 | ||
|
|
3bae26723a | ||
|
|
9d0c643926 | ||
|
|
0716adafc6 | ||
|
|
733d2a6e6e | ||
|
|
ab9c130610 | ||
|
|
3e46011614 | ||
|
|
584c1076a4 | ||
|
|
de9ee3956e | ||
|
|
01fb48e6ef | ||
|
|
5ceaa48cf3 | ||
|
|
6fdb2903a4 | ||
|
|
b9d6695fbf | ||
|
|
3789ef984a | ||
|
|
e1aa419332 | ||
|
|
94e4e92618 | ||
|
|
148e84388a | ||
|
|
6147640656 | ||
|
|
1ddd2d7aaa | ||
|
|
94ddfed1ac | ||
|
|
448910d986 | ||
|
|
3a9b08bd37 | ||
|
|
bce3a7b8d6 | ||
|
|
196f2f801d | ||
|
|
a0d8ec1e7e | ||
|
|
6759c461f9 | ||
|
|
ea4484cc04 | ||
|
|
171b59bec6 | ||
|
|
2867173e7b | ||
|
|
57f0c49154 | ||
|
|
5337baa116 | ||
|
|
afefcb3fa5 | ||
|
|
76e2cf6fdc | ||
|
|
193032533b | ||
|
|
f3406ca43d | ||
|
|
645f2e942e | ||
|
|
d80214d0a2 | ||
|
|
97b67ca1ae | ||
|
|
216c8a15d5 | ||
|
|
752631f5a1 | ||
|
|
2acc6290c8 | ||
|
|
5427a6ec7c | ||
|
|
daa329b3bd | ||
|
|
a5606f7ac7 | ||
|
|
7926eea39c | ||
|
|
a798c5528e | ||
|
|
8ff82d7f78 | ||
|
|
69a4a7461d | ||
|
|
c4628d27cd | ||
|
|
702f827f74 | ||
|
|
82f3d99639 | ||
|
|
0d66867701 | ||
|
|
5da417470f | ||
|
|
b4c70edb78 | ||
|
|
bfa23c9de8 | ||
|
|
f40854fa74 | ||
|
|
956e2b4b42 | ||
|
|
6239453604 | ||
|
|
6acd606a7e | ||
|
|
a16649be87 |
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -1,2 +1 @@
|
|||||||
yarn.lock linguist-generated=true
|
package-lock.json linguist-generated=true
|
||||||
packages/**/* linguist-generated=true
|
|
||||||
|
|||||||
52
.github/workflows/main.yml
vendored
Normal file
52
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
cache: npm
|
||||||
|
|
||||||
|
# Working around https://github.com/npm/cli/issues/4828
|
||||||
|
# - run: npm ci
|
||||||
|
- run: npm install --no-package-lock
|
||||||
|
- run: npm run build
|
||||||
|
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
environment: release
|
||||||
|
needs: build
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
cache: npm
|
||||||
|
registry-url: "https://registry.npmjs.org"
|
||||||
|
|
||||||
|
# Working around https://github.com/npm/cli/issues/4828
|
||||||
|
# - run: npm ci
|
||||||
|
- run: npm install --no-package-lock
|
||||||
|
|
||||||
|
# TODO: Add --provenance once the repo is public
|
||||||
|
- run: npm run publish-all
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
2
.npmrc
Normal file
2
.npmrc
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
registry="https://registry.npmjs.org/"
|
||||||
|
@modelcontextprotocol:registry="https://registry.npmjs.org/"
|
||||||
128
CODE_OF_CONDUCT.md
Normal file
128
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
We as members, contributors, and leaders pledge to make participation in our
|
||||||
|
community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||||
|
identity and expression, level of experience, education, socio-economic status,
|
||||||
|
nationality, personal appearance, race, religion, or sexual identity
|
||||||
|
and orientation.
|
||||||
|
|
||||||
|
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||||
|
diverse, inclusive, and healthy community.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to a positive environment for our
|
||||||
|
community include:
|
||||||
|
|
||||||
|
* Demonstrating empathy and kindness toward other people
|
||||||
|
* Being respectful of differing opinions, viewpoints, and experiences
|
||||||
|
* Giving and gracefully accepting constructive feedback
|
||||||
|
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||||
|
and learning from the experience
|
||||||
|
* Focusing on what is best not just for us as individuals, but for the
|
||||||
|
overall community
|
||||||
|
|
||||||
|
Examples of unacceptable behavior include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery, and sexual attention or
|
||||||
|
advances of any kind
|
||||||
|
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or email
|
||||||
|
address, without their explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Enforcement Responsibilities
|
||||||
|
|
||||||
|
Community leaders are responsible for clarifying and enforcing our standards of
|
||||||
|
acceptable behavior and will take appropriate and fair corrective action in
|
||||||
|
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||||
|
or harmful.
|
||||||
|
|
||||||
|
Community leaders have the right and responsibility to remove, edit, or reject
|
||||||
|
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||||
|
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||||
|
decisions when appropriate.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies within all community spaces, and also applies when
|
||||||
|
an individual is officially representing the community in public spaces.
|
||||||
|
Examples of representing our community include using an official e-mail address,
|
||||||
|
posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported to the community leaders responsible for enforcement at
|
||||||
|
mcp-coc@anthropic.com.
|
||||||
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
reporter of any incident.
|
||||||
|
|
||||||
|
## Enforcement Guidelines
|
||||||
|
|
||||||
|
Community leaders will follow these Community Impact Guidelines in determining
|
||||||
|
the consequences for any action they deem in violation of this Code of Conduct:
|
||||||
|
|
||||||
|
### 1. Correction
|
||||||
|
|
||||||
|
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||||
|
unprofessional or unwelcome in the community.
|
||||||
|
|
||||||
|
**Consequence**: A private, written warning from community leaders, providing
|
||||||
|
clarity around the nature of the violation and an explanation of why the
|
||||||
|
behavior was inappropriate. A public apology may be requested.
|
||||||
|
|
||||||
|
### 2. Warning
|
||||||
|
|
||||||
|
**Community Impact**: A violation through a single incident or series
|
||||||
|
of actions.
|
||||||
|
|
||||||
|
**Consequence**: A warning with consequences for continued behavior. No
|
||||||
|
interaction with the people involved, including unsolicited interaction with
|
||||||
|
those enforcing the Code of Conduct, for a specified period of time. This
|
||||||
|
includes avoiding interactions in community spaces as well as external channels
|
||||||
|
like social media. Violating these terms may lead to a temporary or
|
||||||
|
permanent ban.
|
||||||
|
|
||||||
|
### 3. Temporary Ban
|
||||||
|
|
||||||
|
**Community Impact**: A serious violation of community standards, including
|
||||||
|
sustained inappropriate behavior.
|
||||||
|
|
||||||
|
**Consequence**: A temporary ban from any sort of interaction or public
|
||||||
|
communication with the community for a specified period of time. No public or
|
||||||
|
private interaction with the people involved, including unsolicited interaction
|
||||||
|
with those enforcing the Code of Conduct, is allowed during this period.
|
||||||
|
Violating these terms may lead to a permanent ban.
|
||||||
|
|
||||||
|
### 4. Permanent Ban
|
||||||
|
|
||||||
|
**Community Impact**: Demonstrating a pattern of violation of community
|
||||||
|
standards, including sustained inappropriate behavior, harassment of an
|
||||||
|
individual, or aggression toward or disparagement of classes of individuals.
|
||||||
|
|
||||||
|
**Consequence**: A permanent ban from any sort of public interaction within
|
||||||
|
the community.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||||
|
version 2.0, available at
|
||||||
|
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||||
|
|
||||||
|
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||||
|
enforcement ladder](https://github.com/mozilla/diversity).
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see the FAQ at
|
||||||
|
https://www.contributor-covenant.org/faq. Translations are available at
|
||||||
|
https://www.contributor-covenant.org/translations.
|
||||||
37
CONTRIBUTING.md
Normal file
37
CONTRIBUTING.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# Contributing to Model Context Protocol Inspector
|
||||||
|
|
||||||
|
Thanks for your interest in contributing! This guide explains how to get involved.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
1. Fork the repository and clone it locally
|
||||||
|
2. Install dependencies with `npm install`
|
||||||
|
3. Run `npm run dev` to start both client and server in development mode
|
||||||
|
4. Use the web UI at http://localhost:5173 to interact with the inspector
|
||||||
|
|
||||||
|
## Development Process & Pull Requests
|
||||||
|
|
||||||
|
1. Create a new branch for your changes
|
||||||
|
2. Make your changes following existing code style and conventions
|
||||||
|
3. Test changes locally
|
||||||
|
4. Update documentation as needed
|
||||||
|
5. Use clear commit messages explaining your changes
|
||||||
|
6. Verify all changes work as expected
|
||||||
|
7. Submit a pull request
|
||||||
|
8. PRs will be reviewed by maintainers
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
This project follows our [Code of Conduct](CODE_OF_CONDUCT.md). Please read it before contributing.
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
If you find a security vulnerability, please refer to our [Security Policy](SECURITY.md) for reporting instructions.
|
||||||
|
|
||||||
|
## Questions?
|
||||||
|
|
||||||
|
Feel free to [open an issue](https://github.com/modelcontextprotocol/mcp-inspector/issues) for questions or create a discussion for general topics.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
By contributing, you agree that your contributions will be licensed under the MIT license.
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Anthropic, PBC
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
21
README.md
21
README.md
@@ -2,23 +2,18 @@
|
|||||||
|
|
||||||
The MCP inspector is a developer tool for testing and debugging MCP servers.
|
The MCP inspector is a developer tool for testing and debugging MCP servers.
|
||||||
|
|
||||||
Setup:
|
It can be run easily from `npx`. For example, in a folder where there's a built JavaScript server at `build/index.js`:
|
||||||
|
|
||||||
```bash
|
```
|
||||||
yarn
|
npx @modelcontextprotocol/inspector build/index.js
|
||||||
```
|
```
|
||||||
|
|
||||||
You can run it in dev mode via:
|
You can also pass arguments along to the server:
|
||||||
|
|
||||||
```bash
|
```
|
||||||
yarn dev
|
npx @modelcontextprotocol/inspector build/index.js arg1 arg2 ...
|
||||||
```
|
```
|
||||||
|
|
||||||
This will start both the client and server.
|
## License
|
||||||
|
|
||||||
To run in production mode:
|
This project is licensed under the MIT License—see the [LICENSE](LICENSE) file for details.
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn build
|
|
||||||
yarn start
|
|
||||||
```
|
|
||||||
|
|||||||
14
SECURITY.md
Normal file
14
SECURITY.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Security Policy
|
||||||
|
Thank you for helping us keep the inspector secure.
|
||||||
|
|
||||||
|
## Reporting Security Issues
|
||||||
|
|
||||||
|
This project is maintained by [Anthropic](https://www.anthropic.com/) as part of the Model Context Protocol project.
|
||||||
|
|
||||||
|
The security of our systems and user data is Anthropic’s top priority. We appreciate the work of security researchers acting in good faith in identifying and reporting potential vulnerabilities.
|
||||||
|
|
||||||
|
Our security program is managed on HackerOne and we ask that any validated vulnerability in this functionality be reported through their [submission form](https://hackerone.com/anthropic-vdp/reports/new?type=team&report_type=vulnerability).
|
||||||
|
|
||||||
|
## Vulnerability Disclosure Program
|
||||||
|
|
||||||
|
Our Vulnerability Program Guidelines are defined on our [HackerOne program page](https://hackerone.com/anthropic-vdp).
|
||||||
65
bin/cli.js
Executable file
65
bin/cli.js
Executable file
@@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import { join, dirname } from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
import concurrently from "concurrently";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
// Get command line arguments
|
||||||
|
const [, , command, ...mcpServerArgs] = process.argv;
|
||||||
|
|
||||||
|
const inspectorServerPath = join(__dirname, "../server/build/index.js");
|
||||||
|
|
||||||
|
// Path to the client entry point
|
||||||
|
const inspectorClientPath = join(__dirname, "../client/bin/cli.js");
|
||||||
|
|
||||||
|
console.log("Starting MCP inspector...");
|
||||||
|
|
||||||
|
function escapeArg(arg) {
|
||||||
|
if (arg.includes(" ") || arg.includes("'") || arg.includes('"')) {
|
||||||
|
return `\\"${arg.replace(/"/g, '\\\\\\"')}\\"`;
|
||||||
|
}
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverCommand = [
|
||||||
|
`node`,
|
||||||
|
inspectorServerPath,
|
||||||
|
command ? `--env ${escapeArg(command)}` : "",
|
||||||
|
mcpServerArgs.length
|
||||||
|
? `--args="${mcpServerArgs.map(escapeArg).join(" ")}"`
|
||||||
|
: "",
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(" ");
|
||||||
|
|
||||||
|
const CLIENT_PORT = process.env.CLIENT_PORT ?? "";
|
||||||
|
const SERVER_PORT = process.env.SERVER_PORT ?? "";
|
||||||
|
|
||||||
|
const { result } = concurrently(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
command: `PORT=${SERVER_PORT} ${serverCommand}`,
|
||||||
|
name: "server",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: `PORT=${CLIENT_PORT} node ${inspectorClientPath}`,
|
||||||
|
name: "client",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
prefix: "name",
|
||||||
|
killOthers: ["failure", "success"],
|
||||||
|
restartTries: 3,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`\n🔍 MCP Inspector is up and running at http://localhost:${CLIENT_PORT || 5173} 🚀`,
|
||||||
|
);
|
||||||
|
|
||||||
|
result.catch((err) => {
|
||||||
|
console.error("An error occurred:", err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
16
client/bin/cli.js
Executable file
16
client/bin/cli.js
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import { join, dirname } from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
import handler from "serve-handler";
|
||||||
|
import http from "http";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const distPath = join(__dirname, "../dist");
|
||||||
|
|
||||||
|
const server = http.createServer((request, response) => {
|
||||||
|
return handler(request, response, { public: distPath });
|
||||||
|
});
|
||||||
|
|
||||||
|
const port = process.env.PORT || 5173;
|
||||||
|
server.listen(port, () => {});
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/mcp.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Vite + React + TS</title>
|
<title>MCP Inspector</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -1,8 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "client",
|
"name": "@modelcontextprotocol/inspector-client",
|
||||||
"private": true,
|
"version": "0.2.0",
|
||||||
"version": "0.0.0",
|
"description": "Client-side application for the Model Context Protocol inspector",
|
||||||
|
"license": "MIT",
|
||||||
|
"author": "Anthropic, PBC (https://anthropic.com)",
|
||||||
|
"homepage": "https://modelcontextprotocol.io",
|
||||||
|
"bugs": "https://github.com/modelcontextprotocol/inspector/issues",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"bin": {
|
||||||
|
"mcp-inspector-client": "./bin/cli.js"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"bin",
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
@@ -10,6 +21,7 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@modelcontextprotocol/sdk": "0.7.0",
|
||||||
"@radix-ui/react-icons": "^1.3.0",
|
"@radix-ui/react-icons": "^1.3.0",
|
||||||
"@radix-ui/react-label": "^2.1.0",
|
"@radix-ui/react-label": "^2.1.0",
|
||||||
"@radix-ui/react-select": "^2.1.2",
|
"@radix-ui/react-select": "^2.1.2",
|
||||||
@@ -18,9 +30,10 @@
|
|||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"lucide-react": "^0.447.0",
|
"lucide-react": "^0.447.0",
|
||||||
"mcp-typescript": "file:../packages/mcp-typescript",
|
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
"react-toastify": "^10.0.6",
|
||||||
|
"serve-handler": "^6.1.6",
|
||||||
"tailwind-merge": "^2.5.3",
|
"tailwind-merge": "^2.5.3",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
@@ -30,6 +43,7 @@
|
|||||||
"@types/node": "^22.7.5",
|
"@types/node": "^22.7.5",
|
||||||
"@types/react": "^18.3.10",
|
"@types/react": "^18.3.10",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
|
"@types/serve-handler": "^6.1.4",
|
||||||
"@vitejs/plugin-react": "^4.3.2",
|
"@vitejs/plugin-react": "^4.3.2",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"eslint": "^9.11.1",
|
"eslint": "^9.11.1",
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ export default {
|
|||||||
tailwindcss: {},
|
tailwindcss: {},
|
||||||
autoprefixer: {},
|
autoprefixer: {},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
12
client/public/mcp.svg
Normal file
12
client/public/mcp.svg
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<svg width="180" height="180" viewBox="0 0 180 180" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_19_13)">
|
||||||
|
<path d="M18 84.8528L85.8822 16.9706C95.2548 7.59798 110.451 7.59798 119.823 16.9706V16.9706C129.196 26.3431 129.196 41.5391 119.823 50.9117L68.5581 102.177" stroke="black" stroke-width="12" stroke-linecap="round"/>
|
||||||
|
<path d="M69.2652 101.47L119.823 50.9117C129.196 41.5391 144.392 41.5391 153.765 50.9117L154.118 51.2652C163.491 60.6378 163.491 75.8338 154.118 85.2063L92.7248 146.6C89.6006 149.724 89.6006 154.789 92.7248 157.913L105.331 170.52" stroke="black" stroke-width="12" stroke-linecap="round"/>
|
||||||
|
<path d="M102.853 33.9411L52.6482 84.1457C43.2756 93.5183 43.2756 108.714 52.6482 118.087V118.087C62.0208 127.459 77.2167 127.459 86.5893 118.087L136.794 67.8822" stroke="black" stroke-width="12" stroke-linecap="round"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_19_13">
|
||||||
|
<rect width="180" height="180" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 973 B |
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,75 +1,127 @@
|
|||||||
import { Client } from "mcp-typescript/client/index.js";
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
||||||
import { SSEClientTransport } from "mcp-typescript/client/sse.js";
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
||||||
import {
|
import {
|
||||||
ListResourcesResultSchema,
|
ClientNotification,
|
||||||
GetPromptResultSchema,
|
|
||||||
ListToolsResultSchema,
|
|
||||||
ReadResourceResultSchema,
|
|
||||||
CallToolResultSchema,
|
|
||||||
ListPromptsResultSchema,
|
|
||||||
Resource,
|
|
||||||
Tool,
|
|
||||||
ClientRequest,
|
ClientRequest,
|
||||||
ProgressNotificationSchema,
|
CompatibilityCallToolResult,
|
||||||
ServerNotification,
|
CompatibilityCallToolResultSchema,
|
||||||
|
CreateMessageRequestSchema,
|
||||||
|
CreateMessageResult,
|
||||||
EmptyResultSchema,
|
EmptyResultSchema,
|
||||||
} from "mcp-typescript/types.js";
|
GetPromptResultSchema,
|
||||||
import { useState, useRef } from "react";
|
ListPromptsResultSchema,
|
||||||
import {
|
ListResourcesResultSchema,
|
||||||
Send,
|
ListResourceTemplatesResultSchema,
|
||||||
Terminal,
|
ListRootsRequestSchema,
|
||||||
Files,
|
ListToolsResultSchema,
|
||||||
Bell,
|
ProgressNotificationSchema,
|
||||||
MessageSquare,
|
ReadResourceResultSchema,
|
||||||
Hammer,
|
Request,
|
||||||
Play,
|
Resource,
|
||||||
} from "lucide-react";
|
ResourceTemplate,
|
||||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
Result,
|
||||||
import { Input } from "@/components/ui/input";
|
Root,
|
||||||
import { Button } from "@/components/ui/button";
|
ServerNotification,
|
||||||
import {
|
Tool,
|
||||||
Select,
|
} from "@modelcontextprotocol/sdk/types.js";
|
||||||
SelectContent,
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "@/components/ui/select";
|
|
||||||
|
|
||||||
import ConsoleTab from "./components/ConsoleTab";
|
import {
|
||||||
import Sidebar from "./components/Sidebar";
|
Notification,
|
||||||
import RequestsTab from "./components/RequestsTabs";
|
StdErrNotification,
|
||||||
import ResourcesTab from "./components/ResourcesTab";
|
StdErrNotificationSchema
|
||||||
import PromptsTab, { Prompt } from "./components/PromptsTab";
|
} from "./lib/notificationTypes";
|
||||||
import ToolsTab from "./components/ToolsTab";
|
|
||||||
import { AnyZodObject } from "zod";
|
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import HistoryAndNotifications from "./components/History";
|
import {
|
||||||
|
Bell,
|
||||||
|
Files,
|
||||||
|
FolderTree,
|
||||||
|
Hammer,
|
||||||
|
Hash,
|
||||||
|
MessageSquare,
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
import { ZodType } from "zod";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
|
import ConsoleTab from "./components/ConsoleTab";
|
||||||
|
import HistoryAndNotifications from "./components/History";
|
||||||
import PingTab from "./components/PingTab";
|
import PingTab from "./components/PingTab";
|
||||||
|
import PromptsTab, { Prompt } from "./components/PromptsTab";
|
||||||
|
import ResourcesTab from "./components/ResourcesTab";
|
||||||
|
import RootsTab from "./components/RootsTab";
|
||||||
|
import SamplingTab, { PendingRequest } from "./components/SamplingTab";
|
||||||
|
import Sidebar from "./components/Sidebar";
|
||||||
|
import ToolsTab from "./components/ToolsTab";
|
||||||
|
import useDarkModeSync from "./lib/useDarkModeSync";
|
||||||
|
|
||||||
|
const DEFAULT_REQUEST_TIMEOUT_MSEC = 10000;
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const [connectionStatus, setConnectionStatus] = useState<
|
const [connectionStatus, setConnectionStatus] = useState<
|
||||||
"disconnected" | "connected" | "error"
|
"disconnected" | "connected" | "error"
|
||||||
>("disconnected");
|
>("disconnected");
|
||||||
const [resources, setResources] = useState<Resource[]>([]);
|
const [resources, setResources] = useState<Resource[]>([]);
|
||||||
|
const [resourceTemplates, setResourceTemplates] = useState<
|
||||||
|
ResourceTemplate[]
|
||||||
|
>([]);
|
||||||
const [resourceContent, setResourceContent] = useState<string>("");
|
const [resourceContent, setResourceContent] = useState<string>("");
|
||||||
const [prompts, setPrompts] = useState<Prompt[]>([]);
|
const [prompts, setPrompts] = useState<Prompt[]>([]);
|
||||||
const [promptContent, setPromptContent] = useState<string>("");
|
const [promptContent, setPromptContent] = useState<string>("");
|
||||||
const [tools, setTools] = useState<Tool[]>([]);
|
const [tools, setTools] = useState<Tool[]>([]);
|
||||||
const [toolResult, setToolResult] = useState<string>("");
|
const [toolResult, setToolResult] =
|
||||||
const [error, setError] = useState<string | null>(null);
|
useState<CompatibilityCallToolResult | null>(null);
|
||||||
const [command, setCommand] = useState<string>(
|
const [errors, setErrors] = useState<Record<string, string | null>>({
|
||||||
"/Users/ashwin/.nvm/versions/node/v18.20.4/bin/node",
|
resources: null,
|
||||||
);
|
prompts: null,
|
||||||
const [args, setArgs] = useState<string>(
|
tools: null,
|
||||||
"/Users/ashwin/code/mcp/example-servers/build/everything/stdio.js",
|
});
|
||||||
);
|
const [command, setCommand] = useState<string>(() => {
|
||||||
|
return localStorage.getItem("lastCommand") || "mcp-server-everything";
|
||||||
|
});
|
||||||
|
const [args, setArgs] = useState<string>(() => {
|
||||||
|
return localStorage.getItem("lastArgs") || "";
|
||||||
|
});
|
||||||
const [url, setUrl] = useState<string>("http://localhost:3001/sse");
|
const [url, setUrl] = useState<string>("http://localhost:3001/sse");
|
||||||
const [transportType, setTransportType] = useState<"stdio" | "sse">("stdio");
|
const [transportType, setTransportType] = useState<"stdio" | "sse">("stdio");
|
||||||
const [requestHistory, setRequestHistory] = useState<
|
const [requestHistory, setRequestHistory] = useState<
|
||||||
{ request: string; response: string }[]
|
{ request: string; response?: string }[]
|
||||||
>([]);
|
>([]);
|
||||||
const [mcpClient, setMcpClient] = useState<Client | null>(null);
|
const [mcpClient, setMcpClient] = useState<Client | null>(null);
|
||||||
const [notifications, setNotifications] = useState<ServerNotification[]>([]);
|
const [notifications, setNotifications] = useState<ServerNotification[]>([]);
|
||||||
|
const [stdErrNotifications, setStdErrNotifications] = useState<
|
||||||
|
StdErrNotification[]
|
||||||
|
>([]);
|
||||||
|
const [roots, setRoots] = useState<Root[]>([]);
|
||||||
|
const [env, setEnv] = useState<Record<string, string>>({});
|
||||||
|
|
||||||
|
const [pendingSampleRequests, setPendingSampleRequests] = useState<
|
||||||
|
Array<
|
||||||
|
PendingRequest & {
|
||||||
|
resolve: (result: CreateMessageResult) => void;
|
||||||
|
reject: (error: Error) => void;
|
||||||
|
}
|
||||||
|
>
|
||||||
|
>([]);
|
||||||
|
const nextRequestId = useRef(0);
|
||||||
|
const rootsRef = useRef<Root[]>([]);
|
||||||
|
|
||||||
|
const handleApproveSampling = (id: number, result: CreateMessageResult) => {
|
||||||
|
setPendingSampleRequests((prev) => {
|
||||||
|
const request = prev.find((r) => r.id === id);
|
||||||
|
request?.resolve(result);
|
||||||
|
return prev.filter((r) => r.id !== id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRejectSampling = (id: number) => {
|
||||||
|
setPendingSampleRequests((prev) => {
|
||||||
|
const request = prev.find((r) => r.id === id);
|
||||||
|
request?.reject(new Error("Sampling request rejected"));
|
||||||
|
return prev.filter((r) => r.id !== id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const [selectedResource, setSelectedResource] = useState<Resource | null>(
|
const [selectedResource, setSelectedResource] = useState<Resource | null>(
|
||||||
null,
|
null,
|
||||||
@@ -79,33 +131,158 @@ const App = () => {
|
|||||||
const [nextResourceCursor, setNextResourceCursor] = useState<
|
const [nextResourceCursor, setNextResourceCursor] = useState<
|
||||||
string | undefined
|
string | undefined
|
||||||
>();
|
>();
|
||||||
|
const [nextResourceTemplateCursor, setNextResourceTemplateCursor] = useState<
|
||||||
|
string | undefined
|
||||||
|
>();
|
||||||
const [nextPromptCursor, setNextPromptCursor] = useState<
|
const [nextPromptCursor, setNextPromptCursor] = useState<
|
||||||
string | undefined
|
string | undefined
|
||||||
>();
|
>();
|
||||||
const [nextToolCursor, setNextToolCursor] = useState<string | undefined>();
|
const [nextToolCursor, setNextToolCursor] = useState<string | undefined>();
|
||||||
const progressTokenRef = useRef(0);
|
const progressTokenRef = useRef(0);
|
||||||
|
const [historyPaneHeight, setHistoryPaneHeight] = useState<number>(300);
|
||||||
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
|
const dragStartY = useRef<number>(0);
|
||||||
|
const dragStartHeight = useRef<number>(0);
|
||||||
|
|
||||||
const pushHistory = (request: object, response: object) => {
|
useDarkModeSync();
|
||||||
|
|
||||||
|
const handleDragStart = useCallback(
|
||||||
|
(e: React.MouseEvent) => {
|
||||||
|
setIsDragging(true);
|
||||||
|
dragStartY.current = e.clientY;
|
||||||
|
dragStartHeight.current = historyPaneHeight;
|
||||||
|
document.body.style.userSelect = "none";
|
||||||
|
},
|
||||||
|
[historyPaneHeight],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleDragMove = useCallback(
|
||||||
|
(e: MouseEvent) => {
|
||||||
|
if (!isDragging) return;
|
||||||
|
const deltaY = dragStartY.current - e.clientY;
|
||||||
|
const newHeight = Math.max(
|
||||||
|
100,
|
||||||
|
Math.min(800, dragStartHeight.current + deltaY),
|
||||||
|
);
|
||||||
|
setHistoryPaneHeight(newHeight);
|
||||||
|
},
|
||||||
|
[isDragging],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleDragEnd = useCallback(() => {
|
||||||
|
setIsDragging(false);
|
||||||
|
document.body.style.userSelect = "";
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isDragging) {
|
||||||
|
window.addEventListener("mousemove", handleDragMove);
|
||||||
|
window.addEventListener("mouseup", handleDragEnd);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("mousemove", handleDragMove);
|
||||||
|
window.removeEventListener("mouseup", handleDragEnd);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [isDragging, handleDragMove, handleDragEnd]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem("lastCommand", command);
|
||||||
|
}, [command]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem("lastArgs", args);
|
||||||
|
}, [args]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch("http://localhost:3000/config")
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
setEnv(data.defaultEnvironment);
|
||||||
|
if (data.defaultCommand) {
|
||||||
|
setCommand(data.defaultCommand);
|
||||||
|
}
|
||||||
|
if (data.defaultArgs) {
|
||||||
|
setArgs(data.defaultArgs);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) =>
|
||||||
|
console.error("Error fetching default environment:", error),
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
rootsRef.current = roots;
|
||||||
|
}, [roots]);
|
||||||
|
|
||||||
|
const pushHistory = (request: object, response?: object) => {
|
||||||
setRequestHistory((prev) => [
|
setRequestHistory((prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
{ request: JSON.stringify(request), response: JSON.stringify(response) },
|
{
|
||||||
|
request: JSON.stringify(request),
|
||||||
|
response: response !== undefined ? JSON.stringify(response) : undefined,
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeRequest = async <T extends AnyZodObject>(
|
const clearError = (tabKey: keyof typeof errors) => {
|
||||||
|
setErrors((prev) => ({ ...prev, [tabKey]: null }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const makeRequest = async <T extends ZodType<object>>(
|
||||||
request: ClientRequest,
|
request: ClientRequest,
|
||||||
schema: T,
|
schema: T,
|
||||||
|
tabKey?: keyof typeof errors,
|
||||||
) => {
|
) => {
|
||||||
if (!mcpClient) {
|
if (!mcpClient) {
|
||||||
throw new Error("MCP client not connected");
|
throw new Error("MCP client not connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await mcpClient.request(request, schema);
|
const abortController = new AbortController();
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
abortController.abort("Request timed out");
|
||||||
|
}, DEFAULT_REQUEST_TIMEOUT_MSEC);
|
||||||
|
|
||||||
|
let response;
|
||||||
|
try {
|
||||||
|
response = await mcpClient.request(request, schema, {
|
||||||
|
signal: abortController.signal,
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
pushHistory(request, response);
|
pushHistory(request, response);
|
||||||
|
|
||||||
|
if (tabKey !== undefined) {
|
||||||
|
clearError(tabKey);
|
||||||
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
setError((e as Error).message);
|
const errorString = (e as Error).message ?? String(e);
|
||||||
|
if (tabKey === undefined) {
|
||||||
|
toast.error(errorString);
|
||||||
|
} else {
|
||||||
|
setErrors((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[tabKey]: errorString,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendNotification = async (notification: ClientNotification) => {
|
||||||
|
if (!mcpClient) {
|
||||||
|
throw new Error("MCP client not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await mcpClient.notification(notification);
|
||||||
|
pushHistory(notification);
|
||||||
|
} catch (e: unknown) {
|
||||||
|
toast.error((e as Error).message ?? String(e));
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -117,11 +294,29 @@ const App = () => {
|
|||||||
params: nextResourceCursor ? { cursor: nextResourceCursor } : {},
|
params: nextResourceCursor ? { cursor: nextResourceCursor } : {},
|
||||||
},
|
},
|
||||||
ListResourcesResultSchema,
|
ListResourcesResultSchema,
|
||||||
|
"resources",
|
||||||
);
|
);
|
||||||
setResources(resources.concat(response.resources ?? []));
|
setResources(resources.concat(response.resources ?? []));
|
||||||
setNextResourceCursor(response.nextCursor);
|
setNextResourceCursor(response.nextCursor);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const listResourceTemplates = async () => {
|
||||||
|
const response = await makeRequest(
|
||||||
|
{
|
||||||
|
method: "resources/templates/list" as const,
|
||||||
|
params: nextResourceTemplateCursor
|
||||||
|
? { cursor: nextResourceTemplateCursor }
|
||||||
|
: {},
|
||||||
|
},
|
||||||
|
ListResourceTemplatesResultSchema,
|
||||||
|
"resources",
|
||||||
|
);
|
||||||
|
setResourceTemplates(
|
||||||
|
resourceTemplates.concat(response.resourceTemplates ?? []),
|
||||||
|
);
|
||||||
|
setNextResourceTemplateCursor(response.nextCursor);
|
||||||
|
};
|
||||||
|
|
||||||
const readResource = async (uri: string) => {
|
const readResource = async (uri: string) => {
|
||||||
const response = await makeRequest(
|
const response = await makeRequest(
|
||||||
{
|
{
|
||||||
@@ -129,6 +324,7 @@ const App = () => {
|
|||||||
params: { uri },
|
params: { uri },
|
||||||
},
|
},
|
||||||
ReadResourceResultSchema,
|
ReadResourceResultSchema,
|
||||||
|
"resources",
|
||||||
);
|
);
|
||||||
setResourceContent(JSON.stringify(response, null, 2));
|
setResourceContent(JSON.stringify(response, null, 2));
|
||||||
};
|
};
|
||||||
@@ -140,6 +336,7 @@ const App = () => {
|
|||||||
params: nextPromptCursor ? { cursor: nextPromptCursor } : {},
|
params: nextPromptCursor ? { cursor: nextPromptCursor } : {},
|
||||||
},
|
},
|
||||||
ListPromptsResultSchema,
|
ListPromptsResultSchema,
|
||||||
|
"prompts",
|
||||||
);
|
);
|
||||||
setPrompts(response.prompts);
|
setPrompts(response.prompts);
|
||||||
setNextPromptCursor(response.nextCursor);
|
setNextPromptCursor(response.nextCursor);
|
||||||
@@ -152,6 +349,7 @@ const App = () => {
|
|||||||
params: { name, arguments: args },
|
params: { name, arguments: args },
|
||||||
},
|
},
|
||||||
GetPromptResultSchema,
|
GetPromptResultSchema,
|
||||||
|
"prompts",
|
||||||
);
|
);
|
||||||
setPromptContent(JSON.stringify(response, null, 2));
|
setPromptContent(JSON.stringify(response, null, 2));
|
||||||
};
|
};
|
||||||
@@ -163,6 +361,7 @@ const App = () => {
|
|||||||
params: nextToolCursor ? { cursor: nextToolCursor } : {},
|
params: nextToolCursor ? { cursor: nextToolCursor } : {},
|
||||||
},
|
},
|
||||||
ListToolsResultSchema,
|
ListToolsResultSchema,
|
||||||
|
"tools",
|
||||||
);
|
);
|
||||||
setTools(response.tools);
|
setTools(response.tools);
|
||||||
setNextToolCursor(response.nextCursor);
|
setNextToolCursor(response.nextCursor);
|
||||||
@@ -180,17 +379,33 @@ const App = () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CallToolResultSchema,
|
CompatibilityCallToolResultSchema,
|
||||||
|
"tools",
|
||||||
);
|
);
|
||||||
setToolResult(JSON.stringify(response.toolResult, null, 2));
|
setToolResult(response);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRootsChange = async () => {
|
||||||
|
await sendNotification({ method: "notifications/roots/list_changed" });
|
||||||
};
|
};
|
||||||
|
|
||||||
const connectMcpServer = async () => {
|
const connectMcpServer = async () => {
|
||||||
try {
|
try {
|
||||||
const client = new Client({
|
const client = new Client<Request, Notification, Result>(
|
||||||
|
{
|
||||||
name: "mcp-inspector",
|
name: "mcp-inspector",
|
||||||
version: "0.0.1",
|
version: "0.0.1",
|
||||||
});
|
},
|
||||||
|
{
|
||||||
|
capabilities: {
|
||||||
|
// Support all client capabilities since we're an inspector tool
|
||||||
|
sampling: {},
|
||||||
|
roots: {
|
||||||
|
listChanged: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const backendUrl = new URL("http://localhost:3000/sse");
|
const backendUrl = new URL("http://localhost:3000/sse");
|
||||||
|
|
||||||
@@ -198,13 +413,12 @@ const App = () => {
|
|||||||
if (transportType === "stdio") {
|
if (transportType === "stdio") {
|
||||||
backendUrl.searchParams.append("command", command);
|
backendUrl.searchParams.append("command", command);
|
||||||
backendUrl.searchParams.append("args", args);
|
backendUrl.searchParams.append("args", args);
|
||||||
|
backendUrl.searchParams.append("env", JSON.stringify(env));
|
||||||
} else {
|
} else {
|
||||||
backendUrl.searchParams.append("url", url);
|
backendUrl.searchParams.append("url", url);
|
||||||
}
|
}
|
||||||
|
|
||||||
const clientTransport = new SSEClientTransport(backendUrl);
|
const clientTransport = new SSEClientTransport(backendUrl);
|
||||||
await client.connect(clientTransport);
|
|
||||||
|
|
||||||
client.setNotificationHandler(
|
client.setNotificationHandler(
|
||||||
ProgressNotificationSchema,
|
ProgressNotificationSchema,
|
||||||
(notification) => {
|
(notification) => {
|
||||||
@@ -215,6 +429,31 @@ const App = () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
client.setNotificationHandler(
|
||||||
|
StdErrNotificationSchema,
|
||||||
|
(notification) => {
|
||||||
|
setStdErrNotifications((prevErrorNotifications) => [
|
||||||
|
...prevErrorNotifications,
|
||||||
|
notification,
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
await client.connect(clientTransport);
|
||||||
|
|
||||||
|
client.setRequestHandler(CreateMessageRequestSchema, (request) => {
|
||||||
|
return new Promise<CreateMessageResult>((resolve, reject) => {
|
||||||
|
setPendingSampleRequests((prev) => [
|
||||||
|
...prev,
|
||||||
|
{ id: nextRequestId.current++, request, resolve, reject },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
client.setRequestHandler(ListRootsRequestSchema, async () => {
|
||||||
|
return { roots: rootsRef.current };
|
||||||
|
});
|
||||||
|
|
||||||
setMcpClient(client);
|
setMcpClient(client);
|
||||||
setConnectionStatus("connected");
|
setConnectionStatus("connected");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -224,55 +463,24 @@ const App = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen bg-gray-100">
|
<div className="flex h-screen bg-background">
|
||||||
<Sidebar connectionStatus={connectionStatus} />
|
<Sidebar
|
||||||
|
connectionStatus={connectionStatus}
|
||||||
|
transportType={transportType}
|
||||||
|
setTransportType={setTransportType}
|
||||||
|
command={command}
|
||||||
|
setCommand={setCommand}
|
||||||
|
args={args}
|
||||||
|
setArgs={setArgs}
|
||||||
|
url={url}
|
||||||
|
setUrl={setUrl}
|
||||||
|
env={env}
|
||||||
|
setEnv={setEnv}
|
||||||
|
onConnect={connectMcpServer}
|
||||||
|
stdErrNotifications={stdErrNotifications}
|
||||||
|
/>
|
||||||
<div className="flex-1 flex flex-col overflow-hidden">
|
<div className="flex-1 flex flex-col overflow-hidden">
|
||||||
<h1 className="text-2xl font-bold p-4">MCP Inspector</h1>
|
<div className="flex-1 overflow-auto">
|
||||||
<div className="flex-1 overflow-auto flex">
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="p-4 bg-white shadow-md m-4 rounded-md">
|
|
||||||
<h2 className="text-lg font-semibold mb-2">Connect MCP Server</h2>
|
|
||||||
<div className="flex space-x-2 mb-2">
|
|
||||||
<Select
|
|
||||||
value={transportType}
|
|
||||||
onValueChange={(value: "stdio" | "sse") =>
|
|
||||||
setTransportType(value)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-[180px]">
|
|
||||||
<SelectValue placeholder="Select transport type" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="stdio">STDIO</SelectItem>
|
|
||||||
<SelectItem value="sse">SSE</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
{transportType === "stdio" ? (
|
|
||||||
<>
|
|
||||||
<Input
|
|
||||||
placeholder="Command"
|
|
||||||
value={command}
|
|
||||||
onChange={(e) => setCommand(e.target.value)}
|
|
||||||
/>
|
|
||||||
<Input
|
|
||||||
placeholder="Arguments (space-separated)"
|
|
||||||
value={args}
|
|
||||||
onChange={(e) => setArgs(e.target.value)}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<Input
|
|
||||||
placeholder="URL"
|
|
||||||
value={url}
|
|
||||||
onChange={(e) => setUrl(e.target.value)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Button onClick={connectMcpServer}>
|
|
||||||
<Play className="w-4 h-4 mr-2" />
|
|
||||||
Connect
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{mcpClient ? (
|
{mcpClient ? (
|
||||||
<Tabs defaultValue="resources" className="w-full p-4">
|
<Tabs defaultValue="resources" className="w-full p-4">
|
||||||
<TabsList className="mb-4 p-0">
|
<TabsList className="mb-4 p-0">
|
||||||
@@ -284,58 +492,93 @@ const App = () => {
|
|||||||
<MessageSquare className="w-4 h-4 mr-2" />
|
<MessageSquare className="w-4 h-4 mr-2" />
|
||||||
Prompts
|
Prompts
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger value="requests" disabled>
|
|
||||||
<Send className="w-4 h-4 mr-2" />
|
|
||||||
Requests
|
|
||||||
</TabsTrigger>
|
|
||||||
<TabsTrigger value="tools">
|
<TabsTrigger value="tools">
|
||||||
<Hammer className="w-4 h-4 mr-2" />
|
<Hammer className="w-4 h-4 mr-2" />
|
||||||
Tools
|
Tools
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger value="console" disabled>
|
|
||||||
<Terminal className="w-4 h-4 mr-2" />
|
|
||||||
Console
|
|
||||||
</TabsTrigger>
|
|
||||||
<TabsTrigger value="ping">
|
<TabsTrigger value="ping">
|
||||||
<Bell className="w-4 h-4 mr-2" />
|
<Bell className="w-4 h-4 mr-2" />
|
||||||
Ping
|
Ping
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="sampling" className="relative">
|
||||||
|
<Hash className="w-4 h-4 mr-2" />
|
||||||
|
Sampling
|
||||||
|
{pendingSampleRequests.length > 0 && (
|
||||||
|
<span className="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full h-4 w-4 flex items-center justify-center">
|
||||||
|
{pendingSampleRequests.length}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="roots">
|
||||||
|
<FolderTree className="w-4 h-4 mr-2" />
|
||||||
|
Roots
|
||||||
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<ResourcesTab
|
<ResourcesTab
|
||||||
resources={resources}
|
resources={resources}
|
||||||
listResources={listResources}
|
resourceTemplates={resourceTemplates}
|
||||||
readResource={readResource}
|
listResources={() => {
|
||||||
|
clearError("resources");
|
||||||
|
listResources();
|
||||||
|
}}
|
||||||
|
listResourceTemplates={() => {
|
||||||
|
clearError("resources");
|
||||||
|
listResourceTemplates();
|
||||||
|
}}
|
||||||
|
readResource={(uri) => {
|
||||||
|
clearError("resources");
|
||||||
|
readResource(uri);
|
||||||
|
}}
|
||||||
selectedResource={selectedResource}
|
selectedResource={selectedResource}
|
||||||
setSelectedResource={setSelectedResource}
|
setSelectedResource={(resource) => {
|
||||||
|
clearError("resources");
|
||||||
|
setSelectedResource(resource);
|
||||||
|
}}
|
||||||
resourceContent={resourceContent}
|
resourceContent={resourceContent}
|
||||||
nextCursor={nextResourceCursor}
|
nextCursor={nextResourceCursor}
|
||||||
error={error}
|
nextTemplateCursor={nextResourceTemplateCursor}
|
||||||
|
error={errors.resources}
|
||||||
/>
|
/>
|
||||||
<PromptsTab
|
<PromptsTab
|
||||||
prompts={prompts}
|
prompts={prompts}
|
||||||
listPrompts={listPrompts}
|
listPrompts={() => {
|
||||||
getPrompt={getPrompt}
|
clearError("prompts");
|
||||||
|
listPrompts();
|
||||||
|
}}
|
||||||
|
getPrompt={(name, args) => {
|
||||||
|
clearError("prompts");
|
||||||
|
getPrompt(name, args);
|
||||||
|
}}
|
||||||
selectedPrompt={selectedPrompt}
|
selectedPrompt={selectedPrompt}
|
||||||
setSelectedPrompt={setSelectedPrompt}
|
setSelectedPrompt={(prompt) => {
|
||||||
|
clearError("prompts");
|
||||||
|
setSelectedPrompt(prompt);
|
||||||
|
}}
|
||||||
promptContent={promptContent}
|
promptContent={promptContent}
|
||||||
nextCursor={nextPromptCursor}
|
nextCursor={nextPromptCursor}
|
||||||
error={error}
|
error={errors.prompts}
|
||||||
/>
|
/>
|
||||||
<RequestsTab />
|
|
||||||
<ToolsTab
|
<ToolsTab
|
||||||
tools={tools}
|
tools={tools}
|
||||||
listTools={listTools}
|
listTools={() => {
|
||||||
callTool={callTool}
|
clearError("tools");
|
||||||
|
listTools();
|
||||||
|
}}
|
||||||
|
callTool={(name, params) => {
|
||||||
|
clearError("tools");
|
||||||
|
callTool(name, params);
|
||||||
|
}}
|
||||||
selectedTool={selectedTool}
|
selectedTool={selectedTool}
|
||||||
setSelectedTool={(tool) => {
|
setSelectedTool={(tool) => {
|
||||||
|
clearError("tools");
|
||||||
setSelectedTool(tool);
|
setSelectedTool(tool);
|
||||||
setToolResult("");
|
setToolResult(null);
|
||||||
}}
|
}}
|
||||||
toolResult={toolResult}
|
toolResult={toolResult}
|
||||||
nextCursor={nextToolCursor}
|
nextCursor={nextToolCursor}
|
||||||
error={error}
|
error={errors.tools}
|
||||||
/>
|
/>
|
||||||
<ConsoleTab />
|
<ConsoleTab />
|
||||||
<PingTab
|
<PingTab
|
||||||
@@ -348,6 +591,16 @@ const App = () => {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<SamplingTab
|
||||||
|
pendingRequests={pendingSampleRequests}
|
||||||
|
onApprove={handleApproveSampling}
|
||||||
|
onReject={handleRejectSampling}
|
||||||
|
/>
|
||||||
|
<RootsTab
|
||||||
|
roots={roots}
|
||||||
|
setRoots={setRoots}
|
||||||
|
onRootsChange={handleRootsChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
) : (
|
) : (
|
||||||
@@ -358,13 +611,27 @@ const App = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
className="relative border-t border-border"
|
||||||
|
style={{
|
||||||
|
height: `${historyPaneHeight}px`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="absolute w-full h-4 -top-2 cursor-row-resize flex items-center justify-center hover:bg-accent/50"
|
||||||
|
onMouseDown={handleDragStart}
|
||||||
|
>
|
||||||
|
<div className="w-8 h-1 rounded-full bg-border" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="h-full overflow-auto">
|
||||||
<HistoryAndNotifications
|
<HistoryAndNotifications
|
||||||
requestHistory={requestHistory}
|
requestHistory={requestHistory}
|
||||||
serverNotifications={notifications}
|
serverNotifications={notifications}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
|
||||||
|
Before Width: | Height: | Size: 4.0 KiB |
@@ -1,12 +1,12 @@
|
|||||||
import { useState } from "react";
|
import { ServerNotification } from "@modelcontextprotocol/sdk/types.js";
|
||||||
import { Copy } from "lucide-react";
|
import { Copy } from "lucide-react";
|
||||||
import { ServerNotification } from "mcp-typescript/types.js";
|
import { useState } from "react";
|
||||||
|
|
||||||
const HistoryAndNotifications = ({
|
const HistoryAndNotifications = ({
|
||||||
requestHistory,
|
requestHistory,
|
||||||
serverNotifications,
|
serverNotifications,
|
||||||
}: {
|
}: {
|
||||||
requestHistory: Array<{ request: string; response: string | null }>;
|
requestHistory: Array<{ request: string; response?: string }>;
|
||||||
serverNotifications: ServerNotification[];
|
serverNotifications: ServerNotification[];
|
||||||
}) => {
|
}) => {
|
||||||
const [expandedRequests, setExpandedRequests] = useState<{
|
const [expandedRequests, setExpandedRequests] = useState<{
|
||||||
@@ -29,8 +29,8 @@ const HistoryAndNotifications = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-64 bg-white shadow-md p-4 overflow-hidden flex flex-col h-full">
|
<div className="bg-card overflow-hidden flex h-full">
|
||||||
<div className="flex-1 overflow-y-auto mb-4 border-b pb-4">
|
<div className="flex-1 overflow-y-auto p-4 border-r">
|
||||||
<h2 className="text-lg font-semibold mb-4">History</h2>
|
<h2 className="text-lg font-semibold mb-4">History</h2>
|
||||||
{requestHistory.length === 0 ? (
|
{requestHistory.length === 0 ? (
|
||||||
<p className="text-sm text-gray-500 italic">No history yet</p>
|
<p className="text-sm text-gray-500 italic">No history yet</p>
|
||||||
@@ -42,7 +42,7 @@ const HistoryAndNotifications = ({
|
|||||||
.map((request, index) => (
|
.map((request, index) => (
|
||||||
<li
|
<li
|
||||||
key={index}
|
key={index}
|
||||||
className="text-sm text-gray-600 bg-gray-100 p-2 rounded"
|
className="text-sm text-foreground bg-secondary p-2 rounded"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="flex justify-between items-center cursor-pointer"
|
className="flex justify-between items-center cursor-pointer"
|
||||||
@@ -74,7 +74,7 @@ const HistoryAndNotifications = ({
|
|||||||
<Copy size={16} />
|
<Copy size={16} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<pre className="whitespace-pre-wrap break-words bg-blue-50 p-2 rounded">
|
<pre className="whitespace-pre-wrap break-words bg-background p-2 rounded">
|
||||||
{JSON.stringify(JSON.parse(request.request), null, 2)}
|
{JSON.stringify(JSON.parse(request.request), null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
@@ -91,7 +91,7 @@ const HistoryAndNotifications = ({
|
|||||||
<Copy size={16} />
|
<Copy size={16} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<pre className="whitespace-pre-wrap break-words bg-green-50 p-2 rounded">
|
<pre className="whitespace-pre-wrap break-words bg-background p-2 rounded">
|
||||||
{JSON.stringify(
|
{JSON.stringify(
|
||||||
JSON.parse(request.response),
|
JSON.parse(request.response),
|
||||||
null,
|
null,
|
||||||
@@ -107,7 +107,7 @@ const HistoryAndNotifications = ({
|
|||||||
</ul>
|
</ul>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 overflow-y-auto">
|
<div className="flex-1 overflow-y-auto p-4">
|
||||||
<h2 className="text-lg font-semibold mb-4">Server Notifications</h2>
|
<h2 className="text-lg font-semibold mb-4">Server Notifications</h2>
|
||||||
{serverNotifications.length === 0 ? (
|
{serverNotifications.length === 0 ? (
|
||||||
<p className="text-sm text-gray-500 italic">No notifications yet</p>
|
<p className="text-sm text-gray-500 italic">No notifications yet</p>
|
||||||
@@ -119,7 +119,7 @@ const HistoryAndNotifications = ({
|
|||||||
.map((notification, index) => (
|
.map((notification, index) => (
|
||||||
<li
|
<li
|
||||||
key={index}
|
key={index}
|
||||||
className="text-sm text-gray-600 bg-gray-100 p-2 rounded"
|
className="text-sm text-foreground bg-secondary p-2 rounded"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="flex justify-between items-center cursor-pointer"
|
className="flex justify-between items-center cursor-pointer"
|
||||||
@@ -146,7 +146,7 @@ const HistoryAndNotifications = ({
|
|||||||
<Copy size={16} />
|
<Copy size={16} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<pre className="whitespace-pre-wrap break-words bg-purple-50 p-2 rounded">
|
<pre className="whitespace-pre-wrap break-words bg-background p-2 rounded">
|
||||||
{JSON.stringify(notification, null, 2)}
|
{JSON.stringify(notification, null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ const ListPane = <T extends object>({
|
|||||||
buttonText,
|
buttonText,
|
||||||
isButtonDisabled,
|
isButtonDisabled,
|
||||||
}: ListPaneProps<T>) => (
|
}: ListPaneProps<T>) => (
|
||||||
<div className="bg-white rounded-lg shadow">
|
<div className="bg-card rounded-lg shadow">
|
||||||
<div className="p-4 border-b border-gray-200">
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
<h3 className="font-semibold">{title}</h3>
|
<h3 className="font-semibold dark:text-white">{title}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<Button
|
<Button
|
||||||
@@ -36,7 +36,7 @@ const ListPane = <T extends object>({
|
|||||||
{items.map((item, index) => (
|
{items.map((item, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="flex items-center p-2 rounded hover:bg-gray-50 cursor-pointer"
|
className="flex items-center p-2 rounded hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer"
|
||||||
onClick={() => setSelectedItem(item)}
|
onClick={() => setSelectedItem(item)}
|
||||||
>
|
>
|
||||||
{renderItem(item)}
|
{renderItem(item)}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { AlertCircle } from "lucide-react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
import { TabsContent } from "@/components/ui/tabs";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { TabsContent } from "@/components/ui/tabs";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import { ListPromptsResult } from "@modelcontextprotocol/sdk/types.js";
|
||||||
|
import { AlertCircle } from "lucide-react";
|
||||||
|
import { useState } from "react";
|
||||||
import ListPane from "./ListPane";
|
import ListPane from "./ListPane";
|
||||||
import { ListPromptsResult } from "mcp-typescript/types.js";
|
|
||||||
|
|
||||||
export type Prompt = {
|
export type Prompt = {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -70,7 +70,7 @@ const PromptsTab = ({
|
|||||||
isButtonDisabled={!nextCursor && prompts.length > 0}
|
isButtonDisabled={!nextCursor && prompts.length > 0}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="bg-white rounded-lg shadow">
|
<div className="bg-card rounded-lg shadow">
|
||||||
<div className="p-4 border-b border-gray-200">
|
<div className="p-4 border-b border-gray-200">
|
||||||
<h3 className="font-semibold">
|
<h3 className="font-semibold">
|
||||||
{selectedPrompt ? selectedPrompt.name : "Select a prompt"}
|
{selectedPrompt ? selectedPrompt.name : "Select a prompt"}
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
import { TabsContent } from "@/components/ui/tabs";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
|
||||||
import { Send } from "lucide-react";
|
|
||||||
|
|
||||||
const RequestsTab = () => (
|
|
||||||
<TabsContent value="requests" className="space-y-4">
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex space-x-2">
|
|
||||||
<Input placeholder="Method name" />
|
|
||||||
<Button>
|
|
||||||
<Send className="w-4 h-4 mr-2" />
|
|
||||||
Send
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<Textarea
|
|
||||||
placeholder="Request parameters (JSON)"
|
|
||||||
className="h-64 font-mono"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="bg-gray-50 p-4 rounded-lg h-96 font-mono text-sm overflow-auto">
|
|
||||||
<div className="text-gray-500 mb-2">Response:</div>
|
|
||||||
{/* Response content would go here */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</TabsContent>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default RequestsTab;
|
|
||||||
@@ -1,36 +1,77 @@
|
|||||||
import { FileText, ChevronRight, AlertCircle, RefreshCw } from "lucide-react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
import { TabsContent } from "@/components/ui/tabs";
|
import { TabsContent } from "@/components/ui/tabs";
|
||||||
import { ListResourcesResult, Resource } from "mcp-typescript/types.js";
|
import {
|
||||||
|
ListResourcesResult,
|
||||||
|
Resource,
|
||||||
|
ResourceTemplate,
|
||||||
|
ListResourceTemplatesResult,
|
||||||
|
} from "@modelcontextprotocol/sdk/types.js";
|
||||||
|
import { AlertCircle, ChevronRight, FileText, RefreshCw } from "lucide-react";
|
||||||
import ListPane from "./ListPane";
|
import ListPane from "./ListPane";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
const ResourcesTab = ({
|
const ResourcesTab = ({
|
||||||
resources,
|
resources,
|
||||||
|
resourceTemplates,
|
||||||
listResources,
|
listResources,
|
||||||
|
listResourceTemplates,
|
||||||
readResource,
|
readResource,
|
||||||
selectedResource,
|
selectedResource,
|
||||||
setSelectedResource,
|
setSelectedResource,
|
||||||
resourceContent,
|
resourceContent,
|
||||||
nextCursor,
|
nextCursor,
|
||||||
|
nextTemplateCursor,
|
||||||
error,
|
error,
|
||||||
}: {
|
}: {
|
||||||
resources: Resource[];
|
resources: Resource[];
|
||||||
|
resourceTemplates: ResourceTemplate[];
|
||||||
listResources: () => void;
|
listResources: () => void;
|
||||||
|
listResourceTemplates: () => void;
|
||||||
readResource: (uri: string) => void;
|
readResource: (uri: string) => void;
|
||||||
selectedResource: Resource | null;
|
selectedResource: Resource | null;
|
||||||
setSelectedResource: (resource: Resource) => void;
|
setSelectedResource: (resource: Resource | null) => void;
|
||||||
resourceContent: string;
|
resourceContent: string;
|
||||||
nextCursor: ListResourcesResult["nextCursor"];
|
nextCursor: ListResourcesResult["nextCursor"];
|
||||||
|
nextTemplateCursor: ListResourceTemplatesResult["nextCursor"];
|
||||||
error: string | null;
|
error: string | null;
|
||||||
}) => (
|
}) => {
|
||||||
<TabsContent value="resources" className="grid grid-cols-2 gap-4">
|
const [selectedTemplate, setSelectedTemplate] =
|
||||||
|
useState<ResourceTemplate | null>(null);
|
||||||
|
const [templateValues, setTemplateValues] = useState<Record<string, string>>(
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
|
const fillTemplate = (
|
||||||
|
template: string,
|
||||||
|
values: Record<string, string>,
|
||||||
|
): string => {
|
||||||
|
return template.replace(
|
||||||
|
/{([^}]+)}/g,
|
||||||
|
(_, key) => values[key] || `{${key}}`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleReadTemplateResource = () => {
|
||||||
|
if (selectedTemplate) {
|
||||||
|
const uri = fillTemplate(selectedTemplate.uriTemplate, templateValues);
|
||||||
|
readResource(uri);
|
||||||
|
setSelectedTemplate(null);
|
||||||
|
// We don't have the full Resource object here, so we create a partial one
|
||||||
|
setSelectedResource({ uri, name: uri } as Resource);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TabsContent value="resources" className="grid grid-cols-3 gap-4">
|
||||||
<ListPane
|
<ListPane
|
||||||
items={resources}
|
items={resources}
|
||||||
listItems={listResources}
|
listItems={listResources}
|
||||||
setSelectedItem={(resource) => {
|
setSelectedItem={(resource) => {
|
||||||
setSelectedResource(resource);
|
setSelectedResource(resource);
|
||||||
readResource(resource.uri);
|
readResource(resource.uri);
|
||||||
|
setSelectedTemplate(null);
|
||||||
}}
|
}}
|
||||||
renderItem={(resource) => (
|
renderItem={(resource) => (
|
||||||
<div className="flex items-center w-full">
|
<div className="flex items-center w-full">
|
||||||
@@ -46,10 +87,41 @@ const ResourcesTab = ({
|
|||||||
isButtonDisabled={!nextCursor && resources.length > 0}
|
isButtonDisabled={!nextCursor && resources.length > 0}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="bg-white rounded-lg shadow">
|
<ListPane
|
||||||
|
items={resourceTemplates}
|
||||||
|
listItems={listResourceTemplates}
|
||||||
|
setSelectedItem={(template) => {
|
||||||
|
setSelectedTemplate(template);
|
||||||
|
setSelectedResource(null);
|
||||||
|
setTemplateValues({});
|
||||||
|
}}
|
||||||
|
renderItem={(template) => (
|
||||||
|
<div className="flex items-center w-full">
|
||||||
|
<FileText className="w-4 h-4 mr-2 flex-shrink-0 text-gray-500" />
|
||||||
|
<span className="flex-1 truncate" title={template.uriTemplate}>
|
||||||
|
{template.name}
|
||||||
|
</span>
|
||||||
|
<ChevronRight className="w-4 h-4 flex-shrink-0 text-gray-400" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
title="Resource Templates"
|
||||||
|
buttonText={
|
||||||
|
nextTemplateCursor ? "List More Templates" : "List Templates"
|
||||||
|
}
|
||||||
|
isButtonDisabled={!nextTemplateCursor && resourceTemplates.length > 0}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="bg-card rounded-lg shadow">
|
||||||
<div className="p-4 border-b border-gray-200 flex justify-between items-center">
|
<div className="p-4 border-b border-gray-200 flex justify-between items-center">
|
||||||
<h3 className="font-semibold truncate" title={selectedResource?.name}>
|
<h3
|
||||||
{selectedResource ? selectedResource.name : "Select a resource"}
|
className="font-semibold truncate"
|
||||||
|
title={selectedResource?.name || selectedTemplate?.name}
|
||||||
|
>
|
||||||
|
{selectedResource
|
||||||
|
? selectedResource.name
|
||||||
|
: selectedTemplate
|
||||||
|
? selectedTemplate.name
|
||||||
|
: "Select a resource or template"}
|
||||||
</h3>
|
</h3>
|
||||||
{selectedResource && (
|
{selectedResource && (
|
||||||
<Button
|
<Button
|
||||||
@@ -70,13 +142,51 @@ const ResourcesTab = ({
|
|||||||
<AlertDescription>{error}</AlertDescription>
|
<AlertDescription>{error}</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
) : selectedResource ? (
|
) : selectedResource ? (
|
||||||
<pre className="bg-gray-50 p-4 rounded text-sm overflow-auto max-h-96 whitespace-pre-wrap break-words">
|
<pre className="bg-gray-50 dark:bg-gray-800 p-4 rounded text-sm overflow-auto max-h-96 whitespace-pre-wrap break-words text-gray-900 dark:text-gray-100">
|
||||||
{resourceContent}
|
{resourceContent}
|
||||||
</pre>
|
</pre>
|
||||||
|
) : selectedTemplate ? (
|
||||||
|
<div className="space-y-4">
|
||||||
|
<p className="text-sm text-gray-600">
|
||||||
|
{selectedTemplate.description}
|
||||||
|
</p>
|
||||||
|
{selectedTemplate.uriTemplate
|
||||||
|
.match(/{([^}]+)}/g)
|
||||||
|
?.map((param) => {
|
||||||
|
const key = param.slice(1, -1);
|
||||||
|
return (
|
||||||
|
<div key={key}>
|
||||||
|
<label
|
||||||
|
htmlFor={key}
|
||||||
|
className="block text-sm font-medium text-gray-700"
|
||||||
|
>
|
||||||
|
{key}
|
||||||
|
</label>
|
||||||
|
<Input
|
||||||
|
id={key}
|
||||||
|
value={templateValues[key] || ""}
|
||||||
|
onChange={(e) =>
|
||||||
|
setTemplateValues({
|
||||||
|
...templateValues,
|
||||||
|
[key]: e.target.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
className="mt-1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<Button
|
||||||
|
onClick={handleReadTemplateResource}
|
||||||
|
disabled={Object.keys(templateValues).length === 0}
|
||||||
|
>
|
||||||
|
Read Resource
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Alert>
|
<Alert>
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
Select a resource from the list to view its contents
|
Select a resource or template from the list to view its contents
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
@@ -84,5 +194,6 @@ const ResourcesTab = ({
|
|||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default ResourcesTab;
|
export default ResourcesTab;
|
||||||
|
|||||||
77
client/src/components/RootsTab.tsx
Normal file
77
client/src/components/RootsTab.tsx
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { TabsContent } from "@/components/ui/tabs";
|
||||||
|
import { Root } from "@modelcontextprotocol/sdk/types.js";
|
||||||
|
import { Plus, Minus, Save } from "lucide-react";
|
||||||
|
|
||||||
|
const RootsTab = ({
|
||||||
|
roots,
|
||||||
|
setRoots,
|
||||||
|
onRootsChange,
|
||||||
|
}: {
|
||||||
|
roots: Root[];
|
||||||
|
setRoots: React.Dispatch<React.SetStateAction<Root[]>>;
|
||||||
|
onRootsChange: () => void;
|
||||||
|
}) => {
|
||||||
|
const addRoot = () => {
|
||||||
|
setRoots((currentRoots) => [...currentRoots, { uri: "file://", name: "" }]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeRoot = (index: number) => {
|
||||||
|
setRoots((currentRoots) => currentRoots.filter((_, i) => i !== index));
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateRoot = (index: number, field: keyof Root, value: string) => {
|
||||||
|
setRoots((currentRoots) =>
|
||||||
|
currentRoots.map((root, i) =>
|
||||||
|
i === index ? { ...root, [field]: value } : root,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
onRootsChange();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TabsContent value="roots" className="space-y-4">
|
||||||
|
<Alert>
|
||||||
|
<AlertDescription>
|
||||||
|
Configure the root directories that the server can access
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
|
||||||
|
{roots.map((root, index) => (
|
||||||
|
<div key={index} className="flex gap-2 items-center">
|
||||||
|
<Input
|
||||||
|
placeholder="file:// URI"
|
||||||
|
value={root.uri}
|
||||||
|
onChange={(e) => updateRoot(index, "uri", e.target.value)}
|
||||||
|
className="flex-1"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="destructive"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => removeRoot(index)}
|
||||||
|
>
|
||||||
|
<Minus className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button variant="outline" onClick={addRoot}>
|
||||||
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
|
Add Root
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleSave}>
|
||||||
|
<Save className="h-4 w-4 mr-2" />
|
||||||
|
Save Changes
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RootsTab;
|
||||||
65
client/src/components/SamplingTab.tsx
Normal file
65
client/src/components/SamplingTab.tsx
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { TabsContent } from "@/components/ui/tabs";
|
||||||
|
import {
|
||||||
|
CreateMessageRequest,
|
||||||
|
CreateMessageResult,
|
||||||
|
} from "@modelcontextprotocol/sdk/types.js";
|
||||||
|
|
||||||
|
export type PendingRequest = {
|
||||||
|
id: number;
|
||||||
|
request: CreateMessageRequest;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Props = {
|
||||||
|
pendingRequests: PendingRequest[];
|
||||||
|
onApprove: (id: number, result: CreateMessageResult) => void;
|
||||||
|
onReject: (id: number) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SamplingTab = ({ pendingRequests, onApprove, onReject }: Props) => {
|
||||||
|
const handleApprove = (id: number) => {
|
||||||
|
// For now, just return a stub response
|
||||||
|
onApprove(id, {
|
||||||
|
model: "stub-model",
|
||||||
|
stopReason: "endTurn",
|
||||||
|
role: "assistant",
|
||||||
|
content: {
|
||||||
|
type: "text",
|
||||||
|
text: "This is a stub response.",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TabsContent value="sampling" className="h-96">
|
||||||
|
<Alert>
|
||||||
|
<AlertDescription>
|
||||||
|
When the server requests LLM sampling, requests will appear here for
|
||||||
|
approval.
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
<div className="mt-4 space-y-4">
|
||||||
|
<h3 className="text-lg font-semibold">Recent Requests</h3>
|
||||||
|
{pendingRequests.map((request) => (
|
||||||
|
<div key={request.id} className="p-4 border rounded-lg space-y-4">
|
||||||
|
<pre className="bg-gray-50 p-2 rounded">
|
||||||
|
{JSON.stringify(request.request, null, 2)}
|
||||||
|
</pre>
|
||||||
|
<div className="flex space-x-2">
|
||||||
|
<Button onClick={() => handleApprove(request.id)}>Approve</Button>
|
||||||
|
<Button variant="outline" onClick={() => onReject(request.id)}>
|
||||||
|
Reject
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{pendingRequests.length === 0 && (
|
||||||
|
<p className="text-gray-500">No pending requests</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SamplingTab;
|
||||||
@@ -1,15 +1,178 @@
|
|||||||
import { Menu, Settings } from "lucide-react";
|
import { useState } from "react";
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
|
|
||||||
const Sidebar = ({ connectionStatus }: { connectionStatus: string }) => (
|
import { Play, ChevronDown, ChevronRight, Settings } from "lucide-react";
|
||||||
<div className="w-64 bg-white border-r border-gray-200">
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
import { StdErrNotification } from "@/lib/notificationTypes";
|
||||||
|
|
||||||
|
interface SidebarProps {
|
||||||
|
connectionStatus: "disconnected" | "connected" | "error";
|
||||||
|
transportType: "stdio" | "sse";
|
||||||
|
setTransportType: (type: "stdio" | "sse") => void;
|
||||||
|
command: string;
|
||||||
|
setCommand: (command: string) => void;
|
||||||
|
args: string;
|
||||||
|
setArgs: (args: string) => void;
|
||||||
|
url: string;
|
||||||
|
setUrl: (url: string) => void;
|
||||||
|
env: Record<string, string>;
|
||||||
|
setEnv: (env: Record<string, string>) => void;
|
||||||
|
onConnect: () => void;
|
||||||
|
stdErrNotifications: StdErrNotification[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const Sidebar = ({
|
||||||
|
connectionStatus,
|
||||||
|
transportType,
|
||||||
|
setTransportType,
|
||||||
|
command,
|
||||||
|
setCommand,
|
||||||
|
args,
|
||||||
|
setArgs,
|
||||||
|
url,
|
||||||
|
setUrl,
|
||||||
|
env,
|
||||||
|
setEnv,
|
||||||
|
onConnect,
|
||||||
|
stdErrNotifications,
|
||||||
|
}: SidebarProps) => {
|
||||||
|
const [showEnvVars, setShowEnvVars] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-80 bg-card border-r border-border flex flex-col h-full">
|
||||||
<div className="flex items-center p-4 border-b border-gray-200">
|
<div className="flex items-center p-4 border-b border-gray-200">
|
||||||
<Menu className="w-6 h-6 text-gray-500" />
|
<Settings className="w-6 h-6 text-gray-500" />
|
||||||
<h1 className="ml-2 text-lg font-semibold">MCP Inspector</h1>
|
<h1 className="ml-2 text-lg font-semibold">MCP Inspector</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="p-4">
|
<div className="p-4 flex-1 overflow-auto">
|
||||||
<div className="flex items-center space-x-2 mb-4">
|
<div className="space-y-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-medium">Transport Type</label>
|
||||||
|
<Select
|
||||||
|
value={transportType}
|
||||||
|
onValueChange={(value: "stdio" | "sse") =>
|
||||||
|
setTransportType(value)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder="Select transport type" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="stdio">STDIO</SelectItem>
|
||||||
|
<SelectItem value="sse">SSE</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
{transportType === "stdio" ? (
|
||||||
|
<>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-medium">Command</label>
|
||||||
|
<Input
|
||||||
|
placeholder="Command"
|
||||||
|
value={command}
|
||||||
|
onChange={(e) => setCommand(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-medium">Arguments</label>
|
||||||
|
<Input
|
||||||
|
placeholder="Arguments (space-separated)"
|
||||||
|
value={args}
|
||||||
|
onChange={(e) => setArgs(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-medium">URL</label>
|
||||||
|
<Input
|
||||||
|
placeholder="URL"
|
||||||
|
value={url}
|
||||||
|
onChange={(e) => setUrl(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{transportType === "stdio" && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setShowEnvVars(!showEnvVars)}
|
||||||
|
className="flex items-center w-full"
|
||||||
|
>
|
||||||
|
{showEnvVars ? (
|
||||||
|
<ChevronDown className="w-4 h-4 mr-2" />
|
||||||
|
) : (
|
||||||
|
<ChevronRight className="w-4 h-4 mr-2" />
|
||||||
|
)}
|
||||||
|
Environment Variables
|
||||||
|
</Button>
|
||||||
|
{showEnvVars && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
{Object.entries(env).map(([key, value], idx) => (
|
||||||
|
<div key={idx} className="grid grid-cols-[1fr,auto] gap-2">
|
||||||
|
<div className="space-y-1">
|
||||||
|
<Input
|
||||||
|
placeholder="Key"
|
||||||
|
value={key}
|
||||||
|
onChange={(e) => {
|
||||||
|
const newEnv = { ...env };
|
||||||
|
delete newEnv[key];
|
||||||
|
newEnv[e.target.value] = value;
|
||||||
|
setEnv(newEnv);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
placeholder="Value"
|
||||||
|
value={value}
|
||||||
|
onChange={(e) => {
|
||||||
|
const newEnv = { ...env };
|
||||||
|
newEnv[key] = e.target.value;
|
||||||
|
setEnv(newEnv);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant="destructive"
|
||||||
|
onClick={() => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { [key]: removed, ...rest } = env;
|
||||||
|
setEnv(rest);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => {
|
||||||
|
const newEnv = { ...env };
|
||||||
|
newEnv[""] = "";
|
||||||
|
setEnv(newEnv);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add Environment Variable
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Button className="w-full" onClick={onConnect}>
|
||||||
|
<Play className="w-4 h-4 mr-2" />
|
||||||
|
Connect
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-center space-x-2 mb-4">
|
||||||
<div
|
<div
|
||||||
className={`w-2 h-2 rounded-full ${
|
className={`w-2 h-2 rounded-full ${
|
||||||
connectionStatus === "connected"
|
connectionStatus === "connected"
|
||||||
@@ -27,13 +190,30 @@ const Sidebar = ({ connectionStatus }: { connectionStatus: string }) => (
|
|||||||
: "Disconnected"}
|
: "Disconnected"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
{stdErrNotifications.length > 0 && (
|
||||||
<Button variant="outline" className="w-full justify-start">
|
<>
|
||||||
<Settings className="w-4 h-4 mr-2" />
|
<div className="mt-4 border-t border-gray-200 pt-4">
|
||||||
Connection Settings
|
<h3 className="text-sm font-medium">
|
||||||
</Button>
|
Error output from MCP server
|
||||||
|
</h3>
|
||||||
|
<div className="mt-2 max-h-80 overflow-y-auto">
|
||||||
|
{stdErrNotifications.map((notification, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="text-sm text-red-500 font-mono py-2 border-b border-gray-200 last:border-b-0"
|
||||||
|
>
|
||||||
|
{notification.params.content}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default Sidebar;
|
export default Sidebar;
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
import { TabsContent } from "@/components/ui/tabs";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Send, AlertCircle } from "lucide-react";
|
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
|
||||||
import { ListToolsResult, Tool } from "mcp-typescript/types.js";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { TabsContent } from "@/components/ui/tabs";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import {
|
||||||
|
CallToolResult,
|
||||||
|
ListToolsResult,
|
||||||
|
Tool,
|
||||||
|
} from "@modelcontextprotocol/sdk/types.js";
|
||||||
|
import { AlertCircle, Send } from "lucide-react";
|
||||||
|
import { useState } from "react";
|
||||||
import ListPane from "./ListPane";
|
import ListPane from "./ListPane";
|
||||||
|
|
||||||
|
import { CompatibilityCallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
||||||
|
|
||||||
const ToolsTab = ({
|
const ToolsTab = ({
|
||||||
tools,
|
tools,
|
||||||
listTools,
|
listTools,
|
||||||
@@ -23,12 +30,59 @@ const ToolsTab = ({
|
|||||||
callTool: (name: string, params: Record<string, unknown>) => void;
|
callTool: (name: string, params: Record<string, unknown>) => void;
|
||||||
selectedTool: Tool | null;
|
selectedTool: Tool | null;
|
||||||
setSelectedTool: (tool: Tool) => void;
|
setSelectedTool: (tool: Tool) => void;
|
||||||
toolResult: string;
|
toolResult: CompatibilityCallToolResult | null;
|
||||||
nextCursor: ListToolsResult["nextCursor"];
|
nextCursor: ListToolsResult["nextCursor"];
|
||||||
error: string | null;
|
error: string | null;
|
||||||
}) => {
|
}) => {
|
||||||
const [params, setParams] = useState<Record<string, unknown>>({});
|
const [params, setParams] = useState<Record<string, unknown>>({});
|
||||||
|
|
||||||
|
const renderToolResult = () => {
|
||||||
|
if (!toolResult) return null;
|
||||||
|
|
||||||
|
if ("content" in toolResult) {
|
||||||
|
const structuredResult = toolResult as CallToolResult;
|
||||||
|
const isError = structuredResult.isError ?? false;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h4 className="font-semibold mb-2">
|
||||||
|
Tool Result: {isError ? "Error" : "Success"}
|
||||||
|
</h4>
|
||||||
|
{structuredResult.content.map((item, index) => (
|
||||||
|
<div key={index} className="mb-2">
|
||||||
|
{item.type === "text" && (
|
||||||
|
<pre className="bg-gray-50 p-4 rounded text-sm overflow-auto max-h-64">
|
||||||
|
{item.text}
|
||||||
|
</pre>
|
||||||
|
)}
|
||||||
|
{item.type === "image" && (
|
||||||
|
<img
|
||||||
|
src={`data:${item.mimeType};base64,${item.data}`}
|
||||||
|
alt="Tool result image"
|
||||||
|
className="max-w-full h-auto"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{item.type === "resource" && (
|
||||||
|
<pre className="bg-gray-50 p-4 rounded text-sm overflow-auto max-h-64">
|
||||||
|
{JSON.stringify(item.resource, null, 2)}
|
||||||
|
</pre>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
} else if ("toolResult" in toolResult) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h4 className="font-semibold mb-2">Tool Result (Legacy):</h4>
|
||||||
|
<pre className="bg-gray-50 p-4 rounded text-sm overflow-auto max-h-64">
|
||||||
|
{JSON.stringify(toolResult.toolResult, null, 2)}
|
||||||
|
</pre>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TabsContent value="tools" className="grid grid-cols-2 gap-4">
|
<TabsContent value="tools" className="grid grid-cols-2 gap-4">
|
||||||
<ListPane
|
<ListPane
|
||||||
@@ -48,7 +102,7 @@ const ToolsTab = ({
|
|||||||
isButtonDisabled={!nextCursor && tools.length > 0}
|
isButtonDisabled={!nextCursor && tools.length > 0}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="bg-white rounded-lg shadow">
|
<div className="bg-card rounded-lg shadow">
|
||||||
<div className="p-4 border-b border-gray-200">
|
<div className="p-4 border-b border-gray-200">
|
||||||
<h3 className="font-semibold">
|
<h3 className="font-semibold">
|
||||||
{selectedTool ? selectedTool.name : "Select a tool"}
|
{selectedTool ? selectedTool.name : "Select a tool"}
|
||||||
@@ -75,6 +129,23 @@ const ToolsTab = ({
|
|||||||
>
|
>
|
||||||
{key}
|
{key}
|
||||||
</Label>
|
</Label>
|
||||||
|
{
|
||||||
|
/* @ts-expect-error value type is currently unknown */
|
||||||
|
value.type === "string" ? (
|
||||||
|
<Textarea
|
||||||
|
id={key}
|
||||||
|
name={key}
|
||||||
|
// @ts-expect-error value type is currently unknown
|
||||||
|
placeholder={value.description}
|
||||||
|
onChange={(e) =>
|
||||||
|
setParams({
|
||||||
|
...params,
|
||||||
|
[key]: e.target.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
className="mt-1"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
<Input
|
<Input
|
||||||
// @ts-expect-error value type is currently unknown
|
// @ts-expect-error value type is currently unknown
|
||||||
type={value.type === "number" ? "number" : "text"}
|
type={value.type === "number" ? "number" : "text"}
|
||||||
@@ -92,7 +163,10 @@ const ToolsTab = ({
|
|||||||
: e.target.value,
|
: e.target.value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
className="mt-1"
|
||||||
/>
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
@@ -100,14 +174,7 @@ const ToolsTab = ({
|
|||||||
<Send className="w-4 h-4 mr-2" />
|
<Send className="w-4 h-4 mr-2" />
|
||||||
Run Tool
|
Run Tool
|
||||||
</Button>
|
</Button>
|
||||||
{toolResult && (
|
{toolResult && renderToolResult()}
|
||||||
<>
|
|
||||||
<h4 className="font-semibold mb-2">Tool Result:</h4>
|
|
||||||
<pre className="bg-gray-50 p-4 rounded text-sm overflow-auto max-h-64">
|
|
||||||
{toolResult}
|
|
||||||
</pre>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Alert>
|
<Alert>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const alertVariants = cva(
|
const alertVariants = cva(
|
||||||
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
|
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
|
||||||
@@ -16,8 +16,8 @@ const alertVariants = cva(
|
|||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: "default",
|
variant: "default",
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
const Alert = React.forwardRef<
|
const Alert = React.forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
@@ -29,8 +29,8 @@ const Alert = React.forwardRef<
|
|||||||
className={cn(alertVariants({ variant }), className)}
|
className={cn(alertVariants({ variant }), className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
Alert.displayName = "Alert"
|
Alert.displayName = "Alert";
|
||||||
|
|
||||||
const AlertTitle = React.forwardRef<
|
const AlertTitle = React.forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
@@ -41,8 +41,8 @@ const AlertTitle = React.forwardRef<
|
|||||||
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
|
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
AlertTitle.displayName = "AlertTitle"
|
AlertTitle.displayName = "AlertTitle";
|
||||||
|
|
||||||
const AlertDescription = React.forwardRef<
|
const AlertDescription = React.forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
@@ -53,7 +53,7 @@ const AlertDescription = React.forwardRef<
|
|||||||
className={cn("text-sm [&_p]:leading-relaxed", className)}
|
className={cn("text-sm [&_p]:leading-relaxed", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
AlertDescription.displayName = "AlertDescription"
|
AlertDescription.displayName = "AlertDescription";
|
||||||
|
|
||||||
export { Alert, AlertTitle, AlertDescription }
|
export { Alert, AlertTitle, AlertDescription };
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import { Slot } from "@radix-ui/react-slot"
|
import { Slot } from "@radix-ui/react-slot";
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const buttonVariants = cva(
|
const buttonVariants = cva(
|
||||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
|
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
|
||||||
@@ -10,7 +10,7 @@ const buttonVariants = cva(
|
|||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default:
|
default:
|
||||||
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
"bg-primary text-primary-foreground shadow hover:bg-primary/90 dark:bg-gray-800 dark:text-white dark:hover:bg-gray-700",
|
||||||
destructive:
|
destructive:
|
||||||
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||||
outline:
|
outline:
|
||||||
@@ -31,27 +31,27 @@ const buttonVariants = cva(
|
|||||||
variant: "default",
|
variant: "default",
|
||||||
size: "default",
|
size: "default",
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
export interface ButtonProps
|
export interface ButtonProps
|
||||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||||
VariantProps<typeof buttonVariants> {
|
VariantProps<typeof buttonVariants> {
|
||||||
asChild?: boolean
|
asChild?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||||
const Comp = asChild ? Slot : "button"
|
const Comp = asChild ? Slot : "button";
|
||||||
return (
|
return (
|
||||||
<Comp
|
<Comp
|
||||||
className={cn(buttonVariants({ variant, size, className }))}
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
Button.displayName = "Button"
|
Button.displayName = "Button";
|
||||||
|
|
||||||
export { Button, buttonVariants }
|
export { Button, buttonVariants };
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export interface InputProps
|
export interface InputProps
|
||||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||||
@@ -12,14 +12,14 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|||||||
type={type}
|
type={type}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
Input.displayName = "Input"
|
Input.displayName = "Input";
|
||||||
|
|
||||||
export { Input }
|
export { Input };
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const labelVariants = cva(
|
const labelVariants = cva(
|
||||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||||
)
|
);
|
||||||
|
|
||||||
const Label = React.forwardRef<
|
const Label = React.forwardRef<
|
||||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||||
@@ -18,7 +18,7 @@ const Label = React.forwardRef<
|
|||||||
className={cn(labelVariants(), className)}
|
className={cn(labelVariants(), className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
Label.displayName = LabelPrimitive.Root.displayName
|
Label.displayName = LabelPrimitive.Root.displayName;
|
||||||
|
|
||||||
export { Label }
|
export { Label };
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import {
|
import {
|
||||||
CaretSortIcon,
|
CaretSortIcon,
|
||||||
CheckIcon,
|
CheckIcon,
|
||||||
ChevronDownIcon,
|
ChevronDownIcon,
|
||||||
ChevronUpIcon,
|
ChevronUpIcon,
|
||||||
} from "@radix-ui/react-icons"
|
} from "@radix-ui/react-icons";
|
||||||
import * as SelectPrimitive from "@radix-ui/react-select"
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const Select = SelectPrimitive.Root
|
const Select = SelectPrimitive.Root;
|
||||||
|
|
||||||
const SelectGroup = SelectPrimitive.Group
|
const SelectGroup = SelectPrimitive.Group;
|
||||||
|
|
||||||
const SelectValue = SelectPrimitive.Value
|
const SelectValue = SelectPrimitive.Value;
|
||||||
|
|
||||||
const SelectTrigger = React.forwardRef<
|
const SelectTrigger = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||||
@@ -23,7 +23,7 @@ const SelectTrigger = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
@@ -32,8 +32,8 @@ const SelectTrigger = React.forwardRef<
|
|||||||
<CaretSortIcon className="h-4 w-4 opacity-50" />
|
<CaretSortIcon className="h-4 w-4 opacity-50" />
|
||||||
</SelectPrimitive.Icon>
|
</SelectPrimitive.Icon>
|
||||||
</SelectPrimitive.Trigger>
|
</SelectPrimitive.Trigger>
|
||||||
))
|
));
|
||||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
||||||
|
|
||||||
const SelectScrollUpButton = React.forwardRef<
|
const SelectScrollUpButton = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||||
@@ -43,14 +43,14 @@ const SelectScrollUpButton = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex cursor-default items-center justify-center py-1",
|
"flex cursor-default items-center justify-center py-1",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ChevronUpIcon />
|
<ChevronUpIcon />
|
||||||
</SelectPrimitive.ScrollUpButton>
|
</SelectPrimitive.ScrollUpButton>
|
||||||
))
|
));
|
||||||
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
|
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
||||||
|
|
||||||
const SelectScrollDownButton = React.forwardRef<
|
const SelectScrollDownButton = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||||
@@ -60,15 +60,15 @@ const SelectScrollDownButton = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex cursor-default items-center justify-center py-1",
|
"flex cursor-default items-center justify-center py-1",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ChevronDownIcon />
|
<ChevronDownIcon />
|
||||||
</SelectPrimitive.ScrollDownButton>
|
</SelectPrimitive.ScrollDownButton>
|
||||||
))
|
));
|
||||||
SelectScrollDownButton.displayName =
|
SelectScrollDownButton.displayName =
|
||||||
SelectPrimitive.ScrollDownButton.displayName
|
SelectPrimitive.ScrollDownButton.displayName;
|
||||||
|
|
||||||
const SelectContent = React.forwardRef<
|
const SelectContent = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Content>,
|
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||||
@@ -81,7 +81,7 @@ const SelectContent = React.forwardRef<
|
|||||||
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
position === "popper" &&
|
position === "popper" &&
|
||||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
position={position}
|
position={position}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -91,7 +91,7 @@ const SelectContent = React.forwardRef<
|
|||||||
className={cn(
|
className={cn(
|
||||||
"p-1",
|
"p-1",
|
||||||
position === "popper" &&
|
position === "popper" &&
|
||||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
@@ -99,8 +99,8 @@ const SelectContent = React.forwardRef<
|
|||||||
<SelectScrollDownButton />
|
<SelectScrollDownButton />
|
||||||
</SelectPrimitive.Content>
|
</SelectPrimitive.Content>
|
||||||
</SelectPrimitive.Portal>
|
</SelectPrimitive.Portal>
|
||||||
))
|
));
|
||||||
SelectContent.displayName = SelectPrimitive.Content.displayName
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
||||||
|
|
||||||
const SelectLabel = React.forwardRef<
|
const SelectLabel = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Label>,
|
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||||
@@ -111,8 +111,8 @@ const SelectLabel = React.forwardRef<
|
|||||||
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
|
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
SelectLabel.displayName = SelectPrimitive.Label.displayName
|
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
||||||
|
|
||||||
const SelectItem = React.forwardRef<
|
const SelectItem = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||||
@@ -122,7 +122,7 @@ const SelectItem = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
@@ -133,8 +133,8 @@ const SelectItem = React.forwardRef<
|
|||||||
</span>
|
</span>
|
||||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||||
</SelectPrimitive.Item>
|
</SelectPrimitive.Item>
|
||||||
))
|
));
|
||||||
SelectItem.displayName = SelectPrimitive.Item.displayName
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
||||||
|
|
||||||
const SelectSeparator = React.forwardRef<
|
const SelectSeparator = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Separator>,
|
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||||
@@ -145,8 +145,8 @@ const SelectSeparator = React.forwardRef<
|
|||||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Select,
|
Select,
|
||||||
@@ -159,4 +159,4 @@ export {
|
|||||||
SelectSeparator,
|
SelectSeparator,
|
||||||
SelectScrollUpButton,
|
SelectScrollUpButton,
|
||||||
SelectScrollDownButton,
|
SelectScrollDownButton,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as TabsPrimitive from "@radix-ui/react-tabs"
|
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const Tabs = TabsPrimitive.Root
|
const Tabs = TabsPrimitive.Root;
|
||||||
|
|
||||||
const TabsList = React.forwardRef<
|
const TabsList = React.forwardRef<
|
||||||
React.ElementRef<typeof TabsPrimitive.List>,
|
React.ElementRef<typeof TabsPrimitive.List>,
|
||||||
@@ -13,12 +13,12 @@ const TabsList = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
|
"inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TabsList.displayName = TabsPrimitive.List.displayName
|
TabsList.displayName = TabsPrimitive.List.displayName;
|
||||||
|
|
||||||
const TabsTrigger = React.forwardRef<
|
const TabsTrigger = React.forwardRef<
|
||||||
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
||||||
@@ -28,12 +28,12 @@ const TabsTrigger = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
|
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
|
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
||||||
|
|
||||||
const TabsContent = React.forwardRef<
|
const TabsContent = React.forwardRef<
|
||||||
React.ElementRef<typeof TabsPrimitive.Content>,
|
React.ElementRef<typeof TabsPrimitive.Content>,
|
||||||
@@ -43,11 +43,11 @@ const TabsContent = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TabsContent.displayName = TabsPrimitive.Content.displayName
|
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
||||||
|
|
||||||
export { Tabs, TabsList, TabsTrigger, TabsContent }
|
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export interface TextareaProps
|
export interface TextareaProps
|
||||||
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
||||||
@@ -11,14 +11,14 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|||||||
<textarea
|
<textarea
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
Textarea.displayName = "Textarea"
|
Textarea.displayName = "Textarea";
|
||||||
|
|
||||||
export { Textarea }
|
export { Textarea };
|
||||||
|
|||||||
19
client/src/lib/notificationTypes.ts
Normal file
19
client/src/lib/notificationTypes.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import {
|
||||||
|
NotificationSchema as BaseNotificationSchema,
|
||||||
|
ClientNotificationSchema,
|
||||||
|
} from "@modelcontextprotocol/sdk/types.js";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const StdErrNotificationSchema = BaseNotificationSchema.extend({
|
||||||
|
method: z.literal("notifications/stderr"),
|
||||||
|
params: z.object({
|
||||||
|
content: z.string(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const NotificationSchema = ClientNotificationSchema.or(
|
||||||
|
StdErrNotificationSchema,
|
||||||
|
);
|
||||||
|
|
||||||
|
export type StdErrNotification = z.infer<typeof StdErrNotificationSchema>;
|
||||||
|
export type Notification = z.infer<typeof NotificationSchema>;
|
||||||
29
client/src/lib/useDarkModeSync.ts
Normal file
29
client/src/lib/useDarkModeSync.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
// Listen for changes to the user's preferred color scheme
|
||||||
|
const useDarkModeSync = () => {
|
||||||
|
useEffect(() => {
|
||||||
|
const darkModeMediaQuery = window.matchMedia(
|
||||||
|
"(prefers-color-scheme: dark)",
|
||||||
|
);
|
||||||
|
const handleDarkModeChange = (e: MediaQueryListEvent) => {
|
||||||
|
if (e.matches) {
|
||||||
|
document.documentElement.classList.add("dark");
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.remove("dark");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (darkModeMediaQuery.matches) {
|
||||||
|
document.documentElement.classList.add("dark");
|
||||||
|
}
|
||||||
|
|
||||||
|
darkModeMediaQuery.addEventListener("change", handleDarkModeChange);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
darkModeMediaQuery.removeEventListener("change", handleDarkModeChange);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useDarkModeSync;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { clsx, type ClassValue } from "clsx"
|
import { clsx, type ClassValue } from "clsx";
|
||||||
import { twMerge } from "tailwind-merge"
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs))
|
return twMerge(clsx(inputs));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import { StrictMode } from "react";
|
import { StrictMode } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
|
import { ToastContainer } from 'react-toastify';
|
||||||
|
import 'react-toastify/dist/ReactToastify.css';
|
||||||
import App from "./App.tsx";
|
import App from "./App.tsx";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
|
|
||||||
createRoot(document.getElementById("root")!).render(
|
createRoot(document.getElementById("root")!).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<App />
|
<App />
|
||||||
|
<ToastContainer />
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,9 +2,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": [
|
"@/*": ["./src/*"]
|
||||||
"./src/*"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
|
|||||||
5893
package-lock.json
generated
Normal file
5893
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
49
package.json
49
package.json
@@ -1,25 +1,44 @@
|
|||||||
{
|
{
|
||||||
"name": "mcp-inspector",
|
"name": "@modelcontextprotocol/inspector",
|
||||||
"private": true,
|
"version": "0.2.0",
|
||||||
"version": "0.0.1",
|
"description": "Model Context Protocol inspector",
|
||||||
|
"license": "MIT",
|
||||||
|
"author": "Anthropic, PBC (https://anthropic.com)",
|
||||||
|
"homepage": "https://modelcontextprotocol.io",
|
||||||
|
"bugs": "https://github.com/modelcontextprotocol/inspector/issues",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"workspaces": ["client", "server"],
|
"bin": {
|
||||||
|
"mcp-inspector": "./bin/cli.js"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"bin",
|
||||||
|
"client/bin",
|
||||||
|
"client/dist",
|
||||||
|
"server/build"
|
||||||
|
],
|
||||||
|
"workspaces": [
|
||||||
|
"client",
|
||||||
|
"server"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "concurrently \"cd client && yarn dev\" \"cd server && yarn dev\"",
|
"dev": "concurrently \"cd client && npm run dev\" \"cd server && npm run dev\"",
|
||||||
"build-server": "cd server && yarn build",
|
"build-server": "cd server && npm run build",
|
||||||
"build-client": "cd client && yarn build",
|
"build-client": "cd client && npm run build",
|
||||||
"build": "yarn build-server && yarn build-client",
|
"build": "npm run build-server && npm run build-client",
|
||||||
"start-server": "cd server && yarn start",
|
"start-server": "cd server && npm run start",
|
||||||
"start-client": "cd client && yarn preview",
|
"start-client": "cd client && npm run preview",
|
||||||
"start": "concurrently \"yarn start-server\" \"yarn start-client\"",
|
"start": "./bin/cli.js",
|
||||||
|
"prepare": "npm run build",
|
||||||
"prettier-fix": "prettier --write .",
|
"prettier-fix": "prettier --write .",
|
||||||
"update:mcp": "git subtree pull --prefix=packages/mcp-typescript https://github.com/modelcontextprotocol/typescript-sdk.git main --squash"
|
"publish-all": "npm publish --workspaces --access public && npm publish --access public"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mcp-typescript": "file:packages/mcp-typescript"
|
"@modelcontextprotocol/inspector-client": "0.2.0",
|
||||||
|
"@modelcontextprotocol/inspector-server": "0.2.0",
|
||||||
|
"concurrently": "^9.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^9.0.1",
|
"prettier": "3.3.3",
|
||||||
"prettier": "3.3.3"
|
"@types/node": "^22.7.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
packages/mcp-typescript/.gitattributes
vendored
1
packages/mcp-typescript/.gitattributes
vendored
@@ -1 +0,0 @@
|
|||||||
dist/**/* linguist-generated=true
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
cache: yarn
|
|
||||||
|
|
||||||
- run: yarn install --immutable
|
|
||||||
- run: yarn build
|
|
||||||
|
|
||||||
- name: Verify that `yarn build` did not change outputs
|
|
||||||
run: git diff --exit-code
|
|
||||||
|
|
||||||
- run: yarn test
|
|
||||||
- run: yarn lint
|
|
||||||
131
packages/mcp-typescript/.gitignore
vendored
131
packages/mcp-typescript/.gitignore
vendored
@@ -1,131 +0,0 @@
|
|||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
.pnpm-debug.log*
|
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
*.pid.lock
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
*.lcov
|
|
||||||
|
|
||||||
# nyc test coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
|
||||||
bower_components
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
|
|
||||||
# Dependency directories
|
|
||||||
node_modules/
|
|
||||||
jspm_packages/
|
|
||||||
|
|
||||||
# Snowpack dependency directory (https://snowpack.dev/)
|
|
||||||
web_modules/
|
|
||||||
|
|
||||||
# TypeScript cache
|
|
||||||
*.tsbuildinfo
|
|
||||||
|
|
||||||
# Optional npm cache directory
|
|
||||||
.npm
|
|
||||||
|
|
||||||
# Optional eslint cache
|
|
||||||
.eslintcache
|
|
||||||
|
|
||||||
# Optional stylelint cache
|
|
||||||
.stylelintcache
|
|
||||||
|
|
||||||
# Microbundle cache
|
|
||||||
.rpt2_cache/
|
|
||||||
.rts2_cache_cjs/
|
|
||||||
.rts2_cache_es/
|
|
||||||
.rts2_cache_umd/
|
|
||||||
|
|
||||||
# Optional REPL history
|
|
||||||
.node_repl_history
|
|
||||||
|
|
||||||
# Output of 'npm pack'
|
|
||||||
*.tgz
|
|
||||||
|
|
||||||
# Yarn Integrity file
|
|
||||||
.yarn-integrity
|
|
||||||
|
|
||||||
# dotenv environment variable files
|
|
||||||
.env
|
|
||||||
.env.development.local
|
|
||||||
.env.test.local
|
|
||||||
.env.production.local
|
|
||||||
.env.local
|
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
|
||||||
.cache
|
|
||||||
.parcel-cache
|
|
||||||
|
|
||||||
# Next.js build output
|
|
||||||
.next
|
|
||||||
out
|
|
||||||
|
|
||||||
# Nuxt.js build / generate output
|
|
||||||
.nuxt
|
|
||||||
|
|
||||||
# Gatsby files
|
|
||||||
.cache/
|
|
||||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
|
||||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
||||||
# public
|
|
||||||
|
|
||||||
# vuepress build output
|
|
||||||
.vuepress/dist
|
|
||||||
|
|
||||||
# vuepress v2.x temp and cache directory
|
|
||||||
.temp
|
|
||||||
.cache
|
|
||||||
|
|
||||||
# Docusaurus cache and generated files
|
|
||||||
.docusaurus
|
|
||||||
|
|
||||||
# Serverless directories
|
|
||||||
.serverless/
|
|
||||||
|
|
||||||
# FuseBox cache
|
|
||||||
.fusebox/
|
|
||||||
|
|
||||||
# DynamoDB Local files
|
|
||||||
.dynamodb/
|
|
||||||
|
|
||||||
# TernJS port file
|
|
||||||
.tern-port
|
|
||||||
|
|
||||||
# Stores VSCode versions used for testing VSCode extensions
|
|
||||||
.vscode-test
|
|
||||||
|
|
||||||
# yarn v2
|
|
||||||
.yarn/cache
|
|
||||||
.yarn/unplugged
|
|
||||||
.yarn/build-state.yml
|
|
||||||
.yarn/install-state.gz
|
|
||||||
.pnp.*
|
|
||||||
|
|
||||||
.DS_Store
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# mcp-typescript
|
|
||||||
TypeScript implementation of the Model Context Protocol
|
|
||||||
2
packages/mcp-typescript/dist/cli.d.ts
vendored
2
packages/mcp-typescript/dist/cli.d.ts
vendored
@@ -1,2 +0,0 @@
|
|||||||
export {};
|
|
||||||
//# sourceMappingURL=cli.d.ts.map
|
|
||||||
1
packages/mcp-typescript/dist/cli.d.ts.map
vendored
1
packages/mcp-typescript/dist/cli.d.ts.map
vendored
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
|
||||||
114
packages/mcp-typescript/dist/cli.js
vendored
114
packages/mcp-typescript/dist/cli.js
vendored
@@ -1,114 +0,0 @@
|
|||||||
import EventSource from "eventsource";
|
|
||||||
import WebSocket from "ws";
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
global.EventSource = EventSource;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
global.WebSocket = WebSocket;
|
|
||||||
import express from "express";
|
|
||||||
import { Client } from "./client/index.js";
|
|
||||||
import { SSEClientTransport } from "./client/sse.js";
|
|
||||||
import { Server } from "./server/index.js";
|
|
||||||
import { SSEServerTransport } from "./server/sse.js";
|
|
||||||
import { WebSocketClientTransport } from "./client/websocket.js";
|
|
||||||
import { StdioClientTransport } from "./client/stdio.js";
|
|
||||||
import { StdioServerTransport } from "./server/stdio.js";
|
|
||||||
async function runClient(url_or_command, args) {
|
|
||||||
const client = new Client({
|
|
||||||
name: "mcp-typescript test client",
|
|
||||||
version: "0.1.0",
|
|
||||||
});
|
|
||||||
let clientTransport;
|
|
||||||
let url = undefined;
|
|
||||||
try {
|
|
||||||
url = new URL(url_or_command);
|
|
||||||
}
|
|
||||||
catch (_a) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
if ((url === null || url === void 0 ? void 0 : url.protocol) === "http:" || (url === null || url === void 0 ? void 0 : url.protocol) === "https:") {
|
|
||||||
clientTransport = new SSEClientTransport(new URL(url_or_command));
|
|
||||||
}
|
|
||||||
else if ((url === null || url === void 0 ? void 0 : url.protocol) === "ws:" || (url === null || url === void 0 ? void 0 : url.protocol) === "wss:") {
|
|
||||||
clientTransport = new WebSocketClientTransport(new URL(url_or_command));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
clientTransport = new StdioClientTransport({
|
|
||||||
command: url_or_command,
|
|
||||||
args,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
console.log("Connected to server.");
|
|
||||||
await client.connect(clientTransport);
|
|
||||||
console.log("Initialized.");
|
|
||||||
await client.close();
|
|
||||||
console.log("Closed.");
|
|
||||||
}
|
|
||||||
async function runServer(port) {
|
|
||||||
if (port !== null) {
|
|
||||||
const app = express();
|
|
||||||
let servers = [];
|
|
||||||
app.get("/sse", async (req, res) => {
|
|
||||||
console.log("Got new SSE connection");
|
|
||||||
const transport = new SSEServerTransport("/message", res);
|
|
||||||
const server = new Server({
|
|
||||||
name: "mcp-typescript test server",
|
|
||||||
version: "0.1.0",
|
|
||||||
});
|
|
||||||
servers.push(server);
|
|
||||||
server.onclose = () => {
|
|
||||||
console.log("SSE connection closed");
|
|
||||||
servers = servers.filter((s) => s !== server);
|
|
||||||
};
|
|
||||||
await server.connect(transport);
|
|
||||||
});
|
|
||||||
app.post("/message", async (req, res) => {
|
|
||||||
console.log("Received message");
|
|
||||||
const sessionId = req.query.sessionId;
|
|
||||||
const transport = servers
|
|
||||||
.map((s) => s.transport)
|
|
||||||
.find((t) => t.sessionId === sessionId);
|
|
||||||
if (!transport) {
|
|
||||||
res.status(404).send("Session not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await transport.handlePostMessage(req, res);
|
|
||||||
});
|
|
||||||
app.listen(port, () => {
|
|
||||||
console.log(`Server running on http://localhost:${port}/sse`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const server = new Server({
|
|
||||||
name: "mcp-typescript test server",
|
|
||||||
version: "0.1.0",
|
|
||||||
});
|
|
||||||
const transport = new StdioServerTransport();
|
|
||||||
await server.connect(transport);
|
|
||||||
console.log("Server running on stdio");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const args = process.argv.slice(2);
|
|
||||||
const command = args[0];
|
|
||||||
switch (command) {
|
|
||||||
case "client":
|
|
||||||
if (args.length < 2) {
|
|
||||||
console.error("Usage: client <server_url_or_command> [args...]");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
runClient(args[1], args.slice(2)).catch((error) => {
|
|
||||||
console.error(error);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "server": {
|
|
||||||
const port = args[1] ? parseInt(args[1]) : null;
|
|
||||||
runServer(port).catch((error) => {
|
|
||||||
console.error(error);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
console.error("Unrecognized command:", command);
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=cli.js.map
|
|
||||||
1
packages/mcp-typescript/dist/cli.js.map
vendored
1
packages/mcp-typescript/dist/cli.js.map
vendored
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
||||||
27
packages/mcp-typescript/dist/client/index.d.ts
vendored
27
packages/mcp-typescript/dist/client/index.d.ts
vendored
@@ -1,27 +0,0 @@
|
|||||||
import { Protocol } from "../shared/protocol.js";
|
|
||||||
import { Transport } from "../shared/transport.js";
|
|
||||||
import { ClientNotification, ClientRequest, ClientResult, Implementation, ServerCapabilities } from "../types.js";
|
|
||||||
/**
|
|
||||||
* An MCP client on top of a pluggable transport.
|
|
||||||
*
|
|
||||||
* The client will automatically begin the initialization flow with the server when connect() is called.
|
|
||||||
*/
|
|
||||||
export declare class Client extends Protocol<ClientRequest, ClientNotification, ClientResult> {
|
|
||||||
private _clientInfo;
|
|
||||||
private _serverCapabilities?;
|
|
||||||
private _serverVersion?;
|
|
||||||
/**
|
|
||||||
* Initializes this client with the given name and version information.
|
|
||||||
*/
|
|
||||||
constructor(_clientInfo: Implementation);
|
|
||||||
connect(transport: Transport): Promise<void>;
|
|
||||||
/**
|
|
||||||
* After initialization has completed, this will be populated with the server's reported capabilities.
|
|
||||||
*/
|
|
||||||
getServerCapabilities(): ServerCapabilities | undefined;
|
|
||||||
/**
|
|
||||||
* After initialization has completed, this will be populated with information about the server's name and version.
|
|
||||||
*/
|
|
||||||
getServerVersion(): Implementation | undefined;
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=index.d.ts.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,cAAc,EAGd,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAErB;;;;GAIG;AACH,qBAAa,MAAO,SAAQ,QAAQ,CAClC,aAAa,EACb,kBAAkB,EAClB,YAAY,CACb;IAOa,OAAO,CAAC,WAAW;IAN/B,OAAO,CAAC,mBAAmB,CAAC,CAAqB;IACjD,OAAO,CAAC,cAAc,CAAC,CAAiB;IAExC;;OAEG;gBACiB,WAAW,EAAE,cAAc;IAIhC,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAiC3D;;OAEG;IACH,qBAAqB,IAAI,kBAAkB,GAAG,SAAS;IAIvD;;OAEG;IACH,gBAAgB,IAAI,cAAc,GAAG,SAAS;CAG/C"}
|
|
||||||
51
packages/mcp-typescript/dist/client/index.js
vendored
51
packages/mcp-typescript/dist/client/index.js
vendored
@@ -1,51 +0,0 @@
|
|||||||
import { Protocol } from "../shared/protocol.js";
|
|
||||||
import { InitializeResultSchema, PROTOCOL_VERSION, } from "../types.js";
|
|
||||||
/**
|
|
||||||
* An MCP client on top of a pluggable transport.
|
|
||||||
*
|
|
||||||
* The client will automatically begin the initialization flow with the server when connect() is called.
|
|
||||||
*/
|
|
||||||
export class Client extends Protocol {
|
|
||||||
/**
|
|
||||||
* Initializes this client with the given name and version information.
|
|
||||||
*/
|
|
||||||
constructor(_clientInfo) {
|
|
||||||
super();
|
|
||||||
this._clientInfo = _clientInfo;
|
|
||||||
}
|
|
||||||
async connect(transport) {
|
|
||||||
await super.connect(transport);
|
|
||||||
const result = await this.request({
|
|
||||||
method: "initialize",
|
|
||||||
params: {
|
|
||||||
protocolVersion: PROTOCOL_VERSION,
|
|
||||||
capabilities: {},
|
|
||||||
clientInfo: this._clientInfo,
|
|
||||||
},
|
|
||||||
}, InitializeResultSchema);
|
|
||||||
if (result === undefined) {
|
|
||||||
throw new Error(`Server sent invalid initialize result: ${result}`);
|
|
||||||
}
|
|
||||||
if (result.protocolVersion !== PROTOCOL_VERSION) {
|
|
||||||
throw new Error(`Server's protocol version is not supported: ${result.protocolVersion}`);
|
|
||||||
}
|
|
||||||
this._serverCapabilities = result.capabilities;
|
|
||||||
this._serverVersion = result.serverInfo;
|
|
||||||
await this.notification({
|
|
||||||
method: "notifications/initialized",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* After initialization has completed, this will be populated with the server's reported capabilities.
|
|
||||||
*/
|
|
||||||
getServerCapabilities() {
|
|
||||||
return this._serverCapabilities;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* After initialization has completed, this will be populated with information about the server's name and version.
|
|
||||||
*/
|
|
||||||
getServerVersion() {
|
|
||||||
return this._serverVersion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=index.js.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,OAAO,EAKL,sBAAsB,EACtB,gBAAgB,GAEjB,MAAM,aAAa,CAAC;AAErB;;;;GAIG;AACH,MAAM,OAAO,MAAO,SAAQ,QAI3B;IAIC;;OAEG;IACH,YAAoB,WAA2B;QAC7C,KAAK,EAAE,CAAC;QADU,gBAAW,GAAX,WAAW,CAAgB;IAE/C,CAAC;IAEQ,KAAK,CAAC,OAAO,CAAC,SAAoB;QACzC,MAAM,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAE/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAC/B;YACE,MAAM,EAAE,YAAY;YACpB,MAAM,EAAE;gBACN,eAAe,EAAE,gBAAgB;gBACjC,YAAY,EAAE,EAAE;gBAChB,UAAU,EAAE,IAAI,CAAC,WAAW;aAC7B;SACF,EACD,sBAAsB,CACvB,CAAC;QAEF,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,0CAA0C,MAAM,EAAE,CAAC,CAAC;QACtE,CAAC;QAED,IAAI,MAAM,CAAC,eAAe,KAAK,gBAAgB,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CACb,+CAA+C,MAAM,CAAC,eAAe,EAAE,CACxE,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,mBAAmB,GAAG,MAAM,CAAC,YAAY,CAAC;QAC/C,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC;QAExC,MAAM,IAAI,CAAC,YAAY,CAAC;YACtB,MAAM,EAAE,2BAA2B;SACpC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,qBAAqB;QACnB,OAAO,IAAI,CAAC,mBAAmB,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,gBAAgB;QACd,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;CACF"}
|
|
||||||
22
packages/mcp-typescript/dist/client/sse.d.ts
vendored
22
packages/mcp-typescript/dist/client/sse.d.ts
vendored
@@ -1,22 +0,0 @@
|
|||||||
import { Transport } from "../shared/transport.js";
|
|
||||||
import { JSONRPCMessage } from "../types.js";
|
|
||||||
/**
|
|
||||||
* Client transport for SSE: this will connect to a server using Server-Sent Events for receiving
|
|
||||||
* messages and make separate POST requests for sending messages.
|
|
||||||
*
|
|
||||||
* This uses the EventSource API in browsers. You can install the `eventsource` package for Node.js.
|
|
||||||
*/
|
|
||||||
export declare class SSEClientTransport implements Transport {
|
|
||||||
private _eventSource?;
|
|
||||||
private _endpoint?;
|
|
||||||
private _abortController?;
|
|
||||||
private _url;
|
|
||||||
onclose?: () => void;
|
|
||||||
onerror?: (error: Error) => void;
|
|
||||||
onmessage?: (message: JSONRPCMessage) => void;
|
|
||||||
constructor(url: URL);
|
|
||||||
start(): Promise<void>;
|
|
||||||
close(): Promise<void>;
|
|
||||||
send(message: JSONRPCMessage): Promise<void>;
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=sse.d.ts.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/client/sse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAEnE;;;;;GAKG;AACH,qBAAa,kBAAmB,YAAW,SAAS;IAClD,OAAO,CAAC,YAAY,CAAC,CAAc;IACnC,OAAO,CAAC,SAAS,CAAC,CAAM;IACxB,OAAO,CAAC,gBAAgB,CAAC,CAAkB;IAC3C,OAAO,CAAC,IAAI,CAAM;IAElB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;gBAElC,GAAG,EAAE,GAAG;IAIpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyDhB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CA0BnD"}
|
|
||||||
91
packages/mcp-typescript/dist/client/sse.js
vendored
91
packages/mcp-typescript/dist/client/sse.js
vendored
@@ -1,91 +0,0 @@
|
|||||||
import { JSONRPCMessageSchema } from "../types.js";
|
|
||||||
/**
|
|
||||||
* Client transport for SSE: this will connect to a server using Server-Sent Events for receiving
|
|
||||||
* messages and make separate POST requests for sending messages.
|
|
||||||
*
|
|
||||||
* This uses the EventSource API in browsers. You can install the `eventsource` package for Node.js.
|
|
||||||
*/
|
|
||||||
export class SSEClientTransport {
|
|
||||||
constructor(url) {
|
|
||||||
this._url = url;
|
|
||||||
}
|
|
||||||
start() {
|
|
||||||
if (this._eventSource) {
|
|
||||||
throw new Error("SSEClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this._eventSource = new EventSource(this._url.href);
|
|
||||||
this._abortController = new AbortController();
|
|
||||||
this._eventSource.onerror = (event) => {
|
|
||||||
var _a;
|
|
||||||
const error = new Error(`SSE error: ${JSON.stringify(event)}`);
|
|
||||||
reject(error);
|
|
||||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
||||||
};
|
|
||||||
this._eventSource.onopen = () => {
|
|
||||||
// The connection is open, but we need to wait for the endpoint to be received.
|
|
||||||
};
|
|
||||||
this._eventSource.addEventListener("endpoint", (event) => {
|
|
||||||
var _a;
|
|
||||||
const messageEvent = event;
|
|
||||||
try {
|
|
||||||
this._endpoint = new URL(messageEvent.data, this._url);
|
|
||||||
if (this._endpoint.origin !== this._url.origin) {
|
|
||||||
throw new Error(`Endpoint origin does not match connection origin: ${this._endpoint.origin}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
reject(error);
|
|
||||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
||||||
void this.close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
this._eventSource.onmessage = (event) => {
|
|
||||||
var _a, _b;
|
|
||||||
const messageEvent = event;
|
|
||||||
let message;
|
|
||||||
try {
|
|
||||||
message = JSONRPCMessageSchema.parse(JSON.parse(messageEvent.data));
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
(_b = this.onmessage) === null || _b === void 0 ? void 0 : _b.call(this, message);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
async close() {
|
|
||||||
var _a, _b, _c;
|
|
||||||
(_a = this._abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
||||||
(_b = this._eventSource) === null || _b === void 0 ? void 0 : _b.close();
|
|
||||||
(_c = this.onclose) === null || _c === void 0 ? void 0 : _c.call(this);
|
|
||||||
}
|
|
||||||
async send(message) {
|
|
||||||
var _a, _b;
|
|
||||||
if (!this._endpoint) {
|
|
||||||
throw new Error("Not connected");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const response = await fetch(this._endpoint, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify(message),
|
|
||||||
signal: (_a = this._abortController) === null || _a === void 0 ? void 0 : _a.signal,
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
const text = await response.text().catch(() => null);
|
|
||||||
throw new Error(`Error POSTing to endpoint (HTTP ${response.status}): ${text}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=sse.js.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/client/sse.ts"],"names":[],"mappings":"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"}
|
|
||||||
41
packages/mcp-typescript/dist/client/stdio.d.ts
vendored
41
packages/mcp-typescript/dist/client/stdio.d.ts
vendored
@@ -1,41 +0,0 @@
|
|||||||
import { JSONRPCMessage } from "../types.js";
|
|
||||||
import { Transport } from "../shared/transport.js";
|
|
||||||
export type StdioServerParameters = {
|
|
||||||
/**
|
|
||||||
* The executable to run to start the server.
|
|
||||||
*/
|
|
||||||
command: string;
|
|
||||||
/**
|
|
||||||
* Command line arguments to pass to the executable.
|
|
||||||
*/
|
|
||||||
args?: string[];
|
|
||||||
/**
|
|
||||||
* The environment to use when spawning the process.
|
|
||||||
*
|
|
||||||
* The environment is NOT inherited from the parent process by default.
|
|
||||||
*/
|
|
||||||
env?: object;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Client transport for stdio: this will connect to a server by spawning a process and communicating with it over stdin/stdout.
|
|
||||||
*
|
|
||||||
* This transport is only available in Node.js environments.
|
|
||||||
*/
|
|
||||||
export declare class StdioClientTransport implements Transport {
|
|
||||||
private _process?;
|
|
||||||
private _abortController;
|
|
||||||
private _readBuffer;
|
|
||||||
private _serverParams;
|
|
||||||
onclose?: () => void;
|
|
||||||
onerror?: (error: Error) => void;
|
|
||||||
onmessage?: (message: JSONRPCMessage) => void;
|
|
||||||
constructor(server: StdioServerParameters);
|
|
||||||
/**
|
|
||||||
* Starts the server process and prepares to communicate with it.
|
|
||||||
*/
|
|
||||||
start(): Promise<void>;
|
|
||||||
private processReadBuffer;
|
|
||||||
close(): Promise<void>;
|
|
||||||
send(message: JSONRPCMessage): Promise<void>;
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=stdio.d.ts.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/client/stdio.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,MAAM,MAAM,qBAAqB,GAAG;IAClC;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAEhB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,SAAS;IACpD,OAAO,CAAC,QAAQ,CAAC,CAAe;IAChC,OAAO,CAAC,gBAAgB,CAA0C;IAClE,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,aAAa,CAAwB;IAE7C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;gBAElC,MAAM,EAAE,qBAAqB;IAIzC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyD5B,OAAO,CAAC,iBAAiB;IAenB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAc7C"}
|
|
||||||
99
packages/mcp-typescript/dist/client/stdio.js
vendored
99
packages/mcp-typescript/dist/client/stdio.js
vendored
@@ -1,99 +0,0 @@
|
|||||||
import { spawn } from "node:child_process";
|
|
||||||
import { ReadBuffer, serializeMessage } from "../shared/stdio.js";
|
|
||||||
/**
|
|
||||||
* Client transport for stdio: this will connect to a server by spawning a process and communicating with it over stdin/stdout.
|
|
||||||
*
|
|
||||||
* This transport is only available in Node.js environments.
|
|
||||||
*/
|
|
||||||
export class StdioClientTransport {
|
|
||||||
constructor(server) {
|
|
||||||
this._abortController = new AbortController();
|
|
||||||
this._readBuffer = new ReadBuffer();
|
|
||||||
this._serverParams = server;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Starts the server process and prepares to communicate with it.
|
|
||||||
*/
|
|
||||||
async start() {
|
|
||||||
if (this._process) {
|
|
||||||
throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
var _a, _b, _c, _d;
|
|
||||||
this._process = spawn(this._serverParams.command, (_a = this._serverParams.args) !== null && _a !== void 0 ? _a : [], {
|
|
||||||
// The parent process may have sensitive secrets in its env, so don't inherit it automatically.
|
|
||||||
env: this._serverParams.env === undefined
|
|
||||||
? {}
|
|
||||||
: { ...this._serverParams.env },
|
|
||||||
stdio: ["pipe", "pipe", "inherit"],
|
|
||||||
signal: this._abortController.signal,
|
|
||||||
});
|
|
||||||
this._process.on("error", (error) => {
|
|
||||||
var _a, _b;
|
|
||||||
if (error.name === "AbortError") {
|
|
||||||
// Expected when close() is called.
|
|
||||||
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
reject(error);
|
|
||||||
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
|
|
||||||
});
|
|
||||||
this._process.on("spawn", () => {
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
this._process.on("close", (_code) => {
|
|
||||||
var _a;
|
|
||||||
this._process = undefined;
|
|
||||||
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
||||||
});
|
|
||||||
(_b = this._process.stdin) === null || _b === void 0 ? void 0 : _b.on("error", (error) => {
|
|
||||||
var _a;
|
|
||||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
||||||
});
|
|
||||||
(_c = this._process.stdout) === null || _c === void 0 ? void 0 : _c.on("data", (chunk) => {
|
|
||||||
this._readBuffer.append(chunk);
|
|
||||||
this.processReadBuffer();
|
|
||||||
});
|
|
||||||
(_d = this._process.stdout) === null || _d === void 0 ? void 0 : _d.on("error", (error) => {
|
|
||||||
var _a;
|
|
||||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
processReadBuffer() {
|
|
||||||
var _a, _b;
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
const message = this._readBuffer.readMessage();
|
|
||||||
if (message === null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
(_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, message);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async close() {
|
|
||||||
this._abortController.abort();
|
|
||||||
this._process = undefined;
|
|
||||||
this._readBuffer.clear();
|
|
||||||
}
|
|
||||||
send(message) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
var _a;
|
|
||||||
if (!((_a = this._process) === null || _a === void 0 ? void 0 : _a.stdin)) {
|
|
||||||
throw new Error("Not connected");
|
|
||||||
}
|
|
||||||
const json = serializeMessage(message);
|
|
||||||
if (this._process.stdin.write(json)) {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this._process.stdin.once("drain", resolve);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=stdio.js.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/client/stdio.ts"],"names":[],"mappings":"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"}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export {};
|
|
||||||
//# sourceMappingURL=stdio.test.d.ts.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"stdio.test.d.ts","sourceRoot":"","sources":["../../src/client/stdio.test.ts"],"names":[],"mappings":""}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import { StdioClientTransport } from "./stdio.js";
|
|
||||||
const serverParameters = {
|
|
||||||
command: "/usr/bin/tee",
|
|
||||||
};
|
|
||||||
test("should start then close cleanly", async () => {
|
|
||||||
const client = new StdioClientTransport(serverParameters);
|
|
||||||
client.onerror = (error) => {
|
|
||||||
throw error;
|
|
||||||
};
|
|
||||||
let didClose = false;
|
|
||||||
client.onclose = () => {
|
|
||||||
didClose = true;
|
|
||||||
};
|
|
||||||
await client.start();
|
|
||||||
expect(didClose).toBeFalsy();
|
|
||||||
await client.close();
|
|
||||||
expect(didClose).toBeTruthy();
|
|
||||||
});
|
|
||||||
test("should read messages", async () => {
|
|
||||||
const client = new StdioClientTransport(serverParameters);
|
|
||||||
client.onerror = (error) => {
|
|
||||||
throw error;
|
|
||||||
};
|
|
||||||
const messages = [
|
|
||||||
{
|
|
||||||
jsonrpc: "2.0",
|
|
||||||
id: 1,
|
|
||||||
method: "ping",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
jsonrpc: "2.0",
|
|
||||||
method: "notifications/initialized",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const readMessages = [];
|
|
||||||
const finished = new Promise((resolve) => {
|
|
||||||
client.onmessage = (message) => {
|
|
||||||
readMessages.push(message);
|
|
||||||
if (JSON.stringify(message) === JSON.stringify(messages[1])) {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
await client.start();
|
|
||||||
await client.send(messages[0]);
|
|
||||||
await client.send(messages[1]);
|
|
||||||
await finished;
|
|
||||||
expect(readMessages).toEqual(messages);
|
|
||||||
await client.close();
|
|
||||||
});
|
|
||||||
//# sourceMappingURL=stdio.test.js.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"stdio.test.js","sourceRoot":"","sources":["../../src/client/stdio.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAyB,MAAM,YAAY,CAAC;AAEzE,MAAM,gBAAgB,GAA0B;IAC9C,OAAO,EAAE,cAAc;CACxB,CAAC;AAEF,IAAI,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;IACjD,MAAM,MAAM,GAAG,IAAI,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IAC1D,MAAM,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE;QACzB,MAAM,KAAK,CAAC;IACd,CAAC,CAAC;IAEF,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE;QACpB,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC,CAAC;IAEF,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,CAAC;IAC7B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,EAAE,CAAC;AAChC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;IACtC,MAAM,MAAM,GAAG,IAAI,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IAC1D,MAAM,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE;QACzB,MAAM,KAAK,CAAC;IACd,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAqB;QACjC;YACE,OAAO,EAAE,KAAK;YACd,EAAE,EAAE,CAAC;YACL,MAAM,EAAE,MAAM;SACf;QACD;YACE,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,2BAA2B;SACpC;KACF,CAAC;IAEF,MAAM,YAAY,GAAqB,EAAE,CAAC;IAC1C,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAC7C,MAAM,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,EAAE;YAC7B,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE3B,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5D,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,QAAQ,CAAC;IACf,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEvC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import { Transport } from "../shared/transport.js";
|
|
||||||
import { JSONRPCMessage } from "../types.js";
|
|
||||||
/**
|
|
||||||
* Client transport for WebSocket: this will connect to a server over the WebSocket protocol.
|
|
||||||
*/
|
|
||||||
export declare class WebSocketClientTransport implements Transport {
|
|
||||||
private _socket?;
|
|
||||||
private _url;
|
|
||||||
onclose?: () => void;
|
|
||||||
onerror?: (error: Error) => void;
|
|
||||||
onmessage?: (message: JSONRPCMessage) => void;
|
|
||||||
constructor(url: URL);
|
|
||||||
start(): Promise<void>;
|
|
||||||
close(): Promise<void>;
|
|
||||||
send(message: JSONRPCMessage): Promise<void>;
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=websocket.d.ts.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../src/client/websocket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAInE;;GAEG;AACH,qBAAa,wBAAyB,YAAW,SAAS;IACxD,OAAO,CAAC,OAAO,CAAC,CAAY;IAC5B,OAAO,CAAC,IAAI,CAAM;IAElB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;gBAElC,GAAG,EAAE,GAAG;IAIpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyChB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAW7C"}
|
|
||||||
61
packages/mcp-typescript/dist/client/websocket.js
vendored
61
packages/mcp-typescript/dist/client/websocket.js
vendored
@@ -1,61 +0,0 @@
|
|||||||
import { JSONRPCMessageSchema } from "../types.js";
|
|
||||||
const SUBPROTOCOL = "mcp";
|
|
||||||
/**
|
|
||||||
* Client transport for WebSocket: this will connect to a server over the WebSocket protocol.
|
|
||||||
*/
|
|
||||||
export class WebSocketClientTransport {
|
|
||||||
constructor(url) {
|
|
||||||
this._url = url;
|
|
||||||
}
|
|
||||||
start() {
|
|
||||||
if (this._socket) {
|
|
||||||
throw new Error("WebSocketClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this._socket = new WebSocket(this._url, SUBPROTOCOL);
|
|
||||||
this._socket.onerror = (event) => {
|
|
||||||
var _a;
|
|
||||||
const error = "error" in event
|
|
||||||
? event.error
|
|
||||||
: new Error(`WebSocket error: ${JSON.stringify(event)}`);
|
|
||||||
reject(error);
|
|
||||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
||||||
};
|
|
||||||
this._socket.onopen = () => {
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
this._socket.onclose = () => {
|
|
||||||
var _a;
|
|
||||||
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
||||||
};
|
|
||||||
this._socket.onmessage = (event) => {
|
|
||||||
var _a, _b;
|
|
||||||
let message;
|
|
||||||
try {
|
|
||||||
message = JSONRPCMessageSchema.parse(JSON.parse(event.data));
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
(_b = this.onmessage) === null || _b === void 0 ? void 0 : _b.call(this, message);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
async close() {
|
|
||||||
var _a;
|
|
||||||
(_a = this._socket) === null || _a === void 0 ? void 0 : _a.close();
|
|
||||||
}
|
|
||||||
send(message) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
var _a;
|
|
||||||
if (!this._socket) {
|
|
||||||
reject(new Error("Not connected"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
(_a = this._socket) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify(message));
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=websocket.js.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../src/client/websocket.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnE,MAAM,WAAW,GAAG,KAAK,CAAC;AAE1B;;GAEG;AACH,MAAM,OAAO,wBAAwB;IAQnC,YAAY,GAAQ;QAClB,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;IAClB,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,mHAAmH,CACpH,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,OAAO,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;YAErD,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE;;gBAC/B,MAAM,KAAK,GACT,OAAO,IAAI,KAAK;oBACd,CAAC,CAAE,KAAK,CAAC,KAAe;oBACxB,CAAC,CAAC,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC7D,MAAM,CAAC,KAAK,CAAC,CAAC;gBACd,MAAA,IAAI,CAAC,OAAO,qDAAG,KAAK,CAAC,CAAC;YACxB,CAAC,CAAC;YAEF,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,EAAE;gBACzB,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC;YAEF,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,GAAG,EAAE;;gBAC1B,MAAA,IAAI,CAAC,OAAO,oDAAI,CAAC;YACnB,CAAC,CAAC;YAEF,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,KAAmB,EAAE,EAAE;;gBAC/C,IAAI,OAAuB,CAAC;gBAC5B,IAAI,CAAC;oBACH,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC/D,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAA,IAAI,CAAC,OAAO,qDAAG,KAAc,CAAC,CAAC;oBAC/B,OAAO;gBACT,CAAC;gBAED,MAAA,IAAI,CAAC,SAAS,qDAAG,OAAO,CAAC,CAAC;YAC5B,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,KAAK;;QACT,MAAA,IAAI,CAAC,OAAO,0CAAE,KAAK,EAAE,CAAC;IACxB,CAAC;IAED,IAAI,CAAC,OAAuB;QAC1B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;;YACrC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClB,MAAM,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;gBACnC,OAAO;YACT,CAAC;YAED,MAAA,IAAI,CAAC,OAAO,0CAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;YAC5C,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
||||||
32
packages/mcp-typescript/dist/server/index.d.ts
vendored
32
packages/mcp-typescript/dist/server/index.d.ts
vendored
@@ -1,32 +0,0 @@
|
|||||||
import { Protocol } from "../shared/protocol.js";
|
|
||||||
import { ClientCapabilities, Implementation, ServerNotification, ServerRequest, ServerResult } from "../types.js";
|
|
||||||
/**
|
|
||||||
* An MCP server on top of a pluggable transport.
|
|
||||||
*
|
|
||||||
* This server will automatically respond to the initialization flow as initiated from the client.
|
|
||||||
*/
|
|
||||||
export declare class Server extends Protocol<ServerRequest, ServerNotification, ServerResult> {
|
|
||||||
private _serverInfo;
|
|
||||||
private _clientCapabilities?;
|
|
||||||
private _clientVersion?;
|
|
||||||
/**
|
|
||||||
* Callback for when initialization has fully completed (i.e., the client has sent an `initialized` notification).
|
|
||||||
*/
|
|
||||||
oninitialized?: () => void;
|
|
||||||
/**
|
|
||||||
* Initializes this server with the given name and version information.
|
|
||||||
*/
|
|
||||||
constructor(_serverInfo: Implementation);
|
|
||||||
private _oninitialize;
|
|
||||||
/**
|
|
||||||
* After initialization has completed, this will be populated with the client's reported capabilities.
|
|
||||||
*/
|
|
||||||
getClientCapabilities(): ClientCapabilities | undefined;
|
|
||||||
/**
|
|
||||||
* After initialization has completed, this will be populated with information about the client's name and version.
|
|
||||||
*/
|
|
||||||
getClientVersion(): Implementation | undefined;
|
|
||||||
private getCapability;
|
|
||||||
private getCapabilities;
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=index.d.ts.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EACL,kBAAkB,EAElB,cAAc,EAMd,kBAAkB,EAClB,aAAa,EACb,YAAY,EAMb,MAAM,aAAa,CAAC;AAErB;;;;GAIG;AACH,qBAAa,MAAO,SAAQ,QAAQ,CAClC,aAAa,EACb,kBAAkB,EAClB,YAAY,CACb;IAYa,OAAO,CAAC,WAAW;IAX/B,OAAO,CAAC,mBAAmB,CAAC,CAAqB;IACjD,OAAO,CAAC,cAAc,CAAC,CAAiB;IAExC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAE3B;;OAEG;gBACiB,WAAW,EAAE,cAAc;YAWjC,aAAa;IAmB3B;;OAEG;IACH,qBAAqB,IAAI,kBAAkB,GAAG,SAAS;IAIvD;;OAEG;IACH,gBAAgB,IAAI,cAAc,GAAG,SAAS;IAI9C,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,eAAe;CAUxB"}
|
|
||||||
54
packages/mcp-typescript/dist/server/index.js
vendored
54
packages/mcp-typescript/dist/server/index.js
vendored
@@ -1,54 +0,0 @@
|
|||||||
import { Protocol } from "../shared/protocol.js";
|
|
||||||
import { InitializedNotificationSchema, InitializeRequestSchema, PROTOCOL_VERSION, ListResourcesRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, SetLevelRequestSchema, } from "../types.js";
|
|
||||||
/**
|
|
||||||
* An MCP server on top of a pluggable transport.
|
|
||||||
*
|
|
||||||
* This server will automatically respond to the initialization flow as initiated from the client.
|
|
||||||
*/
|
|
||||||
export class Server extends Protocol {
|
|
||||||
/**
|
|
||||||
* Initializes this server with the given name and version information.
|
|
||||||
*/
|
|
||||||
constructor(_serverInfo) {
|
|
||||||
super();
|
|
||||||
this._serverInfo = _serverInfo;
|
|
||||||
this.setRequestHandler(InitializeRequestSchema, (request) => this._oninitialize(request));
|
|
||||||
this.setNotificationHandler(InitializedNotificationSchema, () => { var _a; return (_a = this.oninitialized) === null || _a === void 0 ? void 0 : _a.call(this); });
|
|
||||||
}
|
|
||||||
async _oninitialize(request) {
|
|
||||||
if (request.params.protocolVersion !== PROTOCOL_VERSION) {
|
|
||||||
throw new Error(`Client's protocol version is not supported: ${request.params.protocolVersion}`);
|
|
||||||
}
|
|
||||||
this._clientCapabilities = request.params.capabilities;
|
|
||||||
this._clientVersion = request.params.clientInfo;
|
|
||||||
return {
|
|
||||||
protocolVersion: PROTOCOL_VERSION,
|
|
||||||
capabilities: this.getCapabilities(),
|
|
||||||
serverInfo: this._serverInfo,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* After initialization has completed, this will be populated with the client's reported capabilities.
|
|
||||||
*/
|
|
||||||
getClientCapabilities() {
|
|
||||||
return this._clientCapabilities;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* After initialization has completed, this will be populated with information about the client's name and version.
|
|
||||||
*/
|
|
||||||
getClientVersion() {
|
|
||||||
return this._clientVersion;
|
|
||||||
}
|
|
||||||
getCapability(reqType) {
|
|
||||||
return this._requestHandlers.has(reqType) ? {} : undefined;
|
|
||||||
}
|
|
||||||
getCapabilities() {
|
|
||||||
return {
|
|
||||||
prompts: this.getCapability(ListPromptsRequestSchema.shape.method.value),
|
|
||||||
resources: this.getCapability(ListResourcesRequestSchema.shape.method.value),
|
|
||||||
tools: this.getCapability(ListToolsRequestSchema.shape.method.value),
|
|
||||||
logging: this.getCapability(SetLevelRequestSchema.shape.method.value),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=index.js.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAIL,6BAA6B,EAE7B,uBAAuB,EAEvB,gBAAgB,EAKhB,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAErB;;;;GAIG;AACH,MAAM,OAAO,MAAO,SAAQ,QAI3B;IASC;;OAEG;IACH,YAAoB,WAA2B;QAC7C,KAAK,EAAE,CAAC;QADU,gBAAW,GAAX,WAAW,CAAgB;QAG7C,IAAI,CAAC,iBAAiB,CAAC,uBAAuB,EAAE,CAAC,OAAO,EAAE,EAAE,CAC1D,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAC5B,CAAC;QACF,IAAI,CAAC,sBAAsB,CAAC,6BAA6B,EAAE,GAAG,EAAE,WAC9D,OAAA,MAAA,IAAI,CAAC,aAAa,oDAAI,CAAA,EAAA,CACvB,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,aAAa,CACzB,OAA0B;QAE1B,IAAI,OAAO,CAAC,MAAM,CAAC,eAAe,KAAK,gBAAgB,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CACb,+CAA+C,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,CAChF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC;QACvD,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC;QAEhD,OAAO;YACL,eAAe,EAAE,gBAAgB;YACjC,YAAY,EAAE,IAAI,CAAC,eAAe,EAAE;YACpC,UAAU,EAAE,IAAI,CAAC,WAAW;SAC7B,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,qBAAqB;QACnB,OAAO,IAAI,CAAC,mBAAmB,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,gBAAgB;QACd,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAEO,aAAa,CACnB,OAAgC;QAEhC,OAAO,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACvE,CAAC;IAEO,eAAe;QACrB,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,wBAAwB,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;YACxE,SAAS,EAAE,IAAI,CAAC,aAAa,CAC3B,0BAA0B,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAC9C;YACD,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,sBAAsB,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;YACpE,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,qBAAqB,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;SACtE,CAAC;IACJ,CAAC;CACF"}
|
|
||||||
46
packages/mcp-typescript/dist/server/sse.d.ts
vendored
46
packages/mcp-typescript/dist/server/sse.d.ts
vendored
@@ -1,46 +0,0 @@
|
|||||||
import { IncomingMessage, ServerResponse } from "node:http";
|
|
||||||
import { Transport } from "../shared/transport.js";
|
|
||||||
import { JSONRPCMessage } from "../types.js";
|
|
||||||
/**
|
|
||||||
* Server transport for SSE: this will send messages over an SSE connection and receive messages from HTTP POST requests.
|
|
||||||
*
|
|
||||||
* This transport is only available in Node.js environments.
|
|
||||||
*/
|
|
||||||
export declare class SSEServerTransport implements Transport {
|
|
||||||
private _endpoint;
|
|
||||||
private res;
|
|
||||||
private _sseResponse?;
|
|
||||||
private _sessionId;
|
|
||||||
onclose?: () => void;
|
|
||||||
onerror?: (error: Error) => void;
|
|
||||||
onmessage?: (message: JSONRPCMessage) => void;
|
|
||||||
/**
|
|
||||||
* Creates a new SSE server transport, which will direct the client to POST messages to the relative or absolute URL identified by `_endpoint`.
|
|
||||||
*/
|
|
||||||
constructor(_endpoint: string, res: ServerResponse);
|
|
||||||
/**
|
|
||||||
* Handles the initial SSE connection request.
|
|
||||||
*
|
|
||||||
* This should be called when a GET request is made to establish the SSE stream.
|
|
||||||
*/
|
|
||||||
start(): Promise<void>;
|
|
||||||
/**
|
|
||||||
* Handles incoming POST messages.
|
|
||||||
*
|
|
||||||
* This should be called when a POST request is made to send a message to the server.
|
|
||||||
*/
|
|
||||||
handlePostMessage(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
||||||
/**
|
|
||||||
* Handle a client message, regardless of how it arrived. This can be used to inform the server of messages that arrive via a means different than HTTP POST.
|
|
||||||
*/
|
|
||||||
handleMessage(message: unknown): Promise<void>;
|
|
||||||
close(): Promise<void>;
|
|
||||||
send(message: JSONRPCMessage): Promise<void>;
|
|
||||||
/**
|
|
||||||
* Returns the session ID for this transport.
|
|
||||||
*
|
|
||||||
* This can be used to route incoming POST requests.
|
|
||||||
*/
|
|
||||||
get sessionId(): string;
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=sse.d.ts.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/server/sse.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAMnE;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,SAAS;IAYhD,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,GAAG;IAZb,OAAO,CAAC,YAAY,CAAC,CAAiB;IACtC,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAE9C;;OAEG;gBAEO,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,cAAc;IAK7B;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB5B;;;;OAIG;IACG,iBAAiB,CACrB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC;IAkChB;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAY9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlD;;;;OAIG;IACH,IAAI,SAAS,IAAI,MAAM,CAEtB;CACF"}
|
|
||||||
116
packages/mcp-typescript/dist/server/sse.js
vendored
116
packages/mcp-typescript/dist/server/sse.js
vendored
@@ -1,116 +0,0 @@
|
|||||||
import { randomUUID } from "node:crypto";
|
|
||||||
import { JSONRPCMessageSchema } from "../types.js";
|
|
||||||
import getRawBody from "raw-body";
|
|
||||||
import contentType from "content-type";
|
|
||||||
const MAXIMUM_MESSAGE_SIZE = "4mb";
|
|
||||||
/**
|
|
||||||
* Server transport for SSE: this will send messages over an SSE connection and receive messages from HTTP POST requests.
|
|
||||||
*
|
|
||||||
* This transport is only available in Node.js environments.
|
|
||||||
*/
|
|
||||||
export class SSEServerTransport {
|
|
||||||
/**
|
|
||||||
* Creates a new SSE server transport, which will direct the client to POST messages to the relative or absolute URL identified by `_endpoint`.
|
|
||||||
*/
|
|
||||||
constructor(_endpoint, res) {
|
|
||||||
this._endpoint = _endpoint;
|
|
||||||
this.res = res;
|
|
||||||
this._sessionId = randomUUID();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Handles the initial SSE connection request.
|
|
||||||
*
|
|
||||||
* This should be called when a GET request is made to establish the SSE stream.
|
|
||||||
*/
|
|
||||||
async start() {
|
|
||||||
if (this._sseResponse) {
|
|
||||||
throw new Error("SSEServerTransport already started! If using Server class, note that connect() calls start() automatically.");
|
|
||||||
}
|
|
||||||
this.res.writeHead(200, {
|
|
||||||
"Content-Type": "text/event-stream",
|
|
||||||
"Cache-Control": "no-cache",
|
|
||||||
Connection: "keep-alive",
|
|
||||||
});
|
|
||||||
// Send the endpoint event
|
|
||||||
this.res.write(`event: endpoint\ndata: ${encodeURI(this._endpoint)}?sessionId=${this._sessionId}\n\n`);
|
|
||||||
this._sseResponse = this.res;
|
|
||||||
this.res.on("close", () => {
|
|
||||||
var _a;
|
|
||||||
this._sseResponse = undefined;
|
|
||||||
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Handles incoming POST messages.
|
|
||||||
*
|
|
||||||
* This should be called when a POST request is made to send a message to the server.
|
|
||||||
*/
|
|
||||||
async handlePostMessage(req, res) {
|
|
||||||
var _a, _b, _c;
|
|
||||||
if (!this._sseResponse) {
|
|
||||||
const message = "SSE connection not established";
|
|
||||||
res.writeHead(500).end(message);
|
|
||||||
throw new Error(message);
|
|
||||||
}
|
|
||||||
let body;
|
|
||||||
try {
|
|
||||||
const ct = contentType.parse((_a = req.headers["content-type"]) !== null && _a !== void 0 ? _a : "");
|
|
||||||
if (ct.type !== "application/json") {
|
|
||||||
throw new Error(`Unsupported content-type: ${ct}`);
|
|
||||||
}
|
|
||||||
body = await getRawBody(req, {
|
|
||||||
limit: MAXIMUM_MESSAGE_SIZE,
|
|
||||||
encoding: (_b = ct.parameters.charset) !== null && _b !== void 0 ? _b : "utf-8",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
res.writeHead(400).end(String(error));
|
|
||||||
(_c = this.onerror) === null || _c === void 0 ? void 0 : _c.call(this, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await this.handleMessage(JSON.parse(body));
|
|
||||||
}
|
|
||||||
catch (_d) {
|
|
||||||
res.writeHead(400).end(`Invalid message: ${body}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
res.writeHead(202).end("Accepted");
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Handle a client message, regardless of how it arrived. This can be used to inform the server of messages that arrive via a means different than HTTP POST.
|
|
||||||
*/
|
|
||||||
async handleMessage(message) {
|
|
||||||
var _a, _b;
|
|
||||||
let parsedMessage;
|
|
||||||
try {
|
|
||||||
parsedMessage = JSONRPCMessageSchema.parse(message);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
(_b = this.onmessage) === null || _b === void 0 ? void 0 : _b.call(this, parsedMessage);
|
|
||||||
}
|
|
||||||
async close() {
|
|
||||||
var _a, _b;
|
|
||||||
(_a = this._sseResponse) === null || _a === void 0 ? void 0 : _a.end();
|
|
||||||
this._sseResponse = undefined;
|
|
||||||
(_b = this.onclose) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
||||||
}
|
|
||||||
async send(message) {
|
|
||||||
if (!this._sseResponse) {
|
|
||||||
throw new Error("Not connected");
|
|
||||||
}
|
|
||||||
this._sseResponse.write(`event: message\ndata: ${JSON.stringify(message)}\n\n`);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Returns the session ID for this transport.
|
|
||||||
*
|
|
||||||
* This can be used to route incoming POST requests.
|
|
||||||
*/
|
|
||||||
get sessionId() {
|
|
||||||
return this._sessionId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=sse.js.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/server/sse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,EAAkB,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,UAAU,MAAM,UAAU,CAAC;AAClC,OAAO,WAAW,MAAM,cAAc,CAAC;AAEvC,MAAM,oBAAoB,GAAG,KAAK,CAAC;AAEnC;;;;GAIG;AACH,MAAM,OAAO,kBAAkB;IAQ7B;;OAEG;IACH,YACU,SAAiB,EACjB,GAAmB;QADnB,cAAS,GAAT,SAAS,CAAQ;QACjB,QAAG,GAAH,GAAG,CAAgB;QAE3B,IAAI,CAAC,UAAU,GAAG,UAAU,EAAE,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CACb,6GAA6G,CAC9G,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;YACtB,cAAc,EAAE,mBAAmB;YACnC,eAAe,EAAE,UAAU;YAC3B,UAAU,EAAE,YAAY;SACzB,CAAC,CAAC;QAEH,0BAA0B;QAC1B,IAAI,CAAC,GAAG,CAAC,KAAK,CACZ,0BAA0B,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,IAAI,CAAC,UAAU,MAAM,CACvF,CAAC;QAEF,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;;YACxB,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;YAC9B,MAAA,IAAI,CAAC,OAAO,oDAAI,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,iBAAiB,CACrB,GAAoB,EACpB,GAAmB;;QAEnB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,MAAM,OAAO,GAAG,gCAAgC,CAAC;YACjD,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;QAED,IAAI,IAAY,CAAC;QACjB,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,MAAA,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,mCAAI,EAAE,CAAC,CAAC;YAChE,IAAI,EAAE,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBACnC,MAAM,IAAI,KAAK,CAAC,6BAA6B,EAAE,EAAE,CAAC,CAAC;YACrD,CAAC;YAED,IAAI,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE;gBAC3B,KAAK,EAAE,oBAAoB;gBAC3B,QAAQ,EAAE,MAAA,EAAE,CAAC,UAAU,CAAC,OAAO,mCAAI,OAAO;aAC3C,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACtC,MAAA,IAAI,CAAC,OAAO,qDAAG,KAAc,CAAC,CAAC;YAC/B,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAC7C,CAAC;QAAC,WAAM,CAAC;YACP,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC;YACnD,OAAO;QACT,CAAC;QAED,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,OAAgB;;QAClC,IAAI,aAA6B,CAAC;QAClC,IAAI,CAAC;YACH,aAAa,GAAG,oBAAoB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACtD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAA,IAAI,CAAC,OAAO,qDAAG,KAAc,CAAC,CAAC;YAC/B,MAAM,KAAK,CAAC;QACd,CAAC;QAED,MAAA,IAAI,CAAC,SAAS,qDAAG,aAAa,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,KAAK;;QACT,MAAA,IAAI,CAAC,YAAY,0CAAE,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;QAC9B,MAAA,IAAI,CAAC,OAAO,oDAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAuB;QAChC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;QACnC,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,KAAK,CACrB,yBAAyB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CACvD,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;CACF"}
|
|
||||||
28
packages/mcp-typescript/dist/server/stdio.d.ts
vendored
28
packages/mcp-typescript/dist/server/stdio.d.ts
vendored
@@ -1,28 +0,0 @@
|
|||||||
import { Readable, Writable } from "node:stream";
|
|
||||||
import { JSONRPCMessage } from "../types.js";
|
|
||||||
import { Transport } from "../shared/transport.js";
|
|
||||||
/**
|
|
||||||
* Server transport for stdio: this communicates with a MCP client by reading from the current process' stdin and writing to stdout.
|
|
||||||
*
|
|
||||||
* This transport is only available in Node.js environments.
|
|
||||||
*/
|
|
||||||
export declare class StdioServerTransport implements Transport {
|
|
||||||
private _stdin;
|
|
||||||
private _stdout;
|
|
||||||
private _readBuffer;
|
|
||||||
private _started;
|
|
||||||
constructor(_stdin?: Readable, _stdout?: Writable);
|
|
||||||
onclose?: () => void;
|
|
||||||
onerror?: (error: Error) => void;
|
|
||||||
onmessage?: (message: JSONRPCMessage) => void;
|
|
||||||
_ondata: (chunk: Buffer) => void;
|
|
||||||
_onerror: (error: Error) => void;
|
|
||||||
/**
|
|
||||||
* Starts listening for messages on stdin.
|
|
||||||
*/
|
|
||||||
start(): Promise<void>;
|
|
||||||
private processReadBuffer;
|
|
||||||
close(): Promise<void>;
|
|
||||||
send(message: JSONRPCMessage): Promise<void>;
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=stdio.d.ts.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/server/stdio.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,SAAS;IAKlD,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,OAAO;IALjB,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,QAAQ,CAAS;gBAGf,MAAM,GAAE,QAAwB,EAChC,OAAO,GAAE,QAAyB;IAG5C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAG9C,OAAO,UAAW,MAAM,UAGtB;IACF,QAAQ,UAAW,KAAK,UAEtB;IAEF;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B,OAAO,CAAC,iBAAiB;IAenB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAU7C"}
|
|
||||||
69
packages/mcp-typescript/dist/server/stdio.js
vendored
69
packages/mcp-typescript/dist/server/stdio.js
vendored
@@ -1,69 +0,0 @@
|
|||||||
import process from "node:process";
|
|
||||||
import { ReadBuffer, serializeMessage } from "../shared/stdio.js";
|
|
||||||
/**
|
|
||||||
* Server transport for stdio: this communicates with a MCP client by reading from the current process' stdin and writing to stdout.
|
|
||||||
*
|
|
||||||
* This transport is only available in Node.js environments.
|
|
||||||
*/
|
|
||||||
export class StdioServerTransport {
|
|
||||||
constructor(_stdin = process.stdin, _stdout = process.stdout) {
|
|
||||||
this._stdin = _stdin;
|
|
||||||
this._stdout = _stdout;
|
|
||||||
this._readBuffer = new ReadBuffer();
|
|
||||||
this._started = false;
|
|
||||||
// Arrow functions to bind `this` properly, while maintaining function identity.
|
|
||||||
this._ondata = (chunk) => {
|
|
||||||
this._readBuffer.append(chunk);
|
|
||||||
this.processReadBuffer();
|
|
||||||
};
|
|
||||||
this._onerror = (error) => {
|
|
||||||
var _a;
|
|
||||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Starts listening for messages on stdin.
|
|
||||||
*/
|
|
||||||
async start() {
|
|
||||||
if (this._started) {
|
|
||||||
throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
|
|
||||||
}
|
|
||||||
this._started = true;
|
|
||||||
this._stdin.on("data", this._ondata);
|
|
||||||
this._stdin.on("error", this._onerror);
|
|
||||||
}
|
|
||||||
processReadBuffer() {
|
|
||||||
var _a, _b;
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
const message = this._readBuffer.readMessage();
|
|
||||||
if (message === null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
(_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, message);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async close() {
|
|
||||||
var _a;
|
|
||||||
this._stdin.off("data", this._ondata);
|
|
||||||
this._stdin.off("error", this._onerror);
|
|
||||||
this._readBuffer.clear();
|
|
||||||
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
||||||
}
|
|
||||||
send(message) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const json = serializeMessage(message);
|
|
||||||
if (this._stdout.write(json)) {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this._stdout.once("drain", resolve);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=stdio.js.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/server/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAIlE;;;;GAIG;AACH,MAAM,OAAO,oBAAoB;IAI/B,YACU,SAAmB,OAAO,CAAC,KAAK,EAChC,UAAoB,OAAO,CAAC,MAAM;QADlC,WAAM,GAAN,MAAM,CAA0B;QAChC,YAAO,GAAP,OAAO,CAA2B;QALpC,gBAAW,GAAe,IAAI,UAAU,EAAE,CAAC;QAC3C,aAAQ,GAAG,KAAK,CAAC;QAWzB,gFAAgF;QAChF,YAAO,GAAG,CAAC,KAAa,EAAE,EAAE;YAC1B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC/B,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,CAAC,CAAC;QACF,aAAQ,GAAG,CAAC,KAAY,EAAE,EAAE;;YAC1B,MAAA,IAAI,CAAC,OAAO,qDAAG,KAAK,CAAC,CAAC;QACxB,CAAC,CAAC;IAbC,CAAC;IAeJ;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CACb,+GAA+G,CAChH,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzC,CAAC;IAEO,iBAAiB;;QACvB,OAAO,IAAI,EAAE,CAAC;YACZ,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;gBAC/C,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;oBACrB,MAAM;gBACR,CAAC;gBAED,MAAA,IAAI,CAAC,SAAS,qDAAG,OAAO,CAAC,CAAC;YAC5B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAA,IAAI,CAAC,OAAO,qDAAG,KAAc,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;;QACT,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QACzB,MAAA,IAAI,CAAC,OAAO,oDAAI,CAAC;IACnB,CAAC;IAED,IAAI,CAAC,OAAuB;QAC1B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7B,OAAO,EAAE,CAAC;YACZ,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACtC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export {};
|
|
||||||
//# sourceMappingURL=stdio.test.d.ts.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"stdio.test.d.ts","sourceRoot":"","sources":["../../src/server/stdio.test.ts"],"names":[],"mappings":""}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
import { Readable, Writable } from "node:stream";
|
|
||||||
import { ReadBuffer, serializeMessage } from "../shared/stdio.js";
|
|
||||||
import { StdioServerTransport } from "./stdio.js";
|
|
||||||
let input;
|
|
||||||
let outputBuffer;
|
|
||||||
let output;
|
|
||||||
beforeEach(() => {
|
|
||||||
input = new Readable({
|
|
||||||
// We'll use input.push() instead.
|
|
||||||
read: () => { },
|
|
||||||
});
|
|
||||||
outputBuffer = new ReadBuffer();
|
|
||||||
output = new Writable({
|
|
||||||
write(chunk, encoding, callback) {
|
|
||||||
outputBuffer.append(chunk);
|
|
||||||
callback();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test("should start then close cleanly", async () => {
|
|
||||||
const server = new StdioServerTransport(input, output);
|
|
||||||
server.onerror = (error) => {
|
|
||||||
throw error;
|
|
||||||
};
|
|
||||||
let didClose = false;
|
|
||||||
server.onclose = () => {
|
|
||||||
didClose = true;
|
|
||||||
};
|
|
||||||
await server.start();
|
|
||||||
expect(didClose).toBeFalsy();
|
|
||||||
await server.close();
|
|
||||||
expect(didClose).toBeTruthy();
|
|
||||||
});
|
|
||||||
test("should not read until started", async () => {
|
|
||||||
const server = new StdioServerTransport(input, output);
|
|
||||||
server.onerror = (error) => {
|
|
||||||
throw error;
|
|
||||||
};
|
|
||||||
let didRead = false;
|
|
||||||
const readMessage = new Promise((resolve) => {
|
|
||||||
server.onmessage = (message) => {
|
|
||||||
didRead = true;
|
|
||||||
resolve(message);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
const message = {
|
|
||||||
jsonrpc: "2.0",
|
|
||||||
id: 1,
|
|
||||||
method: "ping",
|
|
||||||
};
|
|
||||||
input.push(serializeMessage(message));
|
|
||||||
expect(didRead).toBeFalsy();
|
|
||||||
await server.start();
|
|
||||||
expect(await readMessage).toEqual(message);
|
|
||||||
});
|
|
||||||
test("should read multiple messages", async () => {
|
|
||||||
const server = new StdioServerTransport(input, output);
|
|
||||||
server.onerror = (error) => {
|
|
||||||
throw error;
|
|
||||||
};
|
|
||||||
const messages = [
|
|
||||||
{
|
|
||||||
jsonrpc: "2.0",
|
|
||||||
id: 1,
|
|
||||||
method: "ping",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
jsonrpc: "2.0",
|
|
||||||
method: "notifications/initialized",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const readMessages = [];
|
|
||||||
const finished = new Promise((resolve) => {
|
|
||||||
server.onmessage = (message) => {
|
|
||||||
readMessages.push(message);
|
|
||||||
if (JSON.stringify(message) === JSON.stringify(messages[1])) {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
input.push(serializeMessage(messages[0]));
|
|
||||||
input.push(serializeMessage(messages[1]));
|
|
||||||
await server.start();
|
|
||||||
await finished;
|
|
||||||
expect(readMessages).toEqual(messages);
|
|
||||||
});
|
|
||||||
//# sourceMappingURL=stdio.test.js.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"stdio.test.js","sourceRoot":"","sources":["../../src/server/stdio.test.ts"],"names":[],"mappings":"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"}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
import { AnyZodObject, ZodLiteral, ZodObject, z } from "zod";
|
|
||||||
import { JSONRPCRequest, Notification, Progress, Request, Result } from "../types.js";
|
|
||||||
import { Transport } from "./transport.js";
|
|
||||||
/**
|
|
||||||
* Callback for progress notifications.
|
|
||||||
*/
|
|
||||||
export type ProgressCallback = (progress: Progress) => void;
|
|
||||||
/**
|
|
||||||
* Implements MCP protocol framing on top of a pluggable transport, including
|
|
||||||
* features like request/response linking, notifications, and progress.
|
|
||||||
*/
|
|
||||||
export declare class Protocol<SendRequestT extends Request, SendNotificationT extends Notification, SendResultT extends Result> {
|
|
||||||
private _transport?;
|
|
||||||
private _requestMessageId;
|
|
||||||
protected _requestHandlers: Map<string, (request: JSONRPCRequest) => Promise<SendResultT>>;
|
|
||||||
private _notificationHandlers;
|
|
||||||
private _responseHandlers;
|
|
||||||
private _progressHandlers;
|
|
||||||
/**
|
|
||||||
* Callback for when the connection is closed for any reason.
|
|
||||||
*
|
|
||||||
* This is invoked when close() is called as well.
|
|
||||||
*/
|
|
||||||
onclose?: () => void;
|
|
||||||
/**
|
|
||||||
* Callback for when an error occurs.
|
|
||||||
*
|
|
||||||
* Note that errors are not necessarily fatal; they are used for reporting any kind of exceptional condition out of band.
|
|
||||||
*/
|
|
||||||
onerror?: (error: Error) => void;
|
|
||||||
/**
|
|
||||||
* A handler to invoke for any request types that do not have their own handler installed.
|
|
||||||
*/
|
|
||||||
fallbackRequestHandler?: (request: Request) => Promise<SendResultT>;
|
|
||||||
/**
|
|
||||||
* A handler to invoke for any notification types that do not have their own handler installed.
|
|
||||||
*/
|
|
||||||
fallbackNotificationHandler?: (notification: Notification) => Promise<void>;
|
|
||||||
constructor();
|
|
||||||
/**
|
|
||||||
* Attaches to the given transport, starts it, and starts listening for messages.
|
|
||||||
*
|
|
||||||
* The Protocol object assumes ownership of the Transport, replacing any callbacks that have already been set, and expects that it is the only user of the Transport instance going forward.
|
|
||||||
*/
|
|
||||||
connect(transport: Transport): Promise<void>;
|
|
||||||
private _onclose;
|
|
||||||
private _onerror;
|
|
||||||
private _onnotification;
|
|
||||||
private _onrequest;
|
|
||||||
private _onprogress;
|
|
||||||
private _onresponse;
|
|
||||||
get transport(): Transport | undefined;
|
|
||||||
/**
|
|
||||||
* Closes the connection.
|
|
||||||
*/
|
|
||||||
close(): Promise<void>;
|
|
||||||
/**
|
|
||||||
* Sends a request and wait for a response, with optional progress notifications in the meantime (if supported by the server).
|
|
||||||
*
|
|
||||||
* Do not use this method to emit notifications! Use notification() instead.
|
|
||||||
*/
|
|
||||||
request<T extends AnyZodObject>(request: SendRequestT, resultSchema: T, onprogress?: ProgressCallback): Promise<z.infer<T>>;
|
|
||||||
/**
|
|
||||||
* Emits a notification, which is a one-way message that does not expect a response.
|
|
||||||
*/
|
|
||||||
notification(notification: SendNotificationT): Promise<void>;
|
|
||||||
/**
|
|
||||||
* Registers a handler to invoke when this protocol object receives a request with the given method.
|
|
||||||
*
|
|
||||||
* Note that this will replace any previous request handler for the same method.
|
|
||||||
*/
|
|
||||||
setRequestHandler<T extends ZodObject<{
|
|
||||||
method: ZodLiteral<string>;
|
|
||||||
}>>(requestSchema: T, handler: (request: z.infer<T>) => SendResultT | Promise<SendResultT>): void;
|
|
||||||
/**
|
|
||||||
* Removes the request handler for the given method.
|
|
||||||
*/
|
|
||||||
removeRequestHandler(method: string): void;
|
|
||||||
/**
|
|
||||||
* Registers a handler to invoke when this protocol object receives a notification with the given method.
|
|
||||||
*
|
|
||||||
* Note that this will replace any previous notification handler for the same method.
|
|
||||||
*/
|
|
||||||
setNotificationHandler<T extends ZodObject<{
|
|
||||||
method: ZodLiteral<string>;
|
|
||||||
}>>(notificationSchema: T, handler: (notification: z.infer<T>) => void | Promise<void>): void;
|
|
||||||
/**
|
|
||||||
* Removes the notification handler for the given method.
|
|
||||||
*/
|
|
||||||
removeNotificationHandler(method: string): void;
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=protocol.d.ts.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/shared/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7D,OAAO,EAIL,cAAc,EAGd,YAAY,EAEZ,QAAQ,EAGR,OAAO,EACP,MAAM,EACP,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;AAE5D;;;GAGG;AACH,qBAAa,QAAQ,CACnB,YAAY,SAAS,OAAO,EAC5B,iBAAiB,SAAS,YAAY,EACtC,WAAW,SAAS,MAAM;IAE1B,OAAO,CAAC,UAAU,CAAC,CAAY;IAC/B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,SAAS,CAAC,gBAAgB,EAAE,GAAG,CAC7B,MAAM,EACN,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,WAAW,CAAC,CAClD,CAAa;IACd,OAAO,CAAC,qBAAqB,CAGf;IACd,OAAO,CAAC,iBAAiB,CAGX;IACd,OAAO,CAAC,iBAAiB,CAA4C;IAErE;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC;;OAEG;IACH,sBAAsB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAEpE;;OAEG;IACH,2BAA2B,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;;IAc5E;;;;OAIG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBlD,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,UAAU;IAiDlB,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,WAAW;IA0BnB,IAAI,SAAS,IAAI,SAAS,GAAG,SAAS,CAErC;IAED;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;;;OAIG;IACH,OAAO,CAAC,CAAC,SAAS,YAAY,EAC5B,OAAO,EAAE,YAAY,EACrB,YAAY,EAAE,CAAC,EACf,UAAU,CAAC,EAAE,gBAAgB,GAC5B,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAuCtB;;OAEG;IACG,YAAY,CAAC,YAAY,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAalE;;;;OAIG;IACH,iBAAiB,CACf,CAAC,SAAS,SAAS,CAAC;QAClB,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;KAC5B,CAAC,EAEF,aAAa,EAAE,CAAC,EAChB,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,GACnE,IAAI;IAMP;;OAEG;IACH,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI1C;;;;OAIG;IACH,sBAAsB,CACpB,CAAC,SAAS,SAAS,CAAC;QAClB,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;KAC5B,CAAC,EAEF,kBAAkB,EAAE,CAAC,EACrB,OAAO,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAC1D,IAAI;IAQP;;OAEG;IACH,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAGhD"}
|
|
||||||
225
packages/mcp-typescript/dist/shared/protocol.js
vendored
225
packages/mcp-typescript/dist/shared/protocol.js
vendored
@@ -1,225 +0,0 @@
|
|||||||
import { ErrorCode, McpError, PingRequestSchema, ProgressNotificationSchema, } from "../types.js";
|
|
||||||
/**
|
|
||||||
* Implements MCP protocol framing on top of a pluggable transport, including
|
|
||||||
* features like request/response linking, notifications, and progress.
|
|
||||||
*/
|
|
||||||
export class Protocol {
|
|
||||||
constructor() {
|
|
||||||
this._requestMessageId = 0;
|
|
||||||
this._requestHandlers = new Map();
|
|
||||||
this._notificationHandlers = new Map();
|
|
||||||
this._responseHandlers = new Map();
|
|
||||||
this._progressHandlers = new Map();
|
|
||||||
this.setNotificationHandler(ProgressNotificationSchema, (notification) => {
|
|
||||||
this._onprogress(notification);
|
|
||||||
});
|
|
||||||
this.setRequestHandler(PingRequestSchema,
|
|
||||||
// Automatic pong by default.
|
|
||||||
(_request) => ({}));
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Attaches to the given transport, starts it, and starts listening for messages.
|
|
||||||
*
|
|
||||||
* The Protocol object assumes ownership of the Transport, replacing any callbacks that have already been set, and expects that it is the only user of the Transport instance going forward.
|
|
||||||
*/
|
|
||||||
async connect(transport) {
|
|
||||||
this._transport = transport;
|
|
||||||
this._transport.onclose = () => {
|
|
||||||
this._onclose();
|
|
||||||
};
|
|
||||||
this._transport.onerror = (error) => {
|
|
||||||
this._onerror(error);
|
|
||||||
};
|
|
||||||
this._transport.onmessage = (message) => {
|
|
||||||
if (!("method" in message)) {
|
|
||||||
this._onresponse(message);
|
|
||||||
}
|
|
||||||
else if ("id" in message) {
|
|
||||||
this._onrequest(message);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this._onnotification(message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
await this._transport.start();
|
|
||||||
}
|
|
||||||
_onclose() {
|
|
||||||
var _a;
|
|
||||||
const responseHandlers = this._responseHandlers;
|
|
||||||
this._responseHandlers = new Map();
|
|
||||||
this._progressHandlers.clear();
|
|
||||||
this._transport = undefined;
|
|
||||||
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
||||||
const error = new McpError(ErrorCode.ConnectionClosed, "Connection closed");
|
|
||||||
for (const handler of responseHandlers.values()) {
|
|
||||||
handler(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_onerror(error) {
|
|
||||||
var _a;
|
|
||||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
||||||
}
|
|
||||||
_onnotification(notification) {
|
|
||||||
var _a;
|
|
||||||
const handler = (_a = this._notificationHandlers.get(notification.method)) !== null && _a !== void 0 ? _a : this.fallbackNotificationHandler;
|
|
||||||
// Ignore notifications not being subscribed to.
|
|
||||||
if (handler === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
handler(notification).catch((error) => this._onerror(new Error(`Uncaught error in notification handler: ${error}`)));
|
|
||||||
}
|
|
||||||
_onrequest(request) {
|
|
||||||
var _a, _b;
|
|
||||||
const handler = (_a = this._requestHandlers.get(request.method)) !== null && _a !== void 0 ? _a : this.fallbackRequestHandler;
|
|
||||||
if (handler === undefined) {
|
|
||||||
(_b = this._transport) === null || _b === void 0 ? void 0 : _b.send({
|
|
||||||
jsonrpc: "2.0",
|
|
||||||
id: request.id,
|
|
||||||
error: {
|
|
||||||
code: ErrorCode.MethodNotFound,
|
|
||||||
message: "Method not found",
|
|
||||||
},
|
|
||||||
}).catch((error) => this._onerror(new Error(`Failed to send an error response: ${error}`)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
handler(request)
|
|
||||||
.then((result) => {
|
|
||||||
var _a;
|
|
||||||
(_a = this._transport) === null || _a === void 0 ? void 0 : _a.send({
|
|
||||||
result,
|
|
||||||
jsonrpc: "2.0",
|
|
||||||
id: request.id,
|
|
||||||
});
|
|
||||||
}, (error) => {
|
|
||||||
var _a, _b;
|
|
||||||
return (_a = this._transport) === null || _a === void 0 ? void 0 : _a.send({
|
|
||||||
jsonrpc: "2.0",
|
|
||||||
id: request.id,
|
|
||||||
error: {
|
|
||||||
code: error["code"]
|
|
||||||
? Math.floor(Number(error["code"]))
|
|
||||||
: ErrorCode.InternalError,
|
|
||||||
message: (_b = error.message) !== null && _b !== void 0 ? _b : "Internal error",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => this._onerror(new Error(`Failed to send response: ${error}`)));
|
|
||||||
}
|
|
||||||
_onprogress(notification) {
|
|
||||||
const { progress, total, progressToken } = notification.params;
|
|
||||||
const handler = this._progressHandlers.get(Number(progressToken));
|
|
||||||
if (handler === undefined) {
|
|
||||||
this._onerror(new Error(`Received a progress notification for an unknown token: ${JSON.stringify(notification)}`));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
handler({ progress, total });
|
|
||||||
}
|
|
||||||
_onresponse(response) {
|
|
||||||
const messageId = response.id;
|
|
||||||
const handler = this._responseHandlers.get(Number(messageId));
|
|
||||||
if (handler === undefined) {
|
|
||||||
this._onerror(new Error(`Received a response for an unknown message ID: ${JSON.stringify(response)}`));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._responseHandlers.delete(Number(messageId));
|
|
||||||
this._progressHandlers.delete(Number(messageId));
|
|
||||||
if ("result" in response) {
|
|
||||||
handler(response);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const error = new McpError(response.error.code, response.error.message, response.error.data);
|
|
||||||
handler(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get transport() {
|
|
||||||
return this._transport;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Closes the connection.
|
|
||||||
*/
|
|
||||||
async close() {
|
|
||||||
var _a;
|
|
||||||
await ((_a = this._transport) === null || _a === void 0 ? void 0 : _a.close());
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Sends a request and wait for a response, with optional progress notifications in the meantime (if supported by the server).
|
|
||||||
*
|
|
||||||
* Do not use this method to emit notifications! Use notification() instead.
|
|
||||||
*/
|
|
||||||
request(request, resultSchema, onprogress) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (!this._transport) {
|
|
||||||
reject(new Error("Not connected"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const messageId = this._requestMessageId++;
|
|
||||||
const jsonrpcRequest = {
|
|
||||||
...request,
|
|
||||||
jsonrpc: "2.0",
|
|
||||||
id: messageId,
|
|
||||||
};
|
|
||||||
if (onprogress) {
|
|
||||||
this._progressHandlers.set(messageId, onprogress);
|
|
||||||
jsonrpcRequest.params = {
|
|
||||||
...request.params,
|
|
||||||
_meta: { progressToken: messageId },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
this._responseHandlers.set(messageId, (response) => {
|
|
||||||
if (response instanceof Error) {
|
|
||||||
return reject(response);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const result = resultSchema.parse(response.result);
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this._transport.send(jsonrpcRequest).catch(reject);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Emits a notification, which is a one-way message that does not expect a response.
|
|
||||||
*/
|
|
||||||
async notification(notification) {
|
|
||||||
if (!this._transport) {
|
|
||||||
throw new Error("Not connected");
|
|
||||||
}
|
|
||||||
const jsonrpcNotification = {
|
|
||||||
...notification,
|
|
||||||
jsonrpc: "2.0",
|
|
||||||
};
|
|
||||||
await this._transport.send(jsonrpcNotification);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Registers a handler to invoke when this protocol object receives a request with the given method.
|
|
||||||
*
|
|
||||||
* Note that this will replace any previous request handler for the same method.
|
|
||||||
*/
|
|
||||||
setRequestHandler(requestSchema, handler) {
|
|
||||||
this._requestHandlers.set(requestSchema.shape.method.value, (request) => Promise.resolve(handler(requestSchema.parse(request))));
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Removes the request handler for the given method.
|
|
||||||
*/
|
|
||||||
removeRequestHandler(method) {
|
|
||||||
this._requestHandlers.delete(method);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Registers a handler to invoke when this protocol object receives a notification with the given method.
|
|
||||||
*
|
|
||||||
* Note that this will replace any previous notification handler for the same method.
|
|
||||||
*/
|
|
||||||
setNotificationHandler(notificationSchema, handler) {
|
|
||||||
this._notificationHandlers.set(notificationSchema.shape.method.value, (notification) => Promise.resolve(handler(notificationSchema.parse(notification))));
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Removes the notification handler for the given method.
|
|
||||||
*/
|
|
||||||
removeNotificationHandler(method) {
|
|
||||||
this._notificationHandlers.delete(method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=protocol.js.map
|
|
||||||
File diff suppressed because one or more lines are too long
13
packages/mcp-typescript/dist/shared/stdio.d.ts
vendored
13
packages/mcp-typescript/dist/shared/stdio.d.ts
vendored
@@ -1,13 +0,0 @@
|
|||||||
import { JSONRPCMessage } from "../types.js";
|
|
||||||
/**
|
|
||||||
* Buffers a continuous stdio stream into discrete JSON-RPC messages.
|
|
||||||
*/
|
|
||||||
export declare class ReadBuffer {
|
|
||||||
private _buffer?;
|
|
||||||
append(chunk: Buffer): void;
|
|
||||||
readMessage(): JSONRPCMessage | null;
|
|
||||||
clear(): void;
|
|
||||||
}
|
|
||||||
export declare function deserializeMessage(line: string): JSONRPCMessage;
|
|
||||||
export declare function serializeMessage(message: JSONRPCMessage): string;
|
|
||||||
//# sourceMappingURL=stdio.d.ts.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/shared/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAEnE;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAC,CAAS;IAEzB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI3B,WAAW,IAAI,cAAc,GAAG,IAAI;IAepC,KAAK,IAAI,IAAI;CAGd;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAE/D;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAEhE"}
|
|
||||||
31
packages/mcp-typescript/dist/shared/stdio.js
vendored
31
packages/mcp-typescript/dist/shared/stdio.js
vendored
@@ -1,31 +0,0 @@
|
|||||||
import { JSONRPCMessageSchema } from "../types.js";
|
|
||||||
/**
|
|
||||||
* Buffers a continuous stdio stream into discrete JSON-RPC messages.
|
|
||||||
*/
|
|
||||||
export class ReadBuffer {
|
|
||||||
append(chunk) {
|
|
||||||
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
||||||
}
|
|
||||||
readMessage() {
|
|
||||||
if (!this._buffer) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const index = this._buffer.indexOf("\n");
|
|
||||||
if (index === -1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const line = this._buffer.toString("utf8", 0, index);
|
|
||||||
this._buffer = this._buffer.subarray(index + 1);
|
|
||||||
return deserializeMessage(line);
|
|
||||||
}
|
|
||||||
clear() {
|
|
||||||
this._buffer = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export function deserializeMessage(line) {
|
|
||||||
return JSONRPCMessageSchema.parse(JSON.parse(line));
|
|
||||||
}
|
|
||||||
export function serializeMessage(message) {
|
|
||||||
return JSON.stringify(message) + "\n";
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=stdio.js.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/shared/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnE;;GAEG;AACH,MAAM,OAAO,UAAU;IAGrB,MAAM,CAAC,KAAa;QAClB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7E,CAAC;IAED,WAAW;QACT,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QACrD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAChD,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;IAC3B,CAAC;CACF;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAuB;IACtD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;AACxC,CAAC"}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export {};
|
|
||||||
//# sourceMappingURL=stdio.test.d.ts.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"stdio.test.d.ts","sourceRoot":"","sources":["../../src/shared/stdio.test.ts"],"names":[],"mappings":""}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import { ReadBuffer } from "./stdio.js";
|
|
||||||
const testMessage = {
|
|
||||||
jsonrpc: "2.0",
|
|
||||||
method: "foobar",
|
|
||||||
};
|
|
||||||
test("should have no messages after initialization", () => {
|
|
||||||
const readBuffer = new ReadBuffer();
|
|
||||||
expect(readBuffer.readMessage()).toBeNull();
|
|
||||||
});
|
|
||||||
test("should only yield a message after a newline", () => {
|
|
||||||
const readBuffer = new ReadBuffer();
|
|
||||||
readBuffer.append(Buffer.from(JSON.stringify(testMessage)));
|
|
||||||
expect(readBuffer.readMessage()).toBeNull();
|
|
||||||
readBuffer.append(Buffer.from("\n"));
|
|
||||||
expect(readBuffer.readMessage()).toEqual(testMessage);
|
|
||||||
expect(readBuffer.readMessage()).toBeNull();
|
|
||||||
});
|
|
||||||
test("should be reusable after clearing", () => {
|
|
||||||
const readBuffer = new ReadBuffer();
|
|
||||||
readBuffer.append(Buffer.from("foobar"));
|
|
||||||
readBuffer.clear();
|
|
||||||
expect(readBuffer.readMessage()).toBeNull();
|
|
||||||
readBuffer.append(Buffer.from(JSON.stringify(testMessage)));
|
|
||||||
readBuffer.append(Buffer.from("\n"));
|
|
||||||
expect(readBuffer.readMessage()).toEqual(testMessage);
|
|
||||||
});
|
|
||||||
//# sourceMappingURL=stdio.test.js.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"stdio.test.js","sourceRoot":"","sources":["../../src/shared/stdio.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,WAAW,GAAmB;IAClC,OAAO,EAAE,KAAK;IACd,MAAM,EAAE,QAAQ;CACjB,CAAC;AAEF,IAAI,CAAC,8CAA8C,EAAE,GAAG,EAAE;IACxD,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;IACpC,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC9C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6CAA6C,EAAE,GAAG,EAAE;IACvD,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;IAEpC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAE5C,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtD,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC9C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,mCAAmC,EAAE,GAAG,EAAE;IAC7C,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;IAEpC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IACzC,UAAU,CAAC,KAAK,EAAE,CAAC;IACnB,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAE5C,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAC5D,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC"}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import { JSONRPCMessage } from "../types.js";
|
|
||||||
/**
|
|
||||||
* Describes the minimal contract for a MCP transport that a client or server can communicate over.
|
|
||||||
*/
|
|
||||||
export interface Transport {
|
|
||||||
/**
|
|
||||||
* Starts processing messages on the transport, including any connection steps that might need to be taken.
|
|
||||||
*
|
|
||||||
* This method should only be called after callbacks are installed, or else messages may be lost.
|
|
||||||
*
|
|
||||||
* NOTE: This method should not be called explicitly when using Client, Server, or Protocol classes, as they will implicitly call start().
|
|
||||||
*/
|
|
||||||
start(): Promise<void>;
|
|
||||||
/**
|
|
||||||
* Sends a JSON-RPC message (request or response).
|
|
||||||
*/
|
|
||||||
send(message: JSONRPCMessage): Promise<void>;
|
|
||||||
/**
|
|
||||||
* Closes the connection.
|
|
||||||
*/
|
|
||||||
close(): Promise<void>;
|
|
||||||
/**
|
|
||||||
* Callback for when the connection is closed for any reason.
|
|
||||||
*
|
|
||||||
* This should be invoked when close() is called as well.
|
|
||||||
*/
|
|
||||||
onclose?: () => void;
|
|
||||||
/**
|
|
||||||
* Callback for when an error occurs.
|
|
||||||
*
|
|
||||||
* Note that errors are not necessarily fatal; they are used for reporting any kind of exceptional condition out of band.
|
|
||||||
*/
|
|
||||||
onerror?: (error: Error) => void;
|
|
||||||
/**
|
|
||||||
* Callback for when a message (request or response) is received over the connection.
|
|
||||||
*/
|
|
||||||
onmessage?: (message: JSONRPCMessage) => void;
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=transport.d.ts.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/shared/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;;OAMG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;CAC/C"}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export {};
|
|
||||||
//# sourceMappingURL=transport.js.map
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/shared/transport.ts"],"names":[],"mappings":""}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user