Compare commits
1 Commits
0.2.2
...
ashwin/res
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cd1dc7dd4 |
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -1 +1,2 @@
|
|||||||
package-lock.json linguist-generated=true
|
yarn.lock linguist-generated=true
|
||||||
|
packages/**/* linguist-generated=true
|
||||||
|
|||||||
52
.github/workflows/main.yml
vendored
52
.github/workflows/main.yml
vendored
@@ -1,52 +0,0 @@
|
|||||||
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 }}
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,4 +3,3 @@ node_modules
|
|||||||
server/build
|
server/build
|
||||||
client/dist
|
client/dist
|
||||||
client/tsconfig.app.tsbuildinfo
|
client/tsconfig.app.tsbuildinfo
|
||||||
client/tsconfig.node.tsbuildinfo
|
|
||||||
|
|||||||
2
.npmrc
2
.npmrc
@@ -1,2 +0,0 @@
|
|||||||
registry="https://registry.npmjs.org/"
|
|
||||||
@modelcontextprotocol:registry="https://registry.npmjs.org/"
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# 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
21
LICENSE
@@ -1,21 +0,0 @@
|
|||||||
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,18 +2,23 @@
|
|||||||
|
|
||||||
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.
|
||||||
|
|
||||||
It can be run easily from `npx`. For example, in a folder where there's a built JavaScript server at `build/index.js`:
|
Setup:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
npx @modelcontextprotocol/inspector build/index.js
|
yarn
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also pass arguments along to the server:
|
You can run it in dev mode via:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
npx @modelcontextprotocol/inspector build/index.js arg1 arg2 ...
|
yarn dev
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
This will start both the client and server.
|
||||||
|
|
||||||
This project is licensed under the MIT License—see the [LICENSE](LICENSE) file for details.
|
To run in production mode:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn build
|
||||||
|
yarn start
|
||||||
|
```
|
||||||
|
|||||||
14
SECURITY.md
14
SECURITY.md
@@ -1,14 +0,0 @@
|
|||||||
# 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
65
bin/cli.js
@@ -1,65 +0,0 @@
|
|||||||
#!/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);
|
|
||||||
});
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#!/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, () => {});
|
|
||||||
@@ -17,4 +17,4 @@
|
|||||||
"lib": "@/lib",
|
"lib": "@/lib",
|
||||||
"hooks": "@/hooks"
|
"hooks": "@/hooks"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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="/mcp.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>MCP Inspector</title>
|
<title>Vite + React + TS</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -1,19 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "@modelcontextprotocol/inspector-client",
|
"name": "client",
|
||||||
"version": "0.2.2",
|
"private": true,
|
||||||
"description": "Client-side application for the Model Context Protocol inspector",
|
"version": "0.0.0",
|
||||||
"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",
|
||||||
@@ -21,7 +10,6 @@
|
|||||||
"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",
|
||||||
@@ -30,20 +18,17 @@
|
|||||||
"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"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.11.1",
|
"@eslint/js": "^9.11.1",
|
||||||
"@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: {},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
<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>
|
|
||||||
|
Before Width: | Height: | Size: 973 B |
1
client/public/vite.svg
Normal file
1
client/public/vite.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<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>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -1,5 +1,8 @@
|
|||||||
#root {
|
#root {
|
||||||
|
max-width: 1280px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
|
|||||||
@@ -1,285 +1,98 @@
|
|||||||
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
import { Client } from "mcp-typescript/client/index.js";
|
||||||
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
import { SSEClientTransport } from "mcp-typescript/client/sse.js";
|
||||||
import {
|
import {
|
||||||
ClientNotification,
|
|
||||||
ClientRequest,
|
|
||||||
CompatibilityCallToolResult,
|
|
||||||
CompatibilityCallToolResultSchema,
|
|
||||||
CreateMessageRequestSchema,
|
|
||||||
CreateMessageResult,
|
|
||||||
EmptyResultSchema,
|
|
||||||
GetPromptResultSchema,
|
|
||||||
ListPromptsResultSchema,
|
|
||||||
ListResourcesResultSchema,
|
ListResourcesResultSchema,
|
||||||
ListResourceTemplatesResultSchema,
|
GetPromptResultSchema,
|
||||||
ListRootsRequestSchema,
|
|
||||||
ListToolsResultSchema,
|
ListToolsResultSchema,
|
||||||
ProgressNotificationSchema,
|
|
||||||
ReadResourceResultSchema,
|
ReadResourceResultSchema,
|
||||||
Request,
|
CallToolResultSchema,
|
||||||
|
ListPromptsResultSchema,
|
||||||
Resource,
|
Resource,
|
||||||
ResourceTemplate,
|
|
||||||
Result,
|
|
||||||
Root,
|
|
||||||
ServerNotification,
|
|
||||||
Tool,
|
Tool,
|
||||||
} from "@modelcontextprotocol/sdk/types.js";
|
ClientRequest,
|
||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
} from "mcp-typescript/types.js";
|
||||||
|
import { useState } from "react";
|
||||||
import {
|
|
||||||
Notification,
|
|
||||||
StdErrNotification,
|
|
||||||
StdErrNotificationSchema,
|
|
||||||
} from "./lib/notificationTypes";
|
|
||||||
|
|
||||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
||||||
import {
|
import {
|
||||||
|
Send,
|
||||||
Bell,
|
Bell,
|
||||||
|
Terminal,
|
||||||
Files,
|
Files,
|
||||||
FolderTree,
|
|
||||||
Hammer,
|
|
||||||
Hash,
|
|
||||||
MessageSquare,
|
MessageSquare,
|
||||||
|
Hammer,
|
||||||
|
Play,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
|
||||||
import { toast } from "react-toastify";
|
|
||||||
import { ZodType } from "zod";
|
|
||||||
import "./App.css";
|
|
||||||
import ConsoleTab from "./components/ConsoleTab";
|
import ConsoleTab from "./components/ConsoleTab";
|
||||||
import HistoryAndNotifications from "./components/History";
|
|
||||||
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 Sidebar from "./components/Sidebar";
|
||||||
|
import RequestsTab from "./components/RequestsTabs";
|
||||||
|
import ResourcesTab from "./components/ResourcesTab";
|
||||||
|
import NotificationsTab from "./components/NotificationsTab";
|
||||||
|
import PromptsTab, { Prompt } from "./components/PromptsTab";
|
||||||
import ToolsTab from "./components/ToolsTab";
|
import ToolsTab from "./components/ToolsTab";
|
||||||
|
import History from "./components/History";
|
||||||
const DEFAULT_REQUEST_TIMEOUT_MSEC = 10000;
|
import { AnyZodObject } from "node_modules/zod/lib";
|
||||||
|
|
||||||
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] =
|
const [toolResult, setToolResult] = useState<string>("");
|
||||||
useState<CompatibilityCallToolResult | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [errors, setErrors] = useState<Record<string, string | null>>({
|
const [command, setCommand] = useState<string>(
|
||||||
resources: null,
|
"/Users/ashwin/.nvm/versions/node/v18.20.4/bin/node",
|
||||||
prompts: null,
|
);
|
||||||
tools: null,
|
const [args, setArgs] = useState<string>(
|
||||||
});
|
"/Users/ashwin/code/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 [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,
|
||||||
);
|
);
|
||||||
const [selectedPrompt, setSelectedPrompt] = useState<Prompt | null>(null);
|
const [selectedPrompt, setSelectedPrompt] = useState<Prompt | null>(null);
|
||||||
const [selectedTool, setSelectedTool] = useState<Tool | null>(null);
|
const [selectedTool, setSelectedTool] = useState<Tool | null>(null);
|
||||||
const [nextResourceCursor, setNextResourceCursor] = useState<
|
|
||||||
string | undefined
|
|
||||||
>();
|
|
||||||
const [nextResourceTemplateCursor, setNextResourceTemplateCursor] = useState<
|
|
||||||
string | undefined
|
|
||||||
>();
|
|
||||||
const [nextPromptCursor, setNextPromptCursor] = useState<
|
|
||||||
string | undefined
|
|
||||||
>();
|
|
||||||
const [nextToolCursor, setNextToolCursor] = useState<string | undefined>();
|
|
||||||
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 handleDragStart = useCallback(
|
const pushHistory = (request: object, response: object) => {
|
||||||
(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 clearError = (tabKey: keyof typeof errors) => {
|
const makeRequest = async <T extends AnyZodObject>(
|
||||||
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 abortController = new AbortController();
|
const response = await mcpClient.request(request, schema);
|
||||||
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) {
|
||||||
const errorString = (e as Error).message ?? String(e);
|
setError((e as Error).message);
|
||||||
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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -288,40 +101,21 @@ const App = () => {
|
|||||||
const response = await makeRequest(
|
const response = await makeRequest(
|
||||||
{
|
{
|
||||||
method: "resources/list" as const,
|
method: "resources/list" as const,
|
||||||
params: nextResourceCursor ? { cursor: nextResourceCursor } : {},
|
|
||||||
},
|
},
|
||||||
ListResourcesResultSchema,
|
ListResourcesResultSchema,
|
||||||
"resources",
|
|
||||||
);
|
);
|
||||||
setResources(resources.concat(response.resources ?? []));
|
if (response.resources) {
|
||||||
setNextResourceCursor(response.nextCursor);
|
setResources(response.resources);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const listResourceTemplates = async () => {
|
const readResource = async (uri: URL) => {
|
||||||
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 response = await makeRequest(
|
const response = await makeRequest(
|
||||||
{
|
{
|
||||||
method: "resources/read" as const,
|
method: "resources/read" as const,
|
||||||
params: { uri },
|
params: { uri },
|
||||||
},
|
},
|
||||||
ReadResourceResultSchema,
|
ReadResourceResultSchema,
|
||||||
"resources",
|
|
||||||
);
|
);
|
||||||
setResourceContent(JSON.stringify(response, null, 2));
|
setResourceContent(JSON.stringify(response, null, 2));
|
||||||
};
|
};
|
||||||
@@ -330,13 +124,10 @@ const App = () => {
|
|||||||
const response = await makeRequest(
|
const response = await makeRequest(
|
||||||
{
|
{
|
||||||
method: "prompts/list" as const,
|
method: "prompts/list" as const,
|
||||||
params: nextPromptCursor ? { cursor: nextPromptCursor } : {},
|
|
||||||
},
|
},
|
||||||
ListPromptsResultSchema,
|
ListPromptsResultSchema,
|
||||||
"prompts",
|
|
||||||
);
|
);
|
||||||
setPrompts(response.prompts);
|
setPrompts(response.prompts);
|
||||||
setNextPromptCursor(response.nextCursor);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPrompt = async (name: string, args: Record<string, string> = {}) => {
|
const getPrompt = async (name: string, args: Record<string, string> = {}) => {
|
||||||
@@ -346,7 +137,6 @@ 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));
|
||||||
};
|
};
|
||||||
@@ -355,102 +145,44 @@ const App = () => {
|
|||||||
const response = await makeRequest(
|
const response = await makeRequest(
|
||||||
{
|
{
|
||||||
method: "tools/list" as const,
|
method: "tools/list" as const,
|
||||||
params: nextToolCursor ? { cursor: nextToolCursor } : {},
|
|
||||||
},
|
},
|
||||||
ListToolsResultSchema,
|
ListToolsResultSchema,
|
||||||
"tools",
|
|
||||||
);
|
);
|
||||||
setTools(response.tools);
|
setTools(response.tools);
|
||||||
setNextToolCursor(response.nextCursor);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const callTool = async (name: string, params: Record<string, unknown>) => {
|
const callTool = async (name: string, params: Record<string, unknown>) => {
|
||||||
const response = await makeRequest(
|
const response = await makeRequest(
|
||||||
{
|
{
|
||||||
method: "tools/call" as const,
|
method: "tools/call" as const,
|
||||||
params: {
|
params: { name, arguments: params },
|
||||||
name,
|
|
||||||
arguments: params,
|
|
||||||
_meta: {
|
|
||||||
progressToken: progressTokenRef.current++,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
CompatibilityCallToolResultSchema,
|
CallToolResultSchema,
|
||||||
"tools",
|
|
||||||
);
|
);
|
||||||
setToolResult(response);
|
setToolResult(JSON.stringify(response.toolResult, null, 2));
|
||||||
};
|
|
||||||
|
|
||||||
const handleRootsChange = async () => {
|
|
||||||
await sendNotification({ method: "notifications/roots/list_changed" });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const connectMcpServer = async () => {
|
const connectMcpServer = async () => {
|
||||||
try {
|
try {
|
||||||
const client = new Client<Request, Notification, Result>(
|
const client = new Client({
|
||||||
{
|
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 clientTransport = new SSEClientTransport();
|
||||||
const backendUrl = new URL("http://localhost:3000/sse");
|
const backendUrl = new URL("http://localhost:3000/sse");
|
||||||
|
|
||||||
backendUrl.searchParams.append("transportType", transportType);
|
backendUrl.searchParams.append("transportType", transportType);
|
||||||
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);
|
await clientTransport.connect(backendUrl);
|
||||||
client.setNotificationHandler(
|
|
||||||
ProgressNotificationSchema,
|
|
||||||
(notification) => {
|
|
||||||
setNotifications((prevNotifications) => [
|
|
||||||
...prevNotifications,
|
|
||||||
notification,
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
client.setNotificationHandler(
|
|
||||||
StdErrNotificationSchema,
|
|
||||||
(notification) => {
|
|
||||||
setStdErrNotifications((prevErrorNotifications) => [
|
|
||||||
...prevErrorNotifications,
|
|
||||||
notification,
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
await client.connect(clientTransport);
|
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) {
|
||||||
@@ -460,174 +192,131 @@ const App = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen bg-background">
|
<div className="flex h-screen bg-gray-100">
|
||||||
<Sidebar
|
<Sidebar connectionStatus={connectionStatus} />
|
||||||
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">
|
||||||
<div className="flex-1 overflow-auto">
|
<h1 className="text-2xl font-bold p-4">MCP Inspector</h1>
|
||||||
{mcpClient ? (
|
<div className="flex-1 overflow-auto flex">
|
||||||
<Tabs defaultValue="resources" className="w-full p-4">
|
<div className="flex-1">
|
||||||
<TabsList className="mb-4 p-0">
|
<div className="p-4 bg-white shadow-md m-4 rounded-md">
|
||||||
<TabsTrigger value="resources">
|
<h2 className="text-lg font-semibold mb-2">Connect MCP Server</h2>
|
||||||
<Files className="w-4 h-4 mr-2" />
|
<div className="flex space-x-2 mb-2">
|
||||||
Resources
|
<Select
|
||||||
</TabsTrigger>
|
value={transportType}
|
||||||
<TabsTrigger value="prompts">
|
onValueChange={(value: "stdio" | "sse") =>
|
||||||
<MessageSquare className="w-4 h-4 mr-2" />
|
setTransportType(value)
|
||||||
Prompts
|
}
|
||||||
</TabsTrigger>
|
>
|
||||||
<TabsTrigger value="tools">
|
<SelectTrigger className="w-[180px]">
|
||||||
<Hammer className="w-4 h-4 mr-2" />
|
<SelectValue placeholder="Select transport type" />
|
||||||
Tools
|
</SelectTrigger>
|
||||||
</TabsTrigger>
|
<SelectContent>
|
||||||
<TabsTrigger value="ping">
|
<SelectItem value="stdio">STDIO</SelectItem>
|
||||||
<Bell className="w-4 h-4 mr-2" />
|
<SelectItem value="sse">SSE</SelectItem>
|
||||||
Ping
|
</SelectContent>
|
||||||
</TabsTrigger>
|
</Select>
|
||||||
<TabsTrigger value="sampling" className="relative">
|
{transportType === "stdio" ? (
|
||||||
<Hash className="w-4 h-4 mr-2" />
|
<>
|
||||||
Sampling
|
<Input
|
||||||
{pendingSampleRequests.length > 0 && (
|
placeholder="Command"
|
||||||
<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">
|
value={command}
|
||||||
{pendingSampleRequests.length}
|
onChange={(e) => setCommand(e.target.value)}
|
||||||
</span>
|
/>
|
||||||
)}
|
<Input
|
||||||
</TabsTrigger>
|
placeholder="Arguments (space-separated)"
|
||||||
<TabsTrigger value="roots">
|
value={args}
|
||||||
<FolderTree className="w-4 h-4 mr-2" />
|
onChange={(e) => setArgs(e.target.value)}
|
||||||
Roots
|
/>
|
||||||
</TabsTrigger>
|
</>
|
||||||
</TabsList>
|
) : (
|
||||||
|
<Input
|
||||||
<div className="w-full">
|
placeholder="URL"
|
||||||
<ResourcesTab
|
value={url}
|
||||||
resources={resources}
|
onChange={(e) => setUrl(e.target.value)}
|
||||||
resourceTemplates={resourceTemplates}
|
/>
|
||||||
listResources={() => {
|
)}
|
||||||
clearError("resources");
|
<Button onClick={connectMcpServer}>
|
||||||
listResources();
|
<Play className="w-4 h-4 mr-2" />
|
||||||
}}
|
Connect
|
||||||
listResourceTemplates={() => {
|
</Button>
|
||||||
clearError("resources");
|
|
||||||
listResourceTemplates();
|
|
||||||
}}
|
|
||||||
readResource={(uri) => {
|
|
||||||
clearError("resources");
|
|
||||||
readResource(uri);
|
|
||||||
}}
|
|
||||||
selectedResource={selectedResource}
|
|
||||||
setSelectedResource={(resource) => {
|
|
||||||
clearError("resources");
|
|
||||||
setSelectedResource(resource);
|
|
||||||
}}
|
|
||||||
resourceContent={resourceContent}
|
|
||||||
nextCursor={nextResourceCursor}
|
|
||||||
nextTemplateCursor={nextResourceTemplateCursor}
|
|
||||||
error={errors.resources}
|
|
||||||
/>
|
|
||||||
<PromptsTab
|
|
||||||
prompts={prompts}
|
|
||||||
listPrompts={() => {
|
|
||||||
clearError("prompts");
|
|
||||||
listPrompts();
|
|
||||||
}}
|
|
||||||
getPrompt={(name, args) => {
|
|
||||||
clearError("prompts");
|
|
||||||
getPrompt(name, args);
|
|
||||||
}}
|
|
||||||
selectedPrompt={selectedPrompt}
|
|
||||||
setSelectedPrompt={(prompt) => {
|
|
||||||
clearError("prompts");
|
|
||||||
setSelectedPrompt(prompt);
|
|
||||||
}}
|
|
||||||
promptContent={promptContent}
|
|
||||||
nextCursor={nextPromptCursor}
|
|
||||||
error={errors.prompts}
|
|
||||||
/>
|
|
||||||
<ToolsTab
|
|
||||||
tools={tools}
|
|
||||||
listTools={() => {
|
|
||||||
clearError("tools");
|
|
||||||
listTools();
|
|
||||||
}}
|
|
||||||
callTool={(name, params) => {
|
|
||||||
clearError("tools");
|
|
||||||
callTool(name, params);
|
|
||||||
}}
|
|
||||||
selectedTool={selectedTool}
|
|
||||||
setSelectedTool={(tool) => {
|
|
||||||
clearError("tools");
|
|
||||||
setSelectedTool(tool);
|
|
||||||
setToolResult(null);
|
|
||||||
}}
|
|
||||||
toolResult={toolResult}
|
|
||||||
nextCursor={nextToolCursor}
|
|
||||||
error={errors.tools}
|
|
||||||
/>
|
|
||||||
<ConsoleTab />
|
|
||||||
<PingTab
|
|
||||||
onPingClick={() => {
|
|
||||||
void makeRequest(
|
|
||||||
{
|
|
||||||
method: "ping" as const,
|
|
||||||
},
|
|
||||||
EmptyResultSchema,
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<SamplingTab
|
|
||||||
pendingRequests={pendingSampleRequests}
|
|
||||||
onApprove={handleApproveSampling}
|
|
||||||
onReject={handleRejectSampling}
|
|
||||||
/>
|
|
||||||
<RootsTab
|
|
||||||
roots={roots}
|
|
||||||
setRoots={setRoots}
|
|
||||||
onRootsChange={handleRootsChange}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</Tabs>
|
|
||||||
) : (
|
|
||||||
<div className="flex items-center justify-center h-full">
|
|
||||||
<p className="text-lg text-gray-500">
|
|
||||||
Connect to an MCP server to start inspecting
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
{mcpClient ? (
|
||||||
</div>
|
<Tabs defaultValue="resources" className="w-full p-4">
|
||||||
<div
|
<TabsList className="mb-4 p-0">
|
||||||
className="relative border-t border-border"
|
<TabsTrigger value="resources">
|
||||||
style={{
|
<Files className="w-4 h-4 mr-2" />
|
||||||
height: `${historyPaneHeight}px`,
|
Resources
|
||||||
}}
|
</TabsTrigger>
|
||||||
>
|
<TabsTrigger value="prompts">
|
||||||
<div
|
<MessageSquare className="w-4 h-4 mr-2" />
|
||||||
className="absolute w-full h-4 -top-2 cursor-row-resize flex items-center justify-center hover:bg-accent/50"
|
Prompts
|
||||||
onMouseDown={handleDragStart}
|
</TabsTrigger>
|
||||||
>
|
<TabsTrigger value="requests" disabled>
|
||||||
<div className="w-8 h-1 rounded-full bg-border" />
|
<Send className="w-4 h-4 mr-2" />
|
||||||
</div>
|
Requests
|
||||||
<div className="h-full overflow-auto">
|
</TabsTrigger>
|
||||||
<HistoryAndNotifications
|
<TabsTrigger value="notifications" disabled>
|
||||||
requestHistory={requestHistory}
|
<Bell className="w-4 h-4 mr-2" />
|
||||||
serverNotifications={notifications}
|
Notifications
|
||||||
/>
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="tools">
|
||||||
|
<Hammer className="w-4 h-4 mr-2" />
|
||||||
|
Tools
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="console" disabled>
|
||||||
|
<Terminal className="w-4 h-4 mr-2" />
|
||||||
|
Console
|
||||||
|
</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<div className="w-full">
|
||||||
|
<ResourcesTab
|
||||||
|
resources={resources}
|
||||||
|
listResources={listResources}
|
||||||
|
readResource={readResource}
|
||||||
|
selectedResource={selectedResource}
|
||||||
|
setSelectedResource={setSelectedResource}
|
||||||
|
resourceContent={resourceContent}
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
<NotificationsTab />
|
||||||
|
<PromptsTab
|
||||||
|
prompts={prompts}
|
||||||
|
listPrompts={listPrompts}
|
||||||
|
getPrompt={getPrompt}
|
||||||
|
selectedPrompt={selectedPrompt}
|
||||||
|
setSelectedPrompt={setSelectedPrompt}
|
||||||
|
promptContent={promptContent}
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
<RequestsTab />
|
||||||
|
<ToolsTab
|
||||||
|
tools={tools}
|
||||||
|
listTools={listTools}
|
||||||
|
callTool={callTool}
|
||||||
|
selectedTool={selectedTool}
|
||||||
|
setSelectedTool={(tool) => {
|
||||||
|
setSelectedTool(tool);
|
||||||
|
setToolResult("");
|
||||||
|
}}
|
||||||
|
toolResult={toolResult}
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
<ConsoleTab />
|
||||||
|
</div>
|
||||||
|
</Tabs>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center justify-center h-full">
|
||||||
|
<p className="text-lg text-gray-500">
|
||||||
|
Connect to an MCP server to start inspecting
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<History requestHistory={requestHistory} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
1
client/src/assets/react.svg
Normal file
1
client/src/assets/react.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<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>
|
||||||
|
After Width: | Height: | Size: 4.0 KiB |
@@ -1,163 +1,94 @@
|
|||||||
import { ServerNotification } from "@modelcontextprotocol/sdk/types.js";
|
|
||||||
import { Copy } from "lucide-react";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { Copy } from "lucide-react";
|
||||||
|
|
||||||
const HistoryAndNotifications = ({
|
const History = ({
|
||||||
requestHistory,
|
requestHistory,
|
||||||
serverNotifications,
|
|
||||||
}: {
|
}: {
|
||||||
requestHistory: Array<{ request: string; response?: string }>;
|
requestHistory: Array<{ request: string; response: string | null }>;
|
||||||
serverNotifications: ServerNotification[];
|
|
||||||
}) => {
|
}) => {
|
||||||
const [expandedRequests, setExpandedRequests] = useState<{
|
const [expandedRequests, setExpandedRequests] = useState<{
|
||||||
[key: number]: boolean;
|
[key: number]: boolean;
|
||||||
}>({});
|
}>({});
|
||||||
const [expandedNotifications, setExpandedNotifications] = useState<{
|
|
||||||
[key: number]: boolean;
|
|
||||||
}>({});
|
|
||||||
|
|
||||||
const toggleRequestExpansion = (index: number) => {
|
const toggleRequestExpansion = (index: number) => {
|
||||||
setExpandedRequests((prev) => ({ ...prev, [index]: !prev[index] }));
|
setExpandedRequests((prev) => ({ ...prev, [index]: !prev[index] }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleNotificationExpansion = (index: number) => {
|
|
||||||
setExpandedNotifications((prev) => ({ ...prev, [index]: !prev[index] }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const copyToClipboard = (text: string) => {
|
const copyToClipboard = (text: string) => {
|
||||||
navigator.clipboard.writeText(text);
|
navigator.clipboard.writeText(text);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-card overflow-hidden flex h-full">
|
<div className="w-64 bg-white shadow-md p-4 overflow-y-auto">
|
||||||
<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>
|
<ul className="space-y-3">
|
||||||
{requestHistory.length === 0 ? (
|
{requestHistory
|
||||||
<p className="text-sm text-gray-500 italic">No history yet</p>
|
.slice()
|
||||||
) : (
|
.reverse()
|
||||||
<ul className="space-y-3">
|
.map((request, index) => (
|
||||||
{requestHistory
|
<li
|
||||||
.slice()
|
key={index}
|
||||||
.reverse()
|
className="text-sm text-gray-600 bg-gray-100 p-2 rounded"
|
||||||
.map((request, index) => (
|
>
|
||||||
<li
|
<div
|
||||||
key={index}
|
className="flex justify-between items-center cursor-pointer"
|
||||||
className="text-sm text-foreground bg-secondary p-2 rounded"
|
onClick={() =>
|
||||||
>
|
toggleRequestExpansion(requestHistory.length - 1 - index)
|
||||||
<div
|
}
|
||||||
className="flex justify-between items-center cursor-pointer"
|
>
|
||||||
onClick={() =>
|
<span className="font-mono">
|
||||||
toggleRequestExpansion(requestHistory.length - 1 - index)
|
{requestHistory.length - index}.{" "}
|
||||||
}
|
{JSON.parse(request.request).method}
|
||||||
>
|
</span>
|
||||||
<span className="font-mono">
|
<span>
|
||||||
{requestHistory.length - index}.{" "}
|
{expandedRequests[requestHistory.length - 1 - index]
|
||||||
{JSON.parse(request.request).method}
|
? "▼"
|
||||||
</span>
|
: "▶"}
|
||||||
<span>
|
</span>
|
||||||
{expandedRequests[requestHistory.length - 1 - index]
|
</div>
|
||||||
? "▼"
|
{expandedRequests[requestHistory.length - 1 - index] && (
|
||||||
: "▶"}
|
<>
|
||||||
</span>
|
<div className="mt-2">
|
||||||
|
<div className="flex justify-between items-center mb-1">
|
||||||
|
<span className="font-semibold text-blue-600">
|
||||||
|
Request:
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
onClick={() => copyToClipboard(request.request)}
|
||||||
|
className="text-blue-500 hover:text-blue-700"
|
||||||
|
>
|
||||||
|
<Copy size={16} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<pre className="whitespace-pre-wrap break-words bg-blue-50 p-2 rounded">
|
||||||
|
{JSON.stringify(JSON.parse(request.request), null, 2)}
|
||||||
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
{expandedRequests[requestHistory.length - 1 - index] && (
|
{request.response && (
|
||||||
<>
|
|
||||||
<div className="mt-2">
|
|
||||||
<div className="flex justify-between items-center mb-1">
|
|
||||||
<span className="font-semibold text-blue-600">
|
|
||||||
Request:
|
|
||||||
</span>
|
|
||||||
<button
|
|
||||||
onClick={() => copyToClipboard(request.request)}
|
|
||||||
className="text-blue-500 hover:text-blue-700"
|
|
||||||
>
|
|
||||||
<Copy size={16} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<pre className="whitespace-pre-wrap break-words bg-background p-2 rounded">
|
|
||||||
{JSON.stringify(JSON.parse(request.request), null, 2)}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
{request.response && (
|
|
||||||
<div className="mt-2">
|
|
||||||
<div className="flex justify-between items-center mb-1">
|
|
||||||
<span className="font-semibold text-green-600">
|
|
||||||
Response:
|
|
||||||
</span>
|
|
||||||
<button
|
|
||||||
onClick={() => copyToClipboard(request.response!)}
|
|
||||||
className="text-blue-500 hover:text-blue-700"
|
|
||||||
>
|
|
||||||
<Copy size={16} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<pre className="whitespace-pre-wrap break-words bg-background p-2 rounded">
|
|
||||||
{JSON.stringify(
|
|
||||||
JSON.parse(request.response),
|
|
||||||
null,
|
|
||||||
2,
|
|
||||||
)}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="flex-1 overflow-y-auto p-4">
|
|
||||||
<h2 className="text-lg font-semibold mb-4">Server Notifications</h2>
|
|
||||||
{serverNotifications.length === 0 ? (
|
|
||||||
<p className="text-sm text-gray-500 italic">No notifications yet</p>
|
|
||||||
) : (
|
|
||||||
<ul className="space-y-3">
|
|
||||||
{serverNotifications
|
|
||||||
.slice()
|
|
||||||
.reverse()
|
|
||||||
.map((notification, index) => (
|
|
||||||
<li
|
|
||||||
key={index}
|
|
||||||
className="text-sm text-foreground bg-secondary p-2 rounded"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="flex justify-between items-center cursor-pointer"
|
|
||||||
onClick={() => toggleNotificationExpansion(index)}
|
|
||||||
>
|
|
||||||
<span className="font-mono">
|
|
||||||
{serverNotifications.length - index}.{" "}
|
|
||||||
{notification.method}
|
|
||||||
</span>
|
|
||||||
<span>{expandedNotifications[index] ? "▼" : "▶"}</span>
|
|
||||||
</div>
|
|
||||||
{expandedNotifications[index] && (
|
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<div className="flex justify-between items-center mb-1">
|
<div className="flex justify-between items-center mb-1">
|
||||||
<span className="font-semibold text-purple-600">
|
<span className="font-semibold text-green-600">
|
||||||
Details:
|
Response:
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
onClick={() =>
|
onClick={() => copyToClipboard(request.response!)}
|
||||||
copyToClipboard(JSON.stringify(notification))
|
|
||||||
}
|
|
||||||
className="text-blue-500 hover:text-blue-700"
|
className="text-blue-500 hover:text-blue-700"
|
||||||
>
|
>
|
||||||
<Copy size={16} />
|
<Copy size={16} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<pre className="whitespace-pre-wrap break-words bg-background p-2 rounded">
|
<pre className="whitespace-pre-wrap break-words bg-green-50 p-2 rounded">
|
||||||
{JSON.stringify(notification, null, 2)}
|
{JSON.stringify(JSON.parse(request.response), null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</li>
|
</>
|
||||||
))}
|
)}
|
||||||
</ul>
|
</li>
|
||||||
)}
|
))}
|
||||||
</div>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default HistoryAndNotifications;
|
export default History;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ type ListPaneProps<T> = {
|
|||||||
renderItem: (item: T) => React.ReactNode;
|
renderItem: (item: T) => React.ReactNode;
|
||||||
title: string;
|
title: string;
|
||||||
buttonText: string;
|
buttonText: string;
|
||||||
isButtonDisabled?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ListPane = <T extends object>({
|
const ListPane = <T extends object>({
|
||||||
@@ -17,26 +16,20 @@ const ListPane = <T extends object>({
|
|||||||
renderItem,
|
renderItem,
|
||||||
title,
|
title,
|
||||||
buttonText,
|
buttonText,
|
||||||
isButtonDisabled,
|
|
||||||
}: ListPaneProps<T>) => (
|
}: ListPaneProps<T>) => (
|
||||||
<div className="bg-card rounded-lg shadow">
|
<div className="bg-white rounded-lg shadow">
|
||||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
<div className="p-4 border-b border-gray-200">
|
||||||
<h3 className="font-semibold dark:text-white">{title}</h3>
|
<h3 className="font-semibold">{title}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<Button
|
<Button variant="outline" className="w-full mb-4" onClick={listItems}>
|
||||||
variant="outline"
|
|
||||||
className="w-full mb-4"
|
|
||||||
onClick={listItems}
|
|
||||||
disabled={isButtonDisabled}
|
|
||||||
>
|
|
||||||
{buttonText}
|
{buttonText}
|
||||||
</Button>
|
</Button>
|
||||||
<div className="space-y-2 overflow-y-auto max-h-96">
|
<div className="space-y-2">
|
||||||
{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 dark:hover:bg-gray-700 cursor-pointer"
|
className="flex items-center p-2 rounded hover:bg-gray-50 cursor-pointer"
|
||||||
onClick={() => setSelectedItem(item)}
|
onClick={() => setSelectedItem(item)}
|
||||||
>
|
>
|
||||||
{renderItem(item)}
|
{renderItem(item)}
|
||||||
|
|||||||
33
client/src/components/NotificationsTab.tsx
Normal file
33
client/src/components/NotificationsTab.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { Bell } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import { TabsContent } from "@/components/ui/tabs";
|
||||||
|
|
||||||
|
const NotificationsTab = () => (
|
||||||
|
<TabsContent value="notifications" 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="Notification method" />
|
||||||
|
<Button>
|
||||||
|
<Bell className="w-4 h-4 mr-2" />
|
||||||
|
Send
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Textarea
|
||||||
|
placeholder="Notification parameters (JSON)"
|
||||||
|
className="h-64 font-mono"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="bg-white rounded-lg shadow p-4">
|
||||||
|
<h3 className="font-semibold mb-4">Recent Notifications</h3>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{/* Notification history would go here */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default NotificationsTab;
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import { TabsContent } from "@/components/ui/tabs";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
|
|
||||||
const PingTab = ({ onPingClick }: { onPingClick: () => void }) => {
|
|
||||||
return (
|
|
||||||
<TabsContent value="ping" className="grid grid-cols-2 gap-4">
|
|
||||||
<div className="col-span-2 flex justify-center items-center">
|
|
||||||
<Button
|
|
||||||
onClick={onPingClick}
|
|
||||||
className="bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white font-bold py-6 px-12 rounded-full shadow-lg transform transition duration-300 hover:scale-110 focus:outline-none focus:ring-4 focus:ring-purple-300 animate-pulse"
|
|
||||||
>
|
|
||||||
<span className="text-3xl mr-2">🚀</span>
|
|
||||||
MEGA PING
|
|
||||||
<span className="text-3xl ml-2">💥</span>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</TabsContent>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default PingTab;
|
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
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 { AlertCircle } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
|
import { TabsContent } from "@/components/ui/tabs";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
import ListPane from "./ListPane";
|
import ListPane from "./ListPane";
|
||||||
|
|
||||||
export type Prompt = {
|
export type Prompt = {
|
||||||
@@ -26,7 +25,6 @@ const PromptsTab = ({
|
|||||||
selectedPrompt,
|
selectedPrompt,
|
||||||
setSelectedPrompt,
|
setSelectedPrompt,
|
||||||
promptContent,
|
promptContent,
|
||||||
nextCursor,
|
|
||||||
error,
|
error,
|
||||||
}: {
|
}: {
|
||||||
prompts: Prompt[];
|
prompts: Prompt[];
|
||||||
@@ -35,7 +33,6 @@ const PromptsTab = ({
|
|||||||
selectedPrompt: Prompt | null;
|
selectedPrompt: Prompt | null;
|
||||||
setSelectedPrompt: (prompt: Prompt) => void;
|
setSelectedPrompt: (prompt: Prompt) => void;
|
||||||
promptContent: string;
|
promptContent: string;
|
||||||
nextCursor: ListPromptsResult["nextCursor"];
|
|
||||||
error: string | null;
|
error: string | null;
|
||||||
}) => {
|
}) => {
|
||||||
const [promptArgs, setPromptArgs] = useState<Record<string, string>>({});
|
const [promptArgs, setPromptArgs] = useState<Record<string, string>>({});
|
||||||
@@ -66,11 +63,10 @@ const PromptsTab = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
title="Prompts"
|
title="Prompts"
|
||||||
buttonText={nextCursor ? "List More Prompts" : "List Prompts"}
|
buttonText="List Prompts"
|
||||||
isButtonDisabled={!nextCursor && prompts.length > 0}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="bg-card rounded-lg shadow">
|
<div className="bg-white 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"}
|
||||||
|
|||||||
33
client/src/components/RequestsTabs.tsx
Normal file
33
client/src/components/RequestsTabs.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
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,199 +1,85 @@
|
|||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
import { FileText, ChevronRight, AlertCircle, RefreshCw } from "lucide-react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
import { TabsContent } from "@/components/ui/tabs";
|
import { TabsContent } from "@/components/ui/tabs";
|
||||||
import {
|
import { Resource } from "mcp-typescript/types.js";
|
||||||
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,
|
|
||||||
nextTemplateCursor,
|
|
||||||
error,
|
error,
|
||||||
}: {
|
}: {
|
||||||
resources: Resource[];
|
resources: Resource[];
|
||||||
resourceTemplates: ResourceTemplate[];
|
|
||||||
listResources: () => void;
|
listResources: () => void;
|
||||||
listResourceTemplates: () => void;
|
readResource: (uri: URL) => void;
|
||||||
readResource: (uri: string) => void;
|
|
||||||
selectedResource: Resource | null;
|
selectedResource: Resource | null;
|
||||||
setSelectedResource: (resource: Resource | null) => void;
|
setSelectedResource: (resource: Resource) => void;
|
||||||
resourceContent: string;
|
resourceContent: string;
|
||||||
nextCursor: ListResourcesResult["nextCursor"];
|
|
||||||
nextTemplateCursor: ListResourceTemplatesResult["nextCursor"];
|
|
||||||
error: string | null;
|
error: string | null;
|
||||||
}) => {
|
}) => (
|
||||||
const [selectedTemplate, setSelectedTemplate] =
|
<TabsContent value="resources" className="grid grid-cols-2 gap-4">
|
||||||
useState<ResourceTemplate | null>(null);
|
<ListPane
|
||||||
const [templateValues, setTemplateValues] = useState<Record<string, string>>(
|
items={resources}
|
||||||
{},
|
listItems={listResources}
|
||||||
);
|
setSelectedItem={(resource) => {
|
||||||
|
setSelectedResource(resource);
|
||||||
|
readResource(resource.uri);
|
||||||
|
}}
|
||||||
|
renderItem={(resource) => (
|
||||||
|
<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={resource.uri.toString()}>
|
||||||
|
{resource.name}
|
||||||
|
</span>
|
||||||
|
<ChevronRight className="w-4 h-4 flex-shrink-0 text-gray-400" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
title="Resources"
|
||||||
|
buttonText="List Resources"
|
||||||
|
/>
|
||||||
|
|
||||||
const fillTemplate = (
|
<div className="bg-white rounded-lg shadow">
|
||||||
template: string,
|
<div className="p-4 border-b border-gray-200 flex justify-between items-center">
|
||||||
values: Record<string, string>,
|
<h3 className="font-semibold truncate" title={selectedResource?.name}>
|
||||||
): string => {
|
{selectedResource ? selectedResource.name : "Select a resource"}
|
||||||
return template.replace(
|
</h3>
|
||||||
/{([^}]+)}/g,
|
{selectedResource && (
|
||||||
(_, key) => values[key] || `{${key}}`,
|
<Button
|
||||||
);
|
variant="outline"
|
||||||
};
|
size="sm"
|
||||||
|
onClick={() => readResource(selectedResource.uri)}
|
||||||
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
|
|
||||||
items={resources}
|
|
||||||
listItems={listResources}
|
|
||||||
setSelectedItem={(resource) => {
|
|
||||||
setSelectedResource(resource);
|
|
||||||
readResource(resource.uri);
|
|
||||||
setSelectedTemplate(null);
|
|
||||||
}}
|
|
||||||
renderItem={(resource) => (
|
|
||||||
<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={resource.uri.toString()}>
|
|
||||||
{resource.name}
|
|
||||||
</span>
|
|
||||||
<ChevronRight className="w-4 h-4 flex-shrink-0 text-gray-400" />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
title="Resources"
|
|
||||||
buttonText={nextCursor ? "List More Resources" : "List Resources"}
|
|
||||||
isButtonDisabled={!nextCursor && resources.length > 0}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<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">
|
|
||||||
<h3
|
|
||||||
className="font-semibold truncate"
|
|
||||||
title={selectedResource?.name || selectedTemplate?.name}
|
|
||||||
>
|
>
|
||||||
{selectedResource
|
<RefreshCw className="w-4 h-4 mr-2" />
|
||||||
? selectedResource.name
|
Refresh
|
||||||
: selectedTemplate
|
</Button>
|
||||||
? selectedTemplate.name
|
)}
|
||||||
: "Select a resource or template"}
|
|
||||||
</h3>
|
|
||||||
{selectedResource && (
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => readResource(selectedResource.uri)}
|
|
||||||
>
|
|
||||||
<RefreshCw className="w-4 h-4 mr-2" />
|
|
||||||
Refresh
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="p-4">
|
|
||||||
{error ? (
|
|
||||||
<Alert variant="destructive">
|
|
||||||
<AlertCircle className="h-4 w-4" />
|
|
||||||
<AlertTitle>Error</AlertTitle>
|
|
||||||
<AlertDescription>{error}</AlertDescription>
|
|
||||||
</Alert>
|
|
||||||
) : selectedResource ? (
|
|
||||||
<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}
|
|
||||||
</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>
|
|
||||||
<AlertDescription>
|
|
||||||
Select a resource or template from the list to view its contents
|
|
||||||
</AlertDescription>
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
<div className="p-4">
|
||||||
);
|
{error ? (
|
||||||
};
|
<Alert variant="destructive">
|
||||||
|
<AlertCircle className="h-4 w-4" />
|
||||||
|
<AlertTitle>Error</AlertTitle>
|
||||||
|
<AlertDescription>{error}</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
) : selectedResource ? (
|
||||||
|
<pre className="bg-gray-50 p-4 rounded text-sm overflow-auto max-h-96 whitespace-pre-wrap break-words">
|
||||||
|
{resourceContent}
|
||||||
|
</pre>
|
||||||
|
) : (
|
||||||
|
<Alert>
|
||||||
|
<AlertDescription>
|
||||||
|
Select a resource from the list to view its contents
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
);
|
||||||
|
|
||||||
export default ResourcesTab;
|
export default ResourcesTab;
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
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;
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
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,242 +1,39 @@
|
|||||||
import { useState } from "react";
|
import { Menu, Settings } from "lucide-react";
|
||||||
|
|
||||||
import { Play, ChevronDown, ChevronRight } from "lucide-react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
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";
|
|
||||||
|
|
||||||
import useTheme from "../lib/useTheme";
|
const Sidebar = ({ connectionStatus }: { connectionStatus: string }) => (
|
||||||
|
<div className="w-64 bg-white border-r border-gray-200">
|
||||||
interface SidebarProps {
|
<div className="flex items-center p-4 border-b border-gray-200">
|
||||||
connectionStatus: "disconnected" | "connected" | "error";
|
<Menu className="w-6 h-6 text-gray-500" />
|
||||||
transportType: "stdio" | "sse";
|
<h1 className="ml-2 text-lg font-semibold">MCP Inspector</h1>
|
||||||
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 [theme, setTheme] = useTheme();
|
|
||||||
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 justify-between p-4 border-b border-gray-200">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<h1 className="ml-2 text-lg font-semibold">MCP Inspector</h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-4 flex-1 overflow-auto">
|
|
||||||
<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
|
|
||||||
className={`w-2 h-2 rounded-full ${
|
|
||||||
connectionStatus === "connected"
|
|
||||||
? "bg-green-500"
|
|
||||||
: connectionStatus === "error"
|
|
||||||
? "bg-red-500"
|
|
||||||
: "bg-gray-500"
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
<span className="text-sm text-gray-600">
|
|
||||||
{connectionStatus === "connected"
|
|
||||||
? "Connected"
|
|
||||||
: connectionStatus === "error"
|
|
||||||
? "Connection Error"
|
|
||||||
: "Disconnected"}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{stdErrNotifications.length > 0 && (
|
|
||||||
<>
|
|
||||||
<div className="mt-4 border-t border-gray-200 pt-4">
|
|
||||||
<h3 className="text-sm font-medium">
|
|
||||||
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 className="p-4 border-t">
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<Select
|
|
||||||
value={theme}
|
|
||||||
onValueChange={(value: string) =>
|
|
||||||
setTheme(value as "system" | "light" | "dark")
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-[120px]" id="theme-select">
|
|
||||||
<SelectValue />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="system">System</SelectItem>
|
|
||||||
<SelectItem value="light">Light</SelectItem>
|
|
||||||
<SelectItem value="dark">Dark</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
|
||||||
};
|
<div className="p-4">
|
||||||
|
<div className="flex items-center space-x-2 mb-4">
|
||||||
|
<div
|
||||||
|
className={`w-2 h-2 rounded-full ${
|
||||||
|
connectionStatus === "connected"
|
||||||
|
? "bg-green-500"
|
||||||
|
: connectionStatus === "error"
|
||||||
|
? "bg-red-500"
|
||||||
|
: "bg-gray-500"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
<span className="text-sm text-gray-600">
|
||||||
|
{connectionStatus === "connected"
|
||||||
|
? "Connected"
|
||||||
|
: connectionStatus === "error"
|
||||||
|
? "Connection Error"
|
||||||
|
: "Disconnected"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button variant="outline" className="w-full justify-start">
|
||||||
|
<Settings className="w-4 h-4 mr-2" />
|
||||||
|
Connection Settings
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
export default Sidebar;
|
export default Sidebar;
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
import { TabsContent } from "@/components/ui/tabs";
|
||||||
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 { Label } from "@/components/ui/label";
|
import { Send, AlertCircle } from "lucide-react";
|
||||||
import { TabsContent } from "@/components/ui/tabs";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Tool } from "mcp-typescript/types.js";
|
||||||
import {
|
|
||||||
CallToolResult,
|
|
||||||
ListToolsResult,
|
|
||||||
Tool,
|
|
||||||
} from "@modelcontextprotocol/sdk/types.js";
|
|
||||||
import { AlertCircle, Send } from "lucide-react";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
import ListPane from "./ListPane";
|
import ListPane from "./ListPane";
|
||||||
|
|
||||||
import { CompatibilityCallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
||||||
|
|
||||||
const ToolsTab = ({
|
const ToolsTab = ({
|
||||||
tools,
|
tools,
|
||||||
listTools,
|
listTools,
|
||||||
@@ -22,7 +15,6 @@ const ToolsTab = ({
|
|||||||
selectedTool,
|
selectedTool,
|
||||||
setSelectedTool,
|
setSelectedTool,
|
||||||
toolResult,
|
toolResult,
|
||||||
nextCursor,
|
|
||||||
error,
|
error,
|
||||||
}: {
|
}: {
|
||||||
tools: Tool[];
|
tools: Tool[];
|
||||||
@@ -30,59 +22,11 @@ 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: CompatibilityCallToolResult | null;
|
toolResult: string;
|
||||||
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 dark:bg-gray-800 dark:text-gray-100 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
|
||||||
@@ -92,17 +36,14 @@ const ToolsTab = ({
|
|||||||
renderItem={(tool) => (
|
renderItem={(tool) => (
|
||||||
<>
|
<>
|
||||||
<span className="flex-1">{tool.name}</span>
|
<span className="flex-1">{tool.name}</span>
|
||||||
<span className="text-sm text-gray-500 text-right">
|
<span className="text-sm text-gray-500">{tool.description}</span>
|
||||||
{tool.description}
|
|
||||||
</span>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
title="Tools"
|
title="Tools"
|
||||||
buttonText={nextCursor ? "List More Tools" : "List Tools"}
|
buttonText="List Tools"
|
||||||
isButtonDisabled={!nextCursor && tools.length > 0}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="bg-card rounded-lg shadow">
|
<div className="bg-white 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"}
|
||||||
@@ -120,7 +61,7 @@ const ToolsTab = ({
|
|||||||
<p className="text-sm text-gray-600">
|
<p className="text-sm text-gray-600">
|
||||||
{selectedTool.description}
|
{selectedTool.description}
|
||||||
</p>
|
</p>
|
||||||
{Object.entries(selectedTool.inputSchema.properties ?? []).map(
|
{Object.entries(selectedTool.inputSchema.properties).map(
|
||||||
([key, value]) => (
|
([key, value]) => (
|
||||||
<div key={key}>
|
<div key={key}>
|
||||||
<Label
|
<Label
|
||||||
@@ -129,44 +70,21 @@ const ToolsTab = ({
|
|||||||
>
|
>
|
||||||
{key}
|
{key}
|
||||||
</Label>
|
</Label>
|
||||||
{
|
<Input
|
||||||
/* @ts-expect-error value type is currently unknown */
|
type={value.type === "number" ? "number" : "text"}
|
||||||
value.type === "string" ? (
|
id={key}
|
||||||
<Textarea
|
name={key}
|
||||||
id={key}
|
placeholder={value.description}
|
||||||
name={key}
|
onChange={(e) =>
|
||||||
// @ts-expect-error value type is currently unknown
|
setParams({
|
||||||
placeholder={value.description}
|
...params,
|
||||||
onChange={(e) =>
|
[key]:
|
||||||
setParams({
|
value.type === "number"
|
||||||
...params,
|
? Number(e.target.value)
|
||||||
[key]: e.target.value,
|
: e.target.value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
className="mt-1"
|
/>
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Input
|
|
||||||
// @ts-expect-error value type is currently unknown
|
|
||||||
type={value.type === "number" ? "number" : "text"}
|
|
||||||
id={key}
|
|
||||||
name={key}
|
|
||||||
// @ts-expect-error value type is currently unknown
|
|
||||||
placeholder={value.description}
|
|
||||||
onChange={(e) =>
|
|
||||||
setParams({
|
|
||||||
...params,
|
|
||||||
[key]:
|
|
||||||
// @ts-expect-error value type is currently unknown
|
|
||||||
value.type === "number"
|
|
||||||
? Number(e.target.value)
|
|
||||||
: e.target.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
className="mt-1"
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
@@ -174,7 +92,14 @@ 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 && renderToolResult()}
|
{toolResult && (
|
||||||
|
<>
|
||||||
|
<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 dark:bg-gray-800 dark:text-white dark:hover:bg-gray-700",
|
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||||
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>,
|
||||||
@@ -27,13 +27,13 @@ const TabsTrigger = React.forwardRef<
|
|||||||
<TabsPrimitive.Trigger
|
<TabsPrimitive.Trigger
|
||||||
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 bg-muted 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 }
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
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>;
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import { useCallback, useEffect, useState } from "react";
|
|
||||||
|
|
||||||
type Theme = "light" | "dark" | "system";
|
|
||||||
|
|
||||||
const useTheme = (): [Theme, (mode: Theme) => void] => {
|
|
||||||
const [theme, setTheme] = useState<Theme>(() => {
|
|
||||||
const savedTheme = localStorage.getItem("theme") as Theme;
|
|
||||||
return savedTheme || "system";
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const darkModeMediaQuery = window.matchMedia(
|
|
||||||
"(prefers-color-scheme: dark)",
|
|
||||||
);
|
|
||||||
const handleDarkModeChange = (e: MediaQueryListEvent) => {
|
|
||||||
if (theme === "system") {
|
|
||||||
updateDocumentTheme(e.matches ? "dark" : "light");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateDocumentTheme = (newTheme: "light" | "dark") => {
|
|
||||||
document.documentElement.classList.toggle("dark", newTheme === "dark");
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set initial theme based on current mode
|
|
||||||
if (theme === "system") {
|
|
||||||
updateDocumentTheme(darkModeMediaQuery.matches ? "dark" : "light");
|
|
||||||
} else {
|
|
||||||
updateDocumentTheme(theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
darkModeMediaQuery.addEventListener("change", handleDarkModeChange);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
darkModeMediaQuery.removeEventListener("change", handleDarkModeChange);
|
|
||||||
};
|
|
||||||
}, [theme]);
|
|
||||||
|
|
||||||
return [
|
|
||||||
theme,
|
|
||||||
useCallback((newTheme: Theme) => {
|
|
||||||
setTheme(newTheme);
|
|
||||||
localStorage.setItem("theme", newTheme);
|
|
||||||
if (newTheme !== "system") {
|
|
||||||
document.documentElement.classList.toggle("dark", newTheme === "dark");
|
|
||||||
}
|
|
||||||
}, []),
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useTheme;
|
|
||||||
@@ -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,13 +1,10 @@
|
|||||||
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,7 +2,9 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": [
|
||||||
|
"./src/*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
|
|||||||
1
client/tsconfig.node.tsbuildinfo
Normal file
1
client/tsconfig.node.tsbuildinfo
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"root":["./vite.config.ts"],"version":"5.6.2"}
|
||||||
5893
package-lock.json
generated
5893
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
49
package.json
49
package.json
@@ -1,44 +1,25 @@
|
|||||||
{
|
{
|
||||||
"name": "@modelcontextprotocol/inspector",
|
"name": "mcp-inspector",
|
||||||
"version": "0.2.2",
|
"private": true,
|
||||||
"description": "Model Context Protocol inspector",
|
"version": "0.0.1",
|
||||||
"license": "MIT",
|
|
||||||
"author": "Anthropic, PBC (https://anthropic.com)",
|
|
||||||
"homepage": "https://modelcontextprotocol.io",
|
|
||||||
"bugs": "https://github.com/modelcontextprotocol/inspector/issues",
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"workspaces": ["client", "server"],
|
||||||
"mcp-inspector": "./bin/cli.js"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"bin",
|
|
||||||
"client/bin",
|
|
||||||
"client/dist",
|
|
||||||
"server/build"
|
|
||||||
],
|
|
||||||
"workspaces": [
|
|
||||||
"client",
|
|
||||||
"server"
|
|
||||||
],
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "concurrently \"cd client && npm run dev\" \"cd server && npm run dev\"",
|
"dev": "concurrently \"cd client && yarn dev\" \"cd server && yarn dev\"",
|
||||||
"build-server": "cd server && npm run build",
|
"build-server": "cd server && yarn build",
|
||||||
"build-client": "cd client && npm run build",
|
"build-client": "cd client && yarn build",
|
||||||
"build": "npm run build-server && npm run build-client",
|
"build": "yarn build-server && yarn build-client",
|
||||||
"start-server": "cd server && npm run start",
|
"start-server": "cd server && yarn start",
|
||||||
"start-client": "cd client && npm run preview",
|
"start-client": "cd client && yarn preview",
|
||||||
"start": "./bin/cli.js",
|
"start": "concurrently \"yarn start-server\" \"yarn start-client\"",
|
||||||
"prepare": "npm run build",
|
|
||||||
"prettier-fix": "prettier --write .",
|
"prettier-fix": "prettier --write .",
|
||||||
"publish-all": "npm publish --workspaces --access public && npm publish --access public"
|
"update:mcp": "git subtree pull --prefix=packages/mcp-typescript https://github.com/modelcontextprotocol/typescript-sdk.git main --squash"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/inspector-client": "0.2.1",
|
"mcp-typescript": "file:packages/mcp-typescript"
|
||||||
"@modelcontextprotocol/inspector-server": "0.2.1",
|
|
||||||
"concurrently": "^9.0.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prettier": "3.3.3",
|
"concurrently": "^9.0.1",
|
||||||
"@types/node": "^22.7.5"
|
"prettier": "3.3.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
packages/mcp-typescript/.gitattributes
generated
vendored
Normal file
1
packages/mcp-typescript/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
dist/**/* linguist-generated=true
|
||||||
26
packages/mcp-typescript/.github/workflows/main.yml
generated
vendored
Normal file
26
packages/mcp-typescript/.github/workflows/main.yml
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
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
generated
vendored
Normal file
131
packages/mcp-typescript/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
# 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
|
||||||
2
packages/mcp-typescript/README.md
generated
Normal file
2
packages/mcp-typescript/README.md
generated
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# mcp-typescript
|
||||||
|
TypeScript implementation of the Model Context Protocol
|
||||||
2
packages/mcp-typescript/dist/cli.d.ts
generated
vendored
Normal file
2
packages/mcp-typescript/dist/cli.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export {};
|
||||||
|
//# sourceMappingURL=cli.d.ts.map
|
||||||
1
packages/mcp-typescript/dist/cli.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/cli.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
||||||
119
packages/mcp-typescript/dist/cli.js
generated
vendored
Normal file
119
packages/mcp-typescript/dist/cli.js
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
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();
|
||||||
|
await clientTransport.connect(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();
|
||||||
|
await clientTransport.connect(new URL(url_or_command));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
clientTransport = new StdioClientTransport();
|
||||||
|
await clientTransport.spawn({
|
||||||
|
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");
|
||||||
|
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 transport.connectSSE(req, res);
|
||||||
|
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 transport.start();
|
||||||
|
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
generated
vendored
Normal file
1
packages/mcp-typescript/dist/cli.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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
generated
vendored
Normal file
27
packages/mcp-typescript/dist/client/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
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
packages/mcp-typescript/dist/client/index.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/client/index.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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
generated
vendored
Normal file
51
packages/mcp-typescript/dist/client/index.js
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
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
packages/mcp-typescript/dist/client/index.js.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/client/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
20
packages/mcp-typescript/dist/client/sse.d.ts
generated
vendored
Normal file
20
packages/mcp-typescript/dist/client/sse.d.ts
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
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?;
|
||||||
|
onclose?: () => void;
|
||||||
|
onerror?: (error: Error) => void;
|
||||||
|
onmessage?: (message: JSONRPCMessage) => void;
|
||||||
|
connect(url: URL): Promise<void>;
|
||||||
|
close(): Promise<void>;
|
||||||
|
send(message: JSONRPCMessage): Promise<void>;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=sse.d.ts.map
|
||||||
1
packages/mcp-typescript/dist/client/sse.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/client/sse.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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;IAE3C,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,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAmD1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CA0BnD"}
|
||||||
85
packages/mcp-typescript/dist/client/sse.js
generated
vendored
Normal file
85
packages/mcp-typescript/dist/client/sse.js
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
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 {
|
||||||
|
connect(url) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this._eventSource = new EventSource(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, url);
|
||||||
|
if (this._endpoint.origin !== 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
packages/mcp-typescript/dist/client/sse.js.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/client/sse.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/client/sse.ts"],"names":[],"mappings":"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"}
|
||||||
39
packages/mcp-typescript/dist/client/stdio.d.ts
generated
vendored
Normal file
39
packages/mcp-typescript/dist/client/stdio.d.ts
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
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;
|
||||||
|
onclose?: () => void;
|
||||||
|
onerror?: (error: Error) => void;
|
||||||
|
onmessage?: (message: JSONRPCMessage) => void;
|
||||||
|
/**
|
||||||
|
* Spawns the server process and prepare to communicate with it.
|
||||||
|
*/
|
||||||
|
spawn(server: StdioServerParameters): Promise<void>;
|
||||||
|
private processReadBuffer;
|
||||||
|
close(): Promise<void>;
|
||||||
|
send(message: JSONRPCMessage): Promise<void>;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=stdio.d.ts.map
|
||||||
1
packages/mcp-typescript/dist/client/stdio.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/client/stdio.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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;IAEnD,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;IACH,KAAK,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IA4CnD,OAAO,CAAC,iBAAiB;IAenB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAc7C"}
|
||||||
93
packages/mcp-typescript/dist/client/stdio.js
generated
vendored
Normal file
93
packages/mcp-typescript/dist/client/stdio.js
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
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() {
|
||||||
|
this._abortController = new AbortController();
|
||||||
|
this._readBuffer = new ReadBuffer();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Spawns the server process and prepare to communicate with it.
|
||||||
|
*/
|
||||||
|
spawn(server) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var _a, _b, _c, _d;
|
||||||
|
this._process = spawn(server.command, (_a = server.args) !== null && _a !== void 0 ? _a : [], {
|
||||||
|
// The parent process may have sensitive secrets in its env, so don't inherit it automatically.
|
||||||
|
env: server.env === undefined ? {} : { ...server.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
packages/mcp-typescript/dist/client/stdio.js.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/client/stdio.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/client/stdio.ts"],"names":[],"mappings":"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"}
|
||||||
2
packages/mcp-typescript/dist/client/stdio.test.d.ts
generated
vendored
Normal file
2
packages/mcp-typescript/dist/client/stdio.test.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export {};
|
||||||
|
//# sourceMappingURL=stdio.test.d.ts.map
|
||||||
1
packages/mcp-typescript/dist/client/stdio.test.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/client/stdio.test.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"stdio.test.d.ts","sourceRoot":"","sources":["../../src/client/stdio.test.ts"],"names":[],"mappings":""}
|
||||||
51
packages/mcp-typescript/dist/client/stdio.test.js
generated
vendored
Normal file
51
packages/mcp-typescript/dist/client/stdio.test.js
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { StdioClientTransport } from "./stdio.js";
|
||||||
|
const serverParameters = {
|
||||||
|
command: "/usr/bin/tee",
|
||||||
|
};
|
||||||
|
test("should start then close cleanly", async () => {
|
||||||
|
const client = new StdioClientTransport();
|
||||||
|
client.onerror = (error) => {
|
||||||
|
throw error;
|
||||||
|
};
|
||||||
|
let didClose = false;
|
||||||
|
client.onclose = () => {
|
||||||
|
didClose = true;
|
||||||
|
};
|
||||||
|
await client.spawn(serverParameters);
|
||||||
|
expect(didClose).toBeFalsy();
|
||||||
|
await client.close();
|
||||||
|
expect(didClose).toBeTruthy();
|
||||||
|
});
|
||||||
|
test("should read messages", async () => {
|
||||||
|
const client = new StdioClientTransport();
|
||||||
|
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.spawn(serverParameters);
|
||||||
|
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
packages/mcp-typescript/dist/client/stdio.test.js.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/client/stdio.test.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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,EAAE,CAAC;IAC1C,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,CAAC,gBAAgB,CAAC,CAAC;IACrC,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,EAAE,CAAC;IAC1C,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,CAAC,gBAAgB,CAAC,CAAC;IACrC,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"}
|
||||||
15
packages/mcp-typescript/dist/client/websocket.d.ts
generated
vendored
Normal file
15
packages/mcp-typescript/dist/client/websocket.d.ts
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
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?;
|
||||||
|
onclose?: () => void;
|
||||||
|
onerror?: (error: Error) => void;
|
||||||
|
onmessage?: (message: JSONRPCMessage) => void;
|
||||||
|
connect(url: URL): Promise<void>;
|
||||||
|
close(): Promise<void>;
|
||||||
|
send(message: JSONRPCMessage): Promise<void>;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=websocket.d.ts.map
|
||||||
1
packages/mcp-typescript/dist/client/websocket.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/client/websocket.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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;IAE5B,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,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAmC1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAW7C"}
|
||||||
55
packages/mcp-typescript/dist/client/websocket.js
generated
vendored
Normal file
55
packages/mcp-typescript/dist/client/websocket.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
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 {
|
||||||
|
connect(url) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this._socket = new WebSocket(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
packages/mcp-typescript/dist/client/websocket.js.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/client/websocket.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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;IAOnC,OAAO,CAAC,GAAQ;QACd,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,OAAO,GAAG,IAAI,SAAS,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;YAE/C,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"}
|
||||||
30
packages/mcp-typescript/dist/server/index.d.ts
generated
vendored
Normal file
30
packages/mcp-typescript/dist/server/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=index.d.ts.map
|
||||||
1
packages/mcp-typescript/dist/server/index.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/server/index.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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,EAClB,cAAc,EAMd,kBAAkB,EAClB,aAAa,EACb,YAAY,EACb,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;CAG/C"}
|
||||||
43
packages/mcp-typescript/dist/server/index.js
generated
vendored
Normal file
43
packages/mcp-typescript/dist/server/index.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { Protocol } from "../shared/protocol.js";
|
||||||
|
import { InitializedNotificationSchema, InitializeRequestSchema, PROTOCOL_VERSION, } 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: {},
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=index.js.map
|
||||||
1
packages/mcp-typescript/dist/server/index.js.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/server/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAGL,6BAA6B,EAE7B,uBAAuB,EAEvB,gBAAgB,GAIjB,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,EAAE;YAChB,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;CACF"}
|
||||||
45
packages/mcp-typescript/dist/server/sse.d.ts
generated
vendored
Normal file
45
packages/mcp-typescript/dist/server/sse.d.ts
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
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 _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);
|
||||||
|
/**
|
||||||
|
* Handles the initial SSE connection request.
|
||||||
|
*
|
||||||
|
* This should be called when a GET request is made to establish the SSE stream.
|
||||||
|
*/
|
||||||
|
connectSSE(req: IncomingMessage, res: ServerResponse): 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
packages/mcp-typescript/dist/server/sse.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/server/sse.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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;IAWtC,OAAO,CAAC,SAAS;IAV7B,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;gBACiB,SAAS,EAAE,MAAM;IAIrC;;;;OAIG;IACG,UAAU,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB1E;;;;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"}
|
||||||
115
packages/mcp-typescript/dist/server/sse.js
generated
vendored
Normal file
115
packages/mcp-typescript/dist/server/sse.js
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
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) {
|
||||||
|
this._endpoint = _endpoint;
|
||||||
|
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 connectSSE(req, res) {
|
||||||
|
if (this._sseResponse) {
|
||||||
|
throw new Error("Already connected!");
|
||||||
|
}
|
||||||
|
res.writeHead(200, {
|
||||||
|
"Content-Type": "text/event-stream",
|
||||||
|
"Cache-Control": "no-cache",
|
||||||
|
Connection: "keep-alive",
|
||||||
|
});
|
||||||
|
// Send the endpoint event
|
||||||
|
res.write(`event: endpoint\ndata: ${encodeURI(this._endpoint)}?sessionId=${this._sessionId}\n\n`);
|
||||||
|
this._sseResponse = res;
|
||||||
|
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
packages/mcp-typescript/dist/server/sse.js.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/server/sse.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/server/sse.ts"],"names":[],"mappings":"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"}
|
||||||
27
packages/mcp-typescript/dist/server/stdio.d.ts
generated
vendored
Normal file
27
packages/mcp-typescript/dist/server/stdio.d.ts
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
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;
|
||||||
|
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
packages/mcp-typescript/dist/server/stdio.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/server/stdio.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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;IAIlD,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,OAAO;IAJjB,OAAO,CAAC,WAAW,CAAgC;gBAGzC,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;IAK5B,OAAO,CAAC,iBAAiB;IAenB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAU7C"}
|
||||||
64
packages/mcp-typescript/dist/server/stdio.js
generated
vendored
Normal file
64
packages/mcp-typescript/dist/server/stdio.js
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
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();
|
||||||
|
// 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() {
|
||||||
|
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
packages/mcp-typescript/dist/server/stdio.js.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/server/stdio.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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;IAG/B,YACU,SAAmB,OAAO,CAAC,KAAK,EAChC,UAAoB,OAAO,CAAC,MAAM;QADlC,WAAM,GAAN,MAAM,CAA0B;QAChC,YAAO,GAAP,OAAO,CAA2B;QAJpC,gBAAW,GAAe,IAAI,UAAU,EAAE,CAAC;QAWnD,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,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"}
|
||||||
2
packages/mcp-typescript/dist/server/stdio.test.d.ts
generated
vendored
Normal file
2
packages/mcp-typescript/dist/server/stdio.test.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export {};
|
||||||
|
//# sourceMappingURL=stdio.test.d.ts.map
|
||||||
1
packages/mcp-typescript/dist/server/stdio.test.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/server/stdio.test.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"stdio.test.d.ts","sourceRoot":"","sources":["../../src/server/stdio.test.ts"],"names":[],"mappings":""}
|
||||||
87
packages/mcp-typescript/dist/server/stdio.test.js
generated
vendored
Normal file
87
packages/mcp-typescript/dist/server/stdio.test.js
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
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
packages/mcp-typescript/dist/server/stdio.test.js.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/server/stdio.test.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"stdio.test.js","sourceRoot":"","sources":["../../src/server/stdio.test.ts"],"names":[],"mappings":"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"}
|
||||||
92
packages/mcp-typescript/dist/shared/protocol.d.ts
generated
vendored
Normal file
92
packages/mcp-typescript/dist/shared/protocol.d.ts
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import { AnyZodObject, ZodLiteral, ZodObject, z } from "zod";
|
||||||
|
import { 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;
|
||||||
|
private _requestHandlers;
|
||||||
|
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 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
packages/mcp-typescript/dist/shared/protocol.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/shared/protocol.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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,EAOL,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,OAAO,CAAC,gBAAgB,CAGV;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;IAqBlD,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"}
|
||||||
224
packages/mcp-typescript/dist/shared/protocol.js
generated
vendored
Normal file
224
packages/mcp-typescript/dist/shared/protocol.js
generated
vendored
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
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 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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_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
|
||||||
1
packages/mcp-typescript/dist/shared/protocol.js.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/shared/protocol.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
13
packages/mcp-typescript/dist/shared/stdio.d.ts
generated
vendored
Normal file
13
packages/mcp-typescript/dist/shared/stdio.d.ts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
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
packages/mcp-typescript/dist/shared/stdio.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/shared/stdio.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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
generated
vendored
Normal file
31
packages/mcp-typescript/dist/shared/stdio.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
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
packages/mcp-typescript/dist/shared/stdio.js.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/shared/stdio.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"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"}
|
||||||
2
packages/mcp-typescript/dist/shared/stdio.test.d.ts
generated
vendored
Normal file
2
packages/mcp-typescript/dist/shared/stdio.test.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export {};
|
||||||
|
//# sourceMappingURL=stdio.test.d.ts.map
|
||||||
1
packages/mcp-typescript/dist/shared/stdio.test.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/shared/stdio.test.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"stdio.test.d.ts","sourceRoot":"","sources":["../../src/shared/stdio.test.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