Compare commits
1 Commits
0.0.1
...
ashwin/err
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b05ffa7b1 |
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -1 +1,2 @@
|
||||
package-lock.json linguist-generated=true
|
||||
yarn.lock linguist-generated=true
|
||||
packages/**/* linguist-generated=true
|
||||
|
||||
37
.github/workflows/main.yml
vendored
37
.github/workflows/main.yml
vendored
@@ -1,37 +0,0 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
cache: npm
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: modelcontextprotocol/typescript-sdk
|
||||
ssh-key: ${{ secrets.TYPESCRIPT_SDK_KEY }}
|
||||
path: packages/@modelcontextprotocol/sdk
|
||||
|
||||
- run: npm ci
|
||||
working-directory: packages/@modelcontextprotocol/sdk
|
||||
|
||||
- run: npm pack
|
||||
working-directory: packages/@modelcontextprotocol/sdk
|
||||
|
||||
- run: npm install --save packages/@modelcontextprotocol/sdk/modelcontextprotocol-sdk-*.tgz
|
||||
|
||||
# Working around https://github.com/npm/cli/issues/4828
|
||||
# - run: npm ci
|
||||
- run: npm install --no-package-lock
|
||||
- run: npm run build
|
||||
@@ -5,13 +5,13 @@ The MCP inspector is a developer tool for testing and debugging MCP servers.
|
||||
Setup:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
yarn
|
||||
```
|
||||
|
||||
You can run it in dev mode via:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
yarn dev
|
||||
```
|
||||
|
||||
This will start both the client and server.
|
||||
@@ -19,6 +19,6 @@ This will start both the client and server.
|
||||
To run in production mode:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npm start
|
||||
yarn build
|
||||
yarn start
|
||||
```
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>MCP Inspector</title>
|
||||
<title>Vite + React + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "*",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
"@radix-ui/react-select": "^2.1.2",
|
||||
@@ -19,6 +18,7 @@
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.447.0",
|
||||
"mcp-typescript": "file:../packages/mcp-typescript",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"tailwind-merge": "^2.5.3",
|
||||
|
||||
@@ -1,5 +1,33 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Client } from "mcp-typescript/client/index.js";
|
||||
import { SSEClientTransport } from "mcp-typescript/client/sse.js";
|
||||
import {
|
||||
ListResourcesResultSchema,
|
||||
GetPromptResultSchema,
|
||||
ListToolsResultSchema,
|
||||
ReadResourceResultSchema,
|
||||
CallToolResultSchema,
|
||||
ListPromptsResultSchema,
|
||||
Resource,
|
||||
Tool,
|
||||
ClientRequest,
|
||||
ProgressNotificationSchema,
|
||||
ServerNotification,
|
||||
EmptyResultSchema,
|
||||
} from "mcp-typescript/types.js";
|
||||
import { useState, useRef } from "react";
|
||||
import {
|
||||
Send,
|
||||
Terminal,
|
||||
Files,
|
||||
Bell,
|
||||
MessageSquare,
|
||||
Hammer,
|
||||
Play,
|
||||
X,
|
||||
} 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,
|
||||
@@ -7,44 +35,17 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
||||
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
||||
import {
|
||||
CallToolResultSchema,
|
||||
ClientRequest,
|
||||
EmptyResultSchema,
|
||||
GetPromptResultSchema,
|
||||
ListPromptsResultSchema,
|
||||
ListResourcesResultSchema,
|
||||
ListToolsResultSchema,
|
||||
ProgressNotificationSchema,
|
||||
ReadResourceResultSchema,
|
||||
Resource,
|
||||
ServerNotification,
|
||||
Tool,
|
||||
} from "@modelcontextprotocol/sdk/types.js";
|
||||
import {
|
||||
Bell,
|
||||
Files,
|
||||
Hammer,
|
||||
MessageSquare,
|
||||
Play,
|
||||
Send,
|
||||
Terminal,
|
||||
} from "lucide-react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import { AnyZodObject } from "zod";
|
||||
import "./App.css";
|
||||
import ConsoleTab from "./components/ConsoleTab";
|
||||
import HistoryAndNotifications from "./components/History";
|
||||
import PingTab from "./components/PingTab";
|
||||
import PromptsTab, { Prompt } from "./components/PromptsTab";
|
||||
import Sidebar from "./components/Sidebar";
|
||||
import RequestsTab from "./components/RequestsTabs";
|
||||
import ResourcesTab from "./components/ResourcesTab";
|
||||
import Sidebar from "./components/Sidebar";
|
||||
import PromptsTab, { Prompt } from "./components/PromptsTab";
|
||||
import ToolsTab from "./components/ToolsTab";
|
||||
import { AnyZodObject } from "zod";
|
||||
import HistoryAndNotifications from "./components/History";
|
||||
import "./App.css";
|
||||
import PingTab from "./components/PingTab";
|
||||
|
||||
const App = () => {
|
||||
const [connectionStatus, setConnectionStatus] = useState<
|
||||
@@ -57,18 +58,12 @@ const App = () => {
|
||||
const [tools, setTools] = useState<Tool[]>([]);
|
||||
const [toolResult, setToolResult] = useState<string>("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [command, setCommand] = useState<string>(() => {
|
||||
return (
|
||||
localStorage.getItem("lastCommand") ||
|
||||
"/Users/ashwin/.nvm/versions/node/v18.20.4/bin/node"
|
||||
);
|
||||
});
|
||||
const [args, setArgs] = useState<string>(() => {
|
||||
return (
|
||||
localStorage.getItem("lastArgs") ||
|
||||
"/Users/ashwin/code/mcp/example-servers/build/everything/stdio.js"
|
||||
);
|
||||
});
|
||||
const [command, setCommand] = useState<string>(
|
||||
"/Users/ashwin/.nvm/versions/node/v18.20.4/bin/node",
|
||||
);
|
||||
const [args, setArgs] = useState<string>(
|
||||
"/Users/ashwin/code/mcp/example-servers/build/everything/stdio.js",
|
||||
);
|
||||
const [url, setUrl] = useState<string>("http://localhost:3001/sse");
|
||||
const [transportType, setTransportType] = useState<"stdio" | "sse">("stdio");
|
||||
const [requestHistory, setRequestHistory] = useState<
|
||||
@@ -91,14 +86,6 @@ const App = () => {
|
||||
const [nextToolCursor, setNextToolCursor] = useState<string | undefined>();
|
||||
const progressTokenRef = useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem("lastCommand", command);
|
||||
}, [command]);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem("lastArgs", args);
|
||||
}, [args]);
|
||||
|
||||
const pushHistory = (request: object, response: object) => {
|
||||
setRequestHistory((prev) => [
|
||||
...prev,
|
||||
@@ -237,6 +224,10 @@ const App = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const clearError = () => {
|
||||
setError(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-screen bg-gray-100">
|
||||
<Sidebar connectionStatus={connectionStatus} />
|
||||
@@ -286,6 +277,15 @@ const App = () => {
|
||||
Connect
|
||||
</Button>
|
||||
</div>
|
||||
{error && (
|
||||
<div className="mt-2 flex items-center">
|
||||
<p className="text-red-500 mr-2">{error}</p>
|
||||
<Button onClick={clearError} variant="outline" size="sm">
|
||||
<X className="w-4 h-4" />
|
||||
Clear Error
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{mcpClient ? (
|
||||
<Tabs defaultValue="resources" className="w-full p-4">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ServerNotification } from "@modelcontextprotocol/sdk/types.js";
|
||||
import { Copy } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { Copy } from "lucide-react";
|
||||
import { ServerNotification } from "mcp-typescript/types.js";
|
||||
|
||||
const HistoryAndNotifications = ({
|
||||
requestHistory,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
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 { 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 { Label } from "@/components/ui/label";
|
||||
import ListPane from "./ListPane";
|
||||
import { ListPromptsResult } from "mcp-typescript/types.js";
|
||||
|
||||
export type Prompt = {
|
||||
name: string;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { FileText, ChevronRight, AlertCircle, RefreshCw } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { TabsContent } from "@/components/ui/tabs";
|
||||
import { ListResourcesResult, Resource } from "@modelcontextprotocol/sdk/types.js";
|
||||
import { AlertCircle, ChevronRight, FileText, RefreshCw } from "lucide-react";
|
||||
import { ListResourcesResult, Resource } from "mcp-typescript/types.js";
|
||||
import ListPane from "./ListPane";
|
||||
|
||||
const ResourcesTab = ({
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { TabsContent } from "@/components/ui/tabs";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { TabsContent } from "@/components/ui/tabs";
|
||||
import { ListToolsResult, Tool } from "@modelcontextprotocol/sdk/types.js";
|
||||
import { AlertCircle, Send } from "lucide-react";
|
||||
import { Send, AlertCircle } from "lucide-react";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { ListToolsResult, Tool } from "mcp-typescript/types.js";
|
||||
import { useState } from "react";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import ListPane from "./ListPane";
|
||||
|
||||
const ToolsTab = ({
|
||||
|
||||
5815
package-lock.json
generated
5815
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
25
package.json
25
package.json
@@ -3,19 +3,20 @@
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"workspaces": [
|
||||
"client",
|
||||
"server"
|
||||
],
|
||||
"workspaces": ["client", "server"],
|
||||
"scripts": {
|
||||
"dev": "concurrently \"cd client && npm run dev\" \"cd server && npm run dev\"",
|
||||
"build-server": "cd server && npm run build",
|
||||
"build-client": "cd client && npm run build",
|
||||
"build": "npm run build-server && npm run build-client",
|
||||
"start-server": "cd server && npm run start",
|
||||
"start-client": "cd client && npm run preview",
|
||||
"start": "concurrently \"npm run start-server\" \"npm run start-client\"",
|
||||
"prettier-fix": "prettier --write ."
|
||||
"dev": "concurrently \"cd client && yarn dev\" \"cd server && yarn dev\"",
|
||||
"build-server": "cd server && yarn build",
|
||||
"build-client": "cd client && yarn build",
|
||||
"build": "yarn build-server && yarn build-client",
|
||||
"start-server": "cd server && yarn start",
|
||||
"start-client": "cd client && yarn preview",
|
||||
"start": "concurrently \"yarn start-server\" \"yarn start-client\"",
|
||||
"prettier-fix": "prettier --write .",
|
||||
"update:mcp": "git subtree pull --prefix=packages/mcp-typescript https://github.com/modelcontextprotocol/typescript-sdk.git main --squash"
|
||||
},
|
||||
"dependencies": {
|
||||
"mcp-typescript": "file:packages/mcp-typescript"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "^9.0.1",
|
||||
|
||||
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":""}
|
||||
114
packages/mcp-typescript/dist/cli.js
generated
vendored
Normal file
114
packages/mcp-typescript/dist/cli.js
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
import EventSource from "eventsource";
|
||||
import WebSocket from "ws";
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
global.EventSource = EventSource;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
global.WebSocket = WebSocket;
|
||||
import express from "express";
|
||||
import { Client } from "./client/index.js";
|
||||
import { SSEClientTransport } from "./client/sse.js";
|
||||
import { Server } from "./server/index.js";
|
||||
import { SSEServerTransport } from "./server/sse.js";
|
||||
import { WebSocketClientTransport } from "./client/websocket.js";
|
||||
import { StdioClientTransport } from "./client/stdio.js";
|
||||
import { StdioServerTransport } from "./server/stdio.js";
|
||||
async function runClient(url_or_command, args) {
|
||||
const client = new Client({
|
||||
name: "mcp-typescript test client",
|
||||
version: "0.1.0",
|
||||
});
|
||||
let clientTransport;
|
||||
let url = undefined;
|
||||
try {
|
||||
url = new URL(url_or_command);
|
||||
}
|
||||
catch (_a) {
|
||||
// Ignore
|
||||
}
|
||||
if ((url === null || url === void 0 ? void 0 : url.protocol) === "http:" || (url === null || url === void 0 ? void 0 : url.protocol) === "https:") {
|
||||
clientTransport = new SSEClientTransport(new URL(url_or_command));
|
||||
}
|
||||
else if ((url === null || url === void 0 ? void 0 : url.protocol) === "ws:" || (url === null || url === void 0 ? void 0 : url.protocol) === "wss:") {
|
||||
clientTransport = new WebSocketClientTransport(new URL(url_or_command));
|
||||
}
|
||||
else {
|
||||
clientTransport = new StdioClientTransport({
|
||||
command: url_or_command,
|
||||
args,
|
||||
});
|
||||
}
|
||||
console.log("Connected to server.");
|
||||
await client.connect(clientTransport);
|
||||
console.log("Initialized.");
|
||||
await client.close();
|
||||
console.log("Closed.");
|
||||
}
|
||||
async function runServer(port) {
|
||||
if (port !== null) {
|
||||
const app = express();
|
||||
let servers = [];
|
||||
app.get("/sse", async (req, res) => {
|
||||
console.log("Got new SSE connection");
|
||||
const transport = new SSEServerTransport("/message", res);
|
||||
const server = new Server({
|
||||
name: "mcp-typescript test server",
|
||||
version: "0.1.0",
|
||||
});
|
||||
servers.push(server);
|
||||
server.onclose = () => {
|
||||
console.log("SSE connection closed");
|
||||
servers = servers.filter((s) => s !== server);
|
||||
};
|
||||
await server.connect(transport);
|
||||
});
|
||||
app.post("/message", async (req, res) => {
|
||||
console.log("Received message");
|
||||
const sessionId = req.query.sessionId;
|
||||
const transport = servers
|
||||
.map((s) => s.transport)
|
||||
.find((t) => t.sessionId === sessionId);
|
||||
if (!transport) {
|
||||
res.status(404).send("Session not found");
|
||||
return;
|
||||
}
|
||||
await transport.handlePostMessage(req, res);
|
||||
});
|
||||
app.listen(port, () => {
|
||||
console.log(`Server running on http://localhost:${port}/sse`);
|
||||
});
|
||||
}
|
||||
else {
|
||||
const server = new Server({
|
||||
name: "mcp-typescript test server",
|
||||
version: "0.1.0",
|
||||
});
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
console.log("Server running on stdio");
|
||||
}
|
||||
}
|
||||
const args = process.argv.slice(2);
|
||||
const command = args[0];
|
||||
switch (command) {
|
||||
case "client":
|
||||
if (args.length < 2) {
|
||||
console.error("Usage: client <server_url_or_command> [args...]");
|
||||
process.exit(1);
|
||||
}
|
||||
runClient(args[1], args.slice(2)).catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
break;
|
||||
case "server": {
|
||||
const port = args[1] ? parseInt(args[1]) : null;
|
||||
runServer(port).catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.error("Unrecognized command:", command);
|
||||
}
|
||||
//# sourceMappingURL=cli.js.map
|
||||
1
packages/mcp-typescript/dist/cli.js.map
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"}
|
||||
22
packages/mcp-typescript/dist/client/sse.d.ts
generated
vendored
Normal file
22
packages/mcp-typescript/dist/client/sse.d.ts
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Transport } from "../shared/transport.js";
|
||||
import { JSONRPCMessage } from "../types.js";
|
||||
/**
|
||||
* Client transport for SSE: this will connect to a server using Server-Sent Events for receiving
|
||||
* messages and make separate POST requests for sending messages.
|
||||
*
|
||||
* This uses the EventSource API in browsers. You can install the `eventsource` package for Node.js.
|
||||
*/
|
||||
export declare class SSEClientTransport implements Transport {
|
||||
private _eventSource?;
|
||||
private _endpoint?;
|
||||
private _abortController?;
|
||||
private _url;
|
||||
onclose?: () => void;
|
||||
onerror?: (error: Error) => void;
|
||||
onmessage?: (message: JSONRPCMessage) => void;
|
||||
constructor(url: URL);
|
||||
start(): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
send(message: JSONRPCMessage): Promise<void>;
|
||||
}
|
||||
//# sourceMappingURL=sse.d.ts.map
|
||||
1
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;IAC3C,OAAO,CAAC,IAAI,CAAM;IAElB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;gBAElC,GAAG,EAAE,GAAG;IAIpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyDhB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CA0BnD"}
|
||||
91
packages/mcp-typescript/dist/client/sse.js
generated
vendored
Normal file
91
packages/mcp-typescript/dist/client/sse.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
import { JSONRPCMessageSchema } from "../types.js";
|
||||
/**
|
||||
* Client transport for SSE: this will connect to a server using Server-Sent Events for receiving
|
||||
* messages and make separate POST requests for sending messages.
|
||||
*
|
||||
* This uses the EventSource API in browsers. You can install the `eventsource` package for Node.js.
|
||||
*/
|
||||
export class SSEClientTransport {
|
||||
constructor(url) {
|
||||
this._url = url;
|
||||
}
|
||||
start() {
|
||||
if (this._eventSource) {
|
||||
throw new Error("SSEClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
this._eventSource = new EventSource(this._url.href);
|
||||
this._abortController = new AbortController();
|
||||
this._eventSource.onerror = (event) => {
|
||||
var _a;
|
||||
const error = new Error(`SSE error: ${JSON.stringify(event)}`);
|
||||
reject(error);
|
||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
||||
};
|
||||
this._eventSource.onopen = () => {
|
||||
// The connection is open, but we need to wait for the endpoint to be received.
|
||||
};
|
||||
this._eventSource.addEventListener("endpoint", (event) => {
|
||||
var _a;
|
||||
const messageEvent = event;
|
||||
try {
|
||||
this._endpoint = new URL(messageEvent.data, this._url);
|
||||
if (this._endpoint.origin !== this._url.origin) {
|
||||
throw new Error(`Endpoint origin does not match connection origin: ${this._endpoint.origin}`);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
reject(error);
|
||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
||||
void this.close();
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
this._eventSource.onmessage = (event) => {
|
||||
var _a, _b;
|
||||
const messageEvent = event;
|
||||
let message;
|
||||
try {
|
||||
message = JSONRPCMessageSchema.parse(JSON.parse(messageEvent.data));
|
||||
}
|
||||
catch (error) {
|
||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
||||
return;
|
||||
}
|
||||
(_b = this.onmessage) === null || _b === void 0 ? void 0 : _b.call(this, message);
|
||||
};
|
||||
});
|
||||
}
|
||||
async close() {
|
||||
var _a, _b, _c;
|
||||
(_a = this._abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
||||
(_b = this._eventSource) === null || _b === void 0 ? void 0 : _b.close();
|
||||
(_c = this.onclose) === null || _c === void 0 ? void 0 : _c.call(this);
|
||||
}
|
||||
async send(message) {
|
||||
var _a, _b;
|
||||
if (!this._endpoint) {
|
||||
throw new Error("Not connected");
|
||||
}
|
||||
try {
|
||||
const response = await fetch(this._endpoint, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(message),
|
||||
signal: (_a = this._abortController) === null || _a === void 0 ? void 0 : _a.signal,
|
||||
});
|
||||
if (!response.ok) {
|
||||
const text = await response.text().catch(() => null);
|
||||
throw new Error(`Error POSTing to endpoint (HTTP ${response.status}): ${text}`);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=sse.js.map
|
||||
1
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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"}
|
||||
41
packages/mcp-typescript/dist/client/stdio.d.ts
generated
vendored
Normal file
41
packages/mcp-typescript/dist/client/stdio.d.ts
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
import { JSONRPCMessage } from "../types.js";
|
||||
import { Transport } from "../shared/transport.js";
|
||||
export type StdioServerParameters = {
|
||||
/**
|
||||
* The executable to run to start the server.
|
||||
*/
|
||||
command: string;
|
||||
/**
|
||||
* Command line arguments to pass to the executable.
|
||||
*/
|
||||
args?: string[];
|
||||
/**
|
||||
* The environment to use when spawning the process.
|
||||
*
|
||||
* The environment is NOT inherited from the parent process by default.
|
||||
*/
|
||||
env?: object;
|
||||
};
|
||||
/**
|
||||
* Client transport for stdio: this will connect to a server by spawning a process and communicating with it over stdin/stdout.
|
||||
*
|
||||
* This transport is only available in Node.js environments.
|
||||
*/
|
||||
export declare class StdioClientTransport implements Transport {
|
||||
private _process?;
|
||||
private _abortController;
|
||||
private _readBuffer;
|
||||
private _serverParams;
|
||||
onclose?: () => void;
|
||||
onerror?: (error: Error) => void;
|
||||
onmessage?: (message: JSONRPCMessage) => void;
|
||||
constructor(server: StdioServerParameters);
|
||||
/**
|
||||
* Starts the server process and prepares to communicate with it.
|
||||
*/
|
||||
start(): Promise<void>;
|
||||
private processReadBuffer;
|
||||
close(): Promise<void>;
|
||||
send(message: JSONRPCMessage): Promise<void>;
|
||||
}
|
||||
//# sourceMappingURL=stdio.d.ts.map
|
||||
1
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;IACnD,OAAO,CAAC,aAAa,CAAwB;IAE7C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;gBAElC,MAAM,EAAE,qBAAqB;IAIzC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyD5B,OAAO,CAAC,iBAAiB;IAenB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAc7C"}
|
||||
99
packages/mcp-typescript/dist/client/stdio.js
generated
vendored
Normal file
99
packages/mcp-typescript/dist/client/stdio.js
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { ReadBuffer, serializeMessage } from "../shared/stdio.js";
|
||||
/**
|
||||
* Client transport for stdio: this will connect to a server by spawning a process and communicating with it over stdin/stdout.
|
||||
*
|
||||
* This transport is only available in Node.js environments.
|
||||
*/
|
||||
export class StdioClientTransport {
|
||||
constructor(server) {
|
||||
this._abortController = new AbortController();
|
||||
this._readBuffer = new ReadBuffer();
|
||||
this._serverParams = server;
|
||||
}
|
||||
/**
|
||||
* Starts the server process and prepares to communicate with it.
|
||||
*/
|
||||
async start() {
|
||||
if (this._process) {
|
||||
throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
var _a, _b, _c, _d;
|
||||
this._process = spawn(this._serverParams.command, (_a = this._serverParams.args) !== null && _a !== void 0 ? _a : [], {
|
||||
// The parent process may have sensitive secrets in its env, so don't inherit it automatically.
|
||||
env: this._serverParams.env === undefined
|
||||
? {}
|
||||
: { ...this._serverParams.env },
|
||||
stdio: ["pipe", "pipe", "inherit"],
|
||||
signal: this._abortController.signal,
|
||||
});
|
||||
this._process.on("error", (error) => {
|
||||
var _a, _b;
|
||||
if (error.name === "AbortError") {
|
||||
// Expected when close() is called.
|
||||
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
||||
return;
|
||||
}
|
||||
reject(error);
|
||||
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
|
||||
});
|
||||
this._process.on("spawn", () => {
|
||||
resolve();
|
||||
});
|
||||
this._process.on("close", (_code) => {
|
||||
var _a;
|
||||
this._process = undefined;
|
||||
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
||||
});
|
||||
(_b = this._process.stdin) === null || _b === void 0 ? void 0 : _b.on("error", (error) => {
|
||||
var _a;
|
||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
||||
});
|
||||
(_c = this._process.stdout) === null || _c === void 0 ? void 0 : _c.on("data", (chunk) => {
|
||||
this._readBuffer.append(chunk);
|
||||
this.processReadBuffer();
|
||||
});
|
||||
(_d = this._process.stdout) === null || _d === void 0 ? void 0 : _d.on("error", (error) => {
|
||||
var _a;
|
||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
||||
});
|
||||
});
|
||||
}
|
||||
processReadBuffer() {
|
||||
var _a, _b;
|
||||
while (true) {
|
||||
try {
|
||||
const message = this._readBuffer.readMessage();
|
||||
if (message === null) {
|
||||
break;
|
||||
}
|
||||
(_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, message);
|
||||
}
|
||||
catch (error) {
|
||||
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
async close() {
|
||||
this._abortController.abort();
|
||||
this._process = undefined;
|
||||
this._readBuffer.clear();
|
||||
}
|
||||
send(message) {
|
||||
return new Promise((resolve) => {
|
||||
var _a;
|
||||
if (!((_a = this._process) === null || _a === void 0 ? void 0 : _a.stdin)) {
|
||||
throw new Error("Not connected");
|
||||
}
|
||||
const json = serializeMessage(message);
|
||||
if (this._process.stdin.write(json)) {
|
||||
resolve();
|
||||
}
|
||||
else {
|
||||
this._process.stdin.once("drain", resolve);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=stdio.js.map
|
||||
1
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(serverParameters);
|
||||
client.onerror = (error) => {
|
||||
throw error;
|
||||
};
|
||||
let didClose = false;
|
||||
client.onclose = () => {
|
||||
didClose = true;
|
||||
};
|
||||
await client.start();
|
||||
expect(didClose).toBeFalsy();
|
||||
await client.close();
|
||||
expect(didClose).toBeTruthy();
|
||||
});
|
||||
test("should read messages", async () => {
|
||||
const client = new StdioClientTransport(serverParameters);
|
||||
client.onerror = (error) => {
|
||||
throw error;
|
||||
};
|
||||
const messages = [
|
||||
{
|
||||
jsonrpc: "2.0",
|
||||
id: 1,
|
||||
method: "ping",
|
||||
},
|
||||
{
|
||||
jsonrpc: "2.0",
|
||||
method: "notifications/initialized",
|
||||
},
|
||||
];
|
||||
const readMessages = [];
|
||||
const finished = new Promise((resolve) => {
|
||||
client.onmessage = (message) => {
|
||||
readMessages.push(message);
|
||||
if (JSON.stringify(message) === JSON.stringify(messages[1])) {
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
});
|
||||
await client.start();
|
||||
await client.send(messages[0]);
|
||||
await client.send(messages[1]);
|
||||
await finished;
|
||||
expect(readMessages).toEqual(messages);
|
||||
await client.close();
|
||||
});
|
||||
//# sourceMappingURL=stdio.test.js.map
|
||||
1
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,CAAC,gBAAgB,CAAC,CAAC;IAC1D,MAAM,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE;QACzB,MAAM,KAAK,CAAC;IACd,CAAC,CAAC;IAEF,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE;QACpB,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC,CAAC;IAEF,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,CAAC;IAC7B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,EAAE,CAAC;AAChC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;IACtC,MAAM,MAAM,GAAG,IAAI,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IAC1D,MAAM,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE;QACzB,MAAM,KAAK,CAAC;IACd,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAqB;QACjC;YACE,OAAO,EAAE,KAAK;YACd,EAAE,EAAE,CAAC;YACL,MAAM,EAAE,MAAM;SACf;QACD;YACE,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,2BAA2B;SACpC;KACF,CAAC;IAEF,MAAM,YAAY,GAAqB,EAAE,CAAC;IAC1C,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAC7C,MAAM,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,EAAE;YAC7B,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE3B,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5D,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,QAAQ,CAAC;IACf,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEvC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
||||
17
packages/mcp-typescript/dist/client/websocket.d.ts
generated
vendored
Normal file
17
packages/mcp-typescript/dist/client/websocket.d.ts
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Transport } from "../shared/transport.js";
|
||||
import { JSONRPCMessage } from "../types.js";
|
||||
/**
|
||||
* Client transport for WebSocket: this will connect to a server over the WebSocket protocol.
|
||||
*/
|
||||
export declare class WebSocketClientTransport implements Transport {
|
||||
private _socket?;
|
||||
private _url;
|
||||
onclose?: () => void;
|
||||
onerror?: (error: Error) => void;
|
||||
onmessage?: (message: JSONRPCMessage) => void;
|
||||
constructor(url: URL);
|
||||
start(): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
send(message: JSONRPCMessage): Promise<void>;
|
||||
}
|
||||
//# sourceMappingURL=websocket.d.ts.map
|
||||
1
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;IAC5B,OAAO,CAAC,IAAI,CAAM;IAElB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;gBAElC,GAAG,EAAE,GAAG;IAIpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyChB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAW7C"}
|
||||
61
packages/mcp-typescript/dist/client/websocket.js
generated
vendored
Normal file
61
packages/mcp-typescript/dist/client/websocket.js
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
import { JSONRPCMessageSchema } from "../types.js";
|
||||
const SUBPROTOCOL = "mcp";
|
||||
/**
|
||||
* Client transport for WebSocket: this will connect to a server over the WebSocket protocol.
|
||||
*/
|
||||
export class WebSocketClientTransport {
|
||||
constructor(url) {
|
||||
this._url = url;
|
||||
}
|
||||
start() {
|
||||
if (this._socket) {
|
||||
throw new Error("WebSocketClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
this._socket = new WebSocket(this._url, SUBPROTOCOL);
|
||||
this._socket.onerror = (event) => {
|
||||
var _a;
|
||||
const error = "error" in event
|
||||
? event.error
|
||||
: new Error(`WebSocket error: ${JSON.stringify(event)}`);
|
||||
reject(error);
|
||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
||||
};
|
||||
this._socket.onopen = () => {
|
||||
resolve();
|
||||
};
|
||||
this._socket.onclose = () => {
|
||||
var _a;
|
||||
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
||||
};
|
||||
this._socket.onmessage = (event) => {
|
||||
var _a, _b;
|
||||
let message;
|
||||
try {
|
||||
message = JSONRPCMessageSchema.parse(JSON.parse(event.data));
|
||||
}
|
||||
catch (error) {
|
||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
||||
return;
|
||||
}
|
||||
(_b = this.onmessage) === null || _b === void 0 ? void 0 : _b.call(this, message);
|
||||
};
|
||||
});
|
||||
}
|
||||
async close() {
|
||||
var _a;
|
||||
(_a = this._socket) === null || _a === void 0 ? void 0 : _a.close();
|
||||
}
|
||||
send(message) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var _a;
|
||||
if (!this._socket) {
|
||||
reject(new Error("Not connected"));
|
||||
return;
|
||||
}
|
||||
(_a = this._socket) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify(message));
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=websocket.js.map
|
||||
1
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;IAQnC,YAAY,GAAQ;QAClB,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;IAClB,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,mHAAmH,CACpH,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,OAAO,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;YAErD,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE;;gBAC/B,MAAM,KAAK,GACT,OAAO,IAAI,KAAK;oBACd,CAAC,CAAE,KAAK,CAAC,KAAe;oBACxB,CAAC,CAAC,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC7D,MAAM,CAAC,KAAK,CAAC,CAAC;gBACd,MAAA,IAAI,CAAC,OAAO,qDAAG,KAAK,CAAC,CAAC;YACxB,CAAC,CAAC;YAEF,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,EAAE;gBACzB,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC;YAEF,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,GAAG,EAAE;;gBAC1B,MAAA,IAAI,CAAC,OAAO,oDAAI,CAAC;YACnB,CAAC,CAAC;YAEF,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,KAAmB,EAAE,EAAE;;gBAC/C,IAAI,OAAuB,CAAC;gBAC5B,IAAI,CAAC;oBACH,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC/D,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAA,IAAI,CAAC,OAAO,qDAAG,KAAc,CAAC,CAAC;oBAC/B,OAAO;gBACT,CAAC;gBAED,MAAA,IAAI,CAAC,SAAS,qDAAG,OAAO,CAAC,CAAC;YAC5B,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,KAAK;;QACT,MAAA,IAAI,CAAC,OAAO,0CAAE,KAAK,EAAE,CAAC;IACxB,CAAC;IAED,IAAI,CAAC,OAAuB;QAC1B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;;YACrC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClB,MAAM,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;gBACnC,OAAO;YACT,CAAC;YAED,MAAA,IAAI,CAAC,OAAO,0CAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;YAC5C,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
||||
32
packages/mcp-typescript/dist/server/index.d.ts
generated
vendored
Normal file
32
packages/mcp-typescript/dist/server/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Protocol } from "../shared/protocol.js";
|
||||
import { ClientCapabilities, Implementation, ServerNotification, ServerRequest, ServerResult } from "../types.js";
|
||||
/**
|
||||
* An MCP server on top of a pluggable transport.
|
||||
*
|
||||
* This server will automatically respond to the initialization flow as initiated from the client.
|
||||
*/
|
||||
export declare class Server extends Protocol<ServerRequest, ServerNotification, ServerResult> {
|
||||
private _serverInfo;
|
||||
private _clientCapabilities?;
|
||||
private _clientVersion?;
|
||||
/**
|
||||
* Callback for when initialization has fully completed (i.e., the client has sent an `initialized` notification).
|
||||
*/
|
||||
oninitialized?: () => void;
|
||||
/**
|
||||
* Initializes this server with the given name and version information.
|
||||
*/
|
||||
constructor(_serverInfo: Implementation);
|
||||
private _oninitialize;
|
||||
/**
|
||||
* After initialization has completed, this will be populated with the client's reported capabilities.
|
||||
*/
|
||||
getClientCapabilities(): ClientCapabilities | undefined;
|
||||
/**
|
||||
* After initialization has completed, this will be populated with information about the client's name and version.
|
||||
*/
|
||||
getClientVersion(): Implementation | undefined;
|
||||
private getCapability;
|
||||
private getCapabilities;
|
||||
}
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
1
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,EAElB,cAAc,EAMd,kBAAkB,EAClB,aAAa,EACb,YAAY,EAMb,MAAM,aAAa,CAAC;AAErB;;;;GAIG;AACH,qBAAa,MAAO,SAAQ,QAAQ,CAClC,aAAa,EACb,kBAAkB,EAClB,YAAY,CACb;IAYa,OAAO,CAAC,WAAW;IAX/B,OAAO,CAAC,mBAAmB,CAAC,CAAqB;IACjD,OAAO,CAAC,cAAc,CAAC,CAAiB;IAExC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAE3B;;OAEG;gBACiB,WAAW,EAAE,cAAc;YAWjC,aAAa;IAmB3B;;OAEG;IACH,qBAAqB,IAAI,kBAAkB,GAAG,SAAS;IAIvD;;OAEG;IACH,gBAAgB,IAAI,cAAc,GAAG,SAAS;IAI9C,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,eAAe;CAUxB"}
|
||||
54
packages/mcp-typescript/dist/server/index.js
generated
vendored
Normal file
54
packages/mcp-typescript/dist/server/index.js
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
import { Protocol } from "../shared/protocol.js";
|
||||
import { InitializedNotificationSchema, InitializeRequestSchema, PROTOCOL_VERSION, ListResourcesRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, SetLevelRequestSchema, } from "../types.js";
|
||||
/**
|
||||
* An MCP server on top of a pluggable transport.
|
||||
*
|
||||
* This server will automatically respond to the initialization flow as initiated from the client.
|
||||
*/
|
||||
export class Server extends Protocol {
|
||||
/**
|
||||
* Initializes this server with the given name and version information.
|
||||
*/
|
||||
constructor(_serverInfo) {
|
||||
super();
|
||||
this._serverInfo = _serverInfo;
|
||||
this.setRequestHandler(InitializeRequestSchema, (request) => this._oninitialize(request));
|
||||
this.setNotificationHandler(InitializedNotificationSchema, () => { var _a; return (_a = this.oninitialized) === null || _a === void 0 ? void 0 : _a.call(this); });
|
||||
}
|
||||
async _oninitialize(request) {
|
||||
if (request.params.protocolVersion !== PROTOCOL_VERSION) {
|
||||
throw new Error(`Client's protocol version is not supported: ${request.params.protocolVersion}`);
|
||||
}
|
||||
this._clientCapabilities = request.params.capabilities;
|
||||
this._clientVersion = request.params.clientInfo;
|
||||
return {
|
||||
protocolVersion: PROTOCOL_VERSION,
|
||||
capabilities: this.getCapabilities(),
|
||||
serverInfo: this._serverInfo,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* After initialization has completed, this will be populated with the client's reported capabilities.
|
||||
*/
|
||||
getClientCapabilities() {
|
||||
return this._clientCapabilities;
|
||||
}
|
||||
/**
|
||||
* After initialization has completed, this will be populated with information about the client's name and version.
|
||||
*/
|
||||
getClientVersion() {
|
||||
return this._clientVersion;
|
||||
}
|
||||
getCapability(reqType) {
|
||||
return this._requestHandlers.has(reqType) ? {} : undefined;
|
||||
}
|
||||
getCapabilities() {
|
||||
return {
|
||||
prompts: this.getCapability(ListPromptsRequestSchema.shape.method.value),
|
||||
resources: this.getCapability(ListResourcesRequestSchema.shape.method.value),
|
||||
tools: this.getCapability(ListToolsRequestSchema.shape.method.value),
|
||||
logging: this.getCapability(SetLevelRequestSchema.shape.method.value),
|
||||
};
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
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,EAIL,6BAA6B,EAE7B,uBAAuB,EAEvB,gBAAgB,EAKhB,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAErB;;;;GAIG;AACH,MAAM,OAAO,MAAO,SAAQ,QAI3B;IASC;;OAEG;IACH,YAAoB,WAA2B;QAC7C,KAAK,EAAE,CAAC;QADU,gBAAW,GAAX,WAAW,CAAgB;QAG7C,IAAI,CAAC,iBAAiB,CAAC,uBAAuB,EAAE,CAAC,OAAO,EAAE,EAAE,CAC1D,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAC5B,CAAC;QACF,IAAI,CAAC,sBAAsB,CAAC,6BAA6B,EAAE,GAAG,EAAE,WAC9D,OAAA,MAAA,IAAI,CAAC,aAAa,oDAAI,CAAA,EAAA,CACvB,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,aAAa,CACzB,OAA0B;QAE1B,IAAI,OAAO,CAAC,MAAM,CAAC,eAAe,KAAK,gBAAgB,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CACb,+CAA+C,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,CAChF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC;QACvD,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC;QAEhD,OAAO;YACL,eAAe,EAAE,gBAAgB;YACjC,YAAY,EAAE,IAAI,CAAC,eAAe,EAAE;YACpC,UAAU,EAAE,IAAI,CAAC,WAAW;SAC7B,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,qBAAqB;QACnB,OAAO,IAAI,CAAC,mBAAmB,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,gBAAgB;QACd,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAEO,aAAa,CACnB,OAAgC;QAEhC,OAAO,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACvE,CAAC;IAEO,eAAe;QACrB,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,wBAAwB,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;YACxE,SAAS,EAAE,IAAI,CAAC,aAAa,CAC3B,0BAA0B,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAC9C;YACD,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,sBAAsB,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;YACpE,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,qBAAqB,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;SACtE,CAAC;IACJ,CAAC;CACF"}
|
||||
46
packages/mcp-typescript/dist/server/sse.d.ts
generated
vendored
Normal file
46
packages/mcp-typescript/dist/server/sse.d.ts
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
import { IncomingMessage, ServerResponse } from "node:http";
|
||||
import { Transport } from "../shared/transport.js";
|
||||
import { JSONRPCMessage } from "../types.js";
|
||||
/**
|
||||
* Server transport for SSE: this will send messages over an SSE connection and receive messages from HTTP POST requests.
|
||||
*
|
||||
* This transport is only available in Node.js environments.
|
||||
*/
|
||||
export declare class SSEServerTransport implements Transport {
|
||||
private _endpoint;
|
||||
private res;
|
||||
private _sseResponse?;
|
||||
private _sessionId;
|
||||
onclose?: () => void;
|
||||
onerror?: (error: Error) => void;
|
||||
onmessage?: (message: JSONRPCMessage) => void;
|
||||
/**
|
||||
* Creates a new SSE server transport, which will direct the client to POST messages to the relative or absolute URL identified by `_endpoint`.
|
||||
*/
|
||||
constructor(_endpoint: string, res: ServerResponse);
|
||||
/**
|
||||
* Handles the initial SSE connection request.
|
||||
*
|
||||
* This should be called when a GET request is made to establish the SSE stream.
|
||||
*/
|
||||
start(): Promise<void>;
|
||||
/**
|
||||
* Handles incoming POST messages.
|
||||
*
|
||||
* This should be called when a POST request is made to send a message to the server.
|
||||
*/
|
||||
handlePostMessage(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
||||
/**
|
||||
* Handle a client message, regardless of how it arrived. This can be used to inform the server of messages that arrive via a means different than HTTP POST.
|
||||
*/
|
||||
handleMessage(message: unknown): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
send(message: JSONRPCMessage): Promise<void>;
|
||||
/**
|
||||
* Returns the session ID for this transport.
|
||||
*
|
||||
* This can be used to route incoming POST requests.
|
||||
*/
|
||||
get sessionId(): string;
|
||||
}
|
||||
//# sourceMappingURL=sse.d.ts.map
|
||||
1
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;IAYhD,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,GAAG;IAZb,OAAO,CAAC,YAAY,CAAC,CAAiB;IACtC,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAE9C;;OAEG;gBAEO,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,cAAc;IAK7B;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB5B;;;;OAIG;IACG,iBAAiB,CACrB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC;IAkChB;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAY9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlD;;;;OAIG;IACH,IAAI,SAAS,IAAI,MAAM,CAEtB;CACF"}
|
||||
116
packages/mcp-typescript/dist/server/sse.js
generated
vendored
Normal file
116
packages/mcp-typescript/dist/server/sse.js
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { JSONRPCMessageSchema } from "../types.js";
|
||||
import getRawBody from "raw-body";
|
||||
import contentType from "content-type";
|
||||
const MAXIMUM_MESSAGE_SIZE = "4mb";
|
||||
/**
|
||||
* Server transport for SSE: this will send messages over an SSE connection and receive messages from HTTP POST requests.
|
||||
*
|
||||
* This transport is only available in Node.js environments.
|
||||
*/
|
||||
export class SSEServerTransport {
|
||||
/**
|
||||
* Creates a new SSE server transport, which will direct the client to POST messages to the relative or absolute URL identified by `_endpoint`.
|
||||
*/
|
||||
constructor(_endpoint, res) {
|
||||
this._endpoint = _endpoint;
|
||||
this.res = res;
|
||||
this._sessionId = randomUUID();
|
||||
}
|
||||
/**
|
||||
* Handles the initial SSE connection request.
|
||||
*
|
||||
* This should be called when a GET request is made to establish the SSE stream.
|
||||
*/
|
||||
async start() {
|
||||
if (this._sseResponse) {
|
||||
throw new Error("SSEServerTransport already started! If using Server class, note that connect() calls start() automatically.");
|
||||
}
|
||||
this.res.writeHead(200, {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
Connection: "keep-alive",
|
||||
});
|
||||
// Send the endpoint event
|
||||
this.res.write(`event: endpoint\ndata: ${encodeURI(this._endpoint)}?sessionId=${this._sessionId}\n\n`);
|
||||
this._sseResponse = this.res;
|
||||
this.res.on("close", () => {
|
||||
var _a;
|
||||
this._sseResponse = undefined;
|
||||
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Handles incoming POST messages.
|
||||
*
|
||||
* This should be called when a POST request is made to send a message to the server.
|
||||
*/
|
||||
async handlePostMessage(req, res) {
|
||||
var _a, _b, _c;
|
||||
if (!this._sseResponse) {
|
||||
const message = "SSE connection not established";
|
||||
res.writeHead(500).end(message);
|
||||
throw new Error(message);
|
||||
}
|
||||
let body;
|
||||
try {
|
||||
const ct = contentType.parse((_a = req.headers["content-type"]) !== null && _a !== void 0 ? _a : "");
|
||||
if (ct.type !== "application/json") {
|
||||
throw new Error(`Unsupported content-type: ${ct}`);
|
||||
}
|
||||
body = await getRawBody(req, {
|
||||
limit: MAXIMUM_MESSAGE_SIZE,
|
||||
encoding: (_b = ct.parameters.charset) !== null && _b !== void 0 ? _b : "utf-8",
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
res.writeHead(400).end(String(error));
|
||||
(_c = this.onerror) === null || _c === void 0 ? void 0 : _c.call(this, error);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await this.handleMessage(JSON.parse(body));
|
||||
}
|
||||
catch (_d) {
|
||||
res.writeHead(400).end(`Invalid message: ${body}`);
|
||||
return;
|
||||
}
|
||||
res.writeHead(202).end("Accepted");
|
||||
}
|
||||
/**
|
||||
* Handle a client message, regardless of how it arrived. This can be used to inform the server of messages that arrive via a means different than HTTP POST.
|
||||
*/
|
||||
async handleMessage(message) {
|
||||
var _a, _b;
|
||||
let parsedMessage;
|
||||
try {
|
||||
parsedMessage = JSONRPCMessageSchema.parse(message);
|
||||
}
|
||||
catch (error) {
|
||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
||||
throw error;
|
||||
}
|
||||
(_b = this.onmessage) === null || _b === void 0 ? void 0 : _b.call(this, parsedMessage);
|
||||
}
|
||||
async close() {
|
||||
var _a, _b;
|
||||
(_a = this._sseResponse) === null || _a === void 0 ? void 0 : _a.end();
|
||||
this._sseResponse = undefined;
|
||||
(_b = this.onclose) === null || _b === void 0 ? void 0 : _b.call(this);
|
||||
}
|
||||
async send(message) {
|
||||
if (!this._sseResponse) {
|
||||
throw new Error("Not connected");
|
||||
}
|
||||
this._sseResponse.write(`event: message\ndata: ${JSON.stringify(message)}\n\n`);
|
||||
}
|
||||
/**
|
||||
* Returns the session ID for this transport.
|
||||
*
|
||||
* This can be used to route incoming POST requests.
|
||||
*/
|
||||
get sessionId() {
|
||||
return this._sessionId;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=sse.js.map
|
||||
1
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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"}
|
||||
28
packages/mcp-typescript/dist/server/stdio.d.ts
generated
vendored
Normal file
28
packages/mcp-typescript/dist/server/stdio.d.ts
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Readable, Writable } from "node:stream";
|
||||
import { JSONRPCMessage } from "../types.js";
|
||||
import { Transport } from "../shared/transport.js";
|
||||
/**
|
||||
* Server transport for stdio: this communicates with a MCP client by reading from the current process' stdin and writing to stdout.
|
||||
*
|
||||
* This transport is only available in Node.js environments.
|
||||
*/
|
||||
export declare class StdioServerTransport implements Transport {
|
||||
private _stdin;
|
||||
private _stdout;
|
||||
private _readBuffer;
|
||||
private _started;
|
||||
constructor(_stdin?: Readable, _stdout?: Writable);
|
||||
onclose?: () => void;
|
||||
onerror?: (error: Error) => void;
|
||||
onmessage?: (message: JSONRPCMessage) => void;
|
||||
_ondata: (chunk: Buffer) => void;
|
||||
_onerror: (error: Error) => void;
|
||||
/**
|
||||
* Starts listening for messages on stdin.
|
||||
*/
|
||||
start(): Promise<void>;
|
||||
private processReadBuffer;
|
||||
close(): Promise<void>;
|
||||
send(message: JSONRPCMessage): Promise<void>;
|
||||
}
|
||||
//# sourceMappingURL=stdio.d.ts.map
|
||||
1
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;IAKlD,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,OAAO;IALjB,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,QAAQ,CAAS;gBAGf,MAAM,GAAE,QAAwB,EAChC,OAAO,GAAE,QAAyB;IAG5C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAG9C,OAAO,UAAW,MAAM,UAGtB;IACF,QAAQ,UAAW,KAAK,UAEtB;IAEF;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B,OAAO,CAAC,iBAAiB;IAenB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAU7C"}
|
||||
69
packages/mcp-typescript/dist/server/stdio.js
generated
vendored
Normal file
69
packages/mcp-typescript/dist/server/stdio.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
import process from "node:process";
|
||||
import { ReadBuffer, serializeMessage } from "../shared/stdio.js";
|
||||
/**
|
||||
* Server transport for stdio: this communicates with a MCP client by reading from the current process' stdin and writing to stdout.
|
||||
*
|
||||
* This transport is only available in Node.js environments.
|
||||
*/
|
||||
export class StdioServerTransport {
|
||||
constructor(_stdin = process.stdin, _stdout = process.stdout) {
|
||||
this._stdin = _stdin;
|
||||
this._stdout = _stdout;
|
||||
this._readBuffer = new ReadBuffer();
|
||||
this._started = false;
|
||||
// Arrow functions to bind `this` properly, while maintaining function identity.
|
||||
this._ondata = (chunk) => {
|
||||
this._readBuffer.append(chunk);
|
||||
this.processReadBuffer();
|
||||
};
|
||||
this._onerror = (error) => {
|
||||
var _a;
|
||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Starts listening for messages on stdin.
|
||||
*/
|
||||
async start() {
|
||||
if (this._started) {
|
||||
throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
|
||||
}
|
||||
this._started = true;
|
||||
this._stdin.on("data", this._ondata);
|
||||
this._stdin.on("error", this._onerror);
|
||||
}
|
||||
processReadBuffer() {
|
||||
var _a, _b;
|
||||
while (true) {
|
||||
try {
|
||||
const message = this._readBuffer.readMessage();
|
||||
if (message === null) {
|
||||
break;
|
||||
}
|
||||
(_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, message);
|
||||
}
|
||||
catch (error) {
|
||||
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
async close() {
|
||||
var _a;
|
||||
this._stdin.off("data", this._ondata);
|
||||
this._stdin.off("error", this._onerror);
|
||||
this._readBuffer.clear();
|
||||
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
||||
}
|
||||
send(message) {
|
||||
return new Promise((resolve) => {
|
||||
const json = serializeMessage(message);
|
||||
if (this._stdout.write(json)) {
|
||||
resolve();
|
||||
}
|
||||
else {
|
||||
this._stdout.once("drain", resolve);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=stdio.js.map
|
||||
1
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;IAI/B,YACU,SAAmB,OAAO,CAAC,KAAK,EAChC,UAAoB,OAAO,CAAC,MAAM;QADlC,WAAM,GAAN,MAAM,CAA0B;QAChC,YAAO,GAAP,OAAO,CAA2B;QALpC,gBAAW,GAAe,IAAI,UAAU,EAAE,CAAC;QAC3C,aAAQ,GAAG,KAAK,CAAC;QAWzB,gFAAgF;QAChF,YAAO,GAAG,CAAC,KAAa,EAAE,EAAE;YAC1B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC/B,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,CAAC,CAAC;QACF,aAAQ,GAAG,CAAC,KAAY,EAAE,EAAE;;YAC1B,MAAA,IAAI,CAAC,OAAO,qDAAG,KAAK,CAAC,CAAC;QACxB,CAAC,CAAC;IAbC,CAAC;IAeJ;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CACb,+GAA+G,CAChH,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzC,CAAC;IAEO,iBAAiB;;QACvB,OAAO,IAAI,EAAE,CAAC;YACZ,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;gBAC/C,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;oBACrB,MAAM;gBACR,CAAC;gBAED,MAAA,IAAI,CAAC,SAAS,qDAAG,OAAO,CAAC,CAAC;YAC5B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAA,IAAI,CAAC,OAAO,qDAAG,KAAc,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;;QACT,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QACzB,MAAA,IAAI,CAAC,OAAO,oDAAI,CAAC;IACnB,CAAC;IAED,IAAI,CAAC,OAAuB;QAC1B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7B,OAAO,EAAE,CAAC;YACZ,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACtC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
||||
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 { JSONRPCRequest, Notification, Progress, Request, Result } from "../types.js";
|
||||
import { Transport } from "./transport.js";
|
||||
/**
|
||||
* Callback for progress notifications.
|
||||
*/
|
||||
export type ProgressCallback = (progress: Progress) => void;
|
||||
/**
|
||||
* Implements MCP protocol framing on top of a pluggable transport, including
|
||||
* features like request/response linking, notifications, and progress.
|
||||
*/
|
||||
export declare class Protocol<SendRequestT extends Request, SendNotificationT extends Notification, SendResultT extends Result> {
|
||||
private _transport?;
|
||||
private _requestMessageId;
|
||||
protected _requestHandlers: Map<string, (request: JSONRPCRequest) => Promise<SendResultT>>;
|
||||
private _notificationHandlers;
|
||||
private _responseHandlers;
|
||||
private _progressHandlers;
|
||||
/**
|
||||
* Callback for when the connection is closed for any reason.
|
||||
*
|
||||
* This is invoked when close() is called as well.
|
||||
*/
|
||||
onclose?: () => void;
|
||||
/**
|
||||
* Callback for when an error occurs.
|
||||
*
|
||||
* Note that errors are not necessarily fatal; they are used for reporting any kind of exceptional condition out of band.
|
||||
*/
|
||||
onerror?: (error: Error) => void;
|
||||
/**
|
||||
* A handler to invoke for any request types that do not have their own handler installed.
|
||||
*/
|
||||
fallbackRequestHandler?: (request: Request) => Promise<SendResultT>;
|
||||
/**
|
||||
* A handler to invoke for any notification types that do not have their own handler installed.
|
||||
*/
|
||||
fallbackNotificationHandler?: (notification: Notification) => Promise<void>;
|
||||
constructor();
|
||||
/**
|
||||
* Attaches to the given transport, starts it, and starts listening for messages.
|
||||
*
|
||||
* The Protocol object assumes ownership of the Transport, replacing any callbacks that have already been set, and expects that it is the only user of the Transport instance going forward.
|
||||
*/
|
||||
connect(transport: Transport): Promise<void>;
|
||||
private _onclose;
|
||||
private _onerror;
|
||||
private _onnotification;
|
||||
private _onrequest;
|
||||
private _onprogress;
|
||||
private _onresponse;
|
||||
get transport(): Transport | undefined;
|
||||
/**
|
||||
* Closes the connection.
|
||||
*/
|
||||
close(): Promise<void>;
|
||||
/**
|
||||
* Sends a request and wait for a response, with optional progress notifications in the meantime (if supported by the server).
|
||||
*
|
||||
* Do not use this method to emit notifications! Use notification() instead.
|
||||
*/
|
||||
request<T extends AnyZodObject>(request: SendRequestT, resultSchema: T, onprogress?: ProgressCallback): Promise<z.infer<T>>;
|
||||
/**
|
||||
* Emits a notification, which is a one-way message that does not expect a response.
|
||||
*/
|
||||
notification(notification: SendNotificationT): Promise<void>;
|
||||
/**
|
||||
* Registers a handler to invoke when this protocol object receives a request with the given method.
|
||||
*
|
||||
* Note that this will replace any previous request handler for the same method.
|
||||
*/
|
||||
setRequestHandler<T extends ZodObject<{
|
||||
method: ZodLiteral<string>;
|
||||
}>>(requestSchema: T, handler: (request: z.infer<T>) => SendResultT | Promise<SendResultT>): void;
|
||||
/**
|
||||
* Removes the request handler for the given method.
|
||||
*/
|
||||
removeRequestHandler(method: string): void;
|
||||
/**
|
||||
* Registers a handler to invoke when this protocol object receives a notification with the given method.
|
||||
*
|
||||
* Note that this will replace any previous notification handler for the same method.
|
||||
*/
|
||||
setNotificationHandler<T extends ZodObject<{
|
||||
method: ZodLiteral<string>;
|
||||
}>>(notificationSchema: T, handler: (notification: z.infer<T>) => void | Promise<void>): void;
|
||||
/**
|
||||
* Removes the notification handler for the given method.
|
||||
*/
|
||||
removeNotificationHandler(method: string): void;
|
||||
}
|
||||
//# sourceMappingURL=protocol.d.ts.map
|
||||
1
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,EAIL,cAAc,EAGd,YAAY,EAEZ,QAAQ,EAGR,OAAO,EACP,MAAM,EACP,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;AAE5D;;;GAGG;AACH,qBAAa,QAAQ,CACnB,YAAY,SAAS,OAAO,EAC5B,iBAAiB,SAAS,YAAY,EACtC,WAAW,SAAS,MAAM;IAE1B,OAAO,CAAC,UAAU,CAAC,CAAY;IAC/B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,SAAS,CAAC,gBAAgB,EAAE,GAAG,CAC7B,MAAM,EACN,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,WAAW,CAAC,CAClD,CAAa;IACd,OAAO,CAAC,qBAAqB,CAGf;IACd,OAAO,CAAC,iBAAiB,CAGX;IACd,OAAO,CAAC,iBAAiB,CAA4C;IAErE;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC;;OAEG;IACH,sBAAsB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAEpE;;OAEG;IACH,2BAA2B,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;;IAc5E;;;;OAIG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBlD,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,UAAU;IAiDlB,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,WAAW;IA0BnB,IAAI,SAAS,IAAI,SAAS,GAAG,SAAS,CAErC;IAED;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;;;OAIG;IACH,OAAO,CAAC,CAAC,SAAS,YAAY,EAC5B,OAAO,EAAE,YAAY,EACrB,YAAY,EAAE,CAAC,EACf,UAAU,CAAC,EAAE,gBAAgB,GAC5B,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAuCtB;;OAEG;IACG,YAAY,CAAC,YAAY,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAalE;;;;OAIG;IACH,iBAAiB,CACf,CAAC,SAAS,SAAS,CAAC;QAClB,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;KAC5B,CAAC,EAEF,aAAa,EAAE,CAAC,EAChB,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,GACnE,IAAI;IAMP;;OAEG;IACH,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI1C;;;;OAIG;IACH,sBAAsB,CACpB,CAAC,SAAS,SAAS,CAAC;QAClB,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;KAC5B,CAAC,EAEF,kBAAkB,EAAE,CAAC,EACrB,OAAO,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAC1D,IAAI;IAQP;;OAEG;IACH,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAGhD"}
|
||||
225
packages/mcp-typescript/dist/shared/protocol.js
generated
vendored
Normal file
225
packages/mcp-typescript/dist/shared/protocol.js
generated
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
import { ErrorCode, McpError, PingRequestSchema, ProgressNotificationSchema, } from "../types.js";
|
||||
/**
|
||||
* Implements MCP protocol framing on top of a pluggable transport, including
|
||||
* features like request/response linking, notifications, and progress.
|
||||
*/
|
||||
export class Protocol {
|
||||
constructor() {
|
||||
this._requestMessageId = 0;
|
||||
this._requestHandlers = new Map();
|
||||
this._notificationHandlers = new Map();
|
||||
this._responseHandlers = new Map();
|
||||
this._progressHandlers = new Map();
|
||||
this.setNotificationHandler(ProgressNotificationSchema, (notification) => {
|
||||
this._onprogress(notification);
|
||||
});
|
||||
this.setRequestHandler(PingRequestSchema,
|
||||
// Automatic pong by default.
|
||||
(_request) => ({}));
|
||||
}
|
||||
/**
|
||||
* Attaches to the given transport, starts it, and starts listening for messages.
|
||||
*
|
||||
* The Protocol object assumes ownership of the Transport, replacing any callbacks that have already been set, and expects that it is the only user of the Transport instance going forward.
|
||||
*/
|
||||
async connect(transport) {
|
||||
this._transport = transport;
|
||||
this._transport.onclose = () => {
|
||||
this._onclose();
|
||||
};
|
||||
this._transport.onerror = (error) => {
|
||||
this._onerror(error);
|
||||
};
|
||||
this._transport.onmessage = (message) => {
|
||||
if (!("method" in message)) {
|
||||
this._onresponse(message);
|
||||
}
|
||||
else if ("id" in message) {
|
||||
this._onrequest(message);
|
||||
}
|
||||
else {
|
||||
this._onnotification(message);
|
||||
}
|
||||
};
|
||||
await this._transport.start();
|
||||
}
|
||||
_onclose() {
|
||||
var _a;
|
||||
const responseHandlers = this._responseHandlers;
|
||||
this._responseHandlers = new Map();
|
||||
this._progressHandlers.clear();
|
||||
this._transport = undefined;
|
||||
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
||||
const error = new McpError(ErrorCode.ConnectionClosed, "Connection closed");
|
||||
for (const handler of responseHandlers.values()) {
|
||||
handler(error);
|
||||
}
|
||||
}
|
||||
_onerror(error) {
|
||||
var _a;
|
||||
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
||||
}
|
||||
_onnotification(notification) {
|
||||
var _a;
|
||||
const handler = (_a = this._notificationHandlers.get(notification.method)) !== null && _a !== void 0 ? _a : this.fallbackNotificationHandler;
|
||||
// Ignore notifications not being subscribed to.
|
||||
if (handler === undefined) {
|
||||
return;
|
||||
}
|
||||
handler(notification).catch((error) => this._onerror(new Error(`Uncaught error in notification handler: ${error}`)));
|
||||
}
|
||||
_onrequest(request) {
|
||||
var _a, _b;
|
||||
const handler = (_a = this._requestHandlers.get(request.method)) !== null && _a !== void 0 ? _a : this.fallbackRequestHandler;
|
||||
if (handler === undefined) {
|
||||
(_b = this._transport) === null || _b === void 0 ? void 0 : _b.send({
|
||||
jsonrpc: "2.0",
|
||||
id: request.id,
|
||||
error: {
|
||||
code: ErrorCode.MethodNotFound,
|
||||
message: "Method not found",
|
||||
},
|
||||
}).catch((error) => this._onerror(new Error(`Failed to send an error response: ${error}`)));
|
||||
return;
|
||||
}
|
||||
handler(request)
|
||||
.then((result) => {
|
||||
var _a;
|
||||
(_a = this._transport) === null || _a === void 0 ? void 0 : _a.send({
|
||||
result,
|
||||
jsonrpc: "2.0",
|
||||
id: request.id,
|
||||
});
|
||||
}, (error) => {
|
||||
var _a, _b;
|
||||
return (_a = this._transport) === null || _a === void 0 ? void 0 : _a.send({
|
||||
jsonrpc: "2.0",
|
||||
id: request.id,
|
||||
error: {
|
||||
code: error["code"]
|
||||
? Math.floor(Number(error["code"]))
|
||||
: ErrorCode.InternalError,
|
||||
message: (_b = error.message) !== null && _b !== void 0 ? _b : "Internal error",
|
||||
},
|
||||
});
|
||||
})
|
||||
.catch((error) => this._onerror(new Error(`Failed to send response: ${error}`)));
|
||||
}
|
||||
_onprogress(notification) {
|
||||
const { progress, total, progressToken } = notification.params;
|
||||
const handler = this._progressHandlers.get(Number(progressToken));
|
||||
if (handler === undefined) {
|
||||
this._onerror(new Error(`Received a progress notification for an unknown token: ${JSON.stringify(notification)}`));
|
||||
return;
|
||||
}
|
||||
handler({ progress, total });
|
||||
}
|
||||
_onresponse(response) {
|
||||
const messageId = response.id;
|
||||
const handler = this._responseHandlers.get(Number(messageId));
|
||||
if (handler === undefined) {
|
||||
this._onerror(new Error(`Received a response for an unknown message ID: ${JSON.stringify(response)}`));
|
||||
return;
|
||||
}
|
||||
this._responseHandlers.delete(Number(messageId));
|
||||
this._progressHandlers.delete(Number(messageId));
|
||||
if ("result" in response) {
|
||||
handler(response);
|
||||
}
|
||||
else {
|
||||
const error = new McpError(response.error.code, response.error.message, response.error.data);
|
||||
handler(error);
|
||||
}
|
||||
}
|
||||
get transport() {
|
||||
return this._transport;
|
||||
}
|
||||
/**
|
||||
* Closes the connection.
|
||||
*/
|
||||
async close() {
|
||||
var _a;
|
||||
await ((_a = this._transport) === null || _a === void 0 ? void 0 : _a.close());
|
||||
}
|
||||
/**
|
||||
* Sends a request and wait for a response, with optional progress notifications in the meantime (if supported by the server).
|
||||
*
|
||||
* Do not use this method to emit notifications! Use notification() instead.
|
||||
*/
|
||||
request(request, resultSchema, onprogress) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._transport) {
|
||||
reject(new Error("Not connected"));
|
||||
return;
|
||||
}
|
||||
const messageId = this._requestMessageId++;
|
||||
const jsonrpcRequest = {
|
||||
...request,
|
||||
jsonrpc: "2.0",
|
||||
id: messageId,
|
||||
};
|
||||
if (onprogress) {
|
||||
this._progressHandlers.set(messageId, onprogress);
|
||||
jsonrpcRequest.params = {
|
||||
...request.params,
|
||||
_meta: { progressToken: messageId },
|
||||
};
|
||||
}
|
||||
this._responseHandlers.set(messageId, (response) => {
|
||||
if (response instanceof Error) {
|
||||
return reject(response);
|
||||
}
|
||||
try {
|
||||
const result = resultSchema.parse(response.result);
|
||||
resolve(result);
|
||||
}
|
||||
catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
this._transport.send(jsonrpcRequest).catch(reject);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Emits a notification, which is a one-way message that does not expect a response.
|
||||
*/
|
||||
async notification(notification) {
|
||||
if (!this._transport) {
|
||||
throw new Error("Not connected");
|
||||
}
|
||||
const jsonrpcNotification = {
|
||||
...notification,
|
||||
jsonrpc: "2.0",
|
||||
};
|
||||
await this._transport.send(jsonrpcNotification);
|
||||
}
|
||||
/**
|
||||
* Registers a handler to invoke when this protocol object receives a request with the given method.
|
||||
*
|
||||
* Note that this will replace any previous request handler for the same method.
|
||||
*/
|
||||
setRequestHandler(requestSchema, handler) {
|
||||
this._requestHandlers.set(requestSchema.shape.method.value, (request) => Promise.resolve(handler(requestSchema.parse(request))));
|
||||
}
|
||||
/**
|
||||
* Removes the request handler for the given method.
|
||||
*/
|
||||
removeRequestHandler(method) {
|
||||
this._requestHandlers.delete(method);
|
||||
}
|
||||
/**
|
||||
* Registers a handler to invoke when this protocol object receives a notification with the given method.
|
||||
*
|
||||
* Note that this will replace any previous notification handler for the same method.
|
||||
*/
|
||||
setNotificationHandler(notificationSchema, handler) {
|
||||
this._notificationHandlers.set(notificationSchema.shape.method.value, (notification) => Promise.resolve(handler(notificationSchema.parse(notification))));
|
||||
}
|
||||
/**
|
||||
* Removes the notification handler for the given method.
|
||||
*/
|
||||
removeNotificationHandler(method) {
|
||||
this._notificationHandlers.delete(method);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=protocol.js.map
|
||||
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":""}
|
||||
27
packages/mcp-typescript/dist/shared/stdio.test.js
generated
vendored
Normal file
27
packages/mcp-typescript/dist/shared/stdio.test.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
import { ReadBuffer } from "./stdio.js";
|
||||
const testMessage = {
|
||||
jsonrpc: "2.0",
|
||||
method: "foobar",
|
||||
};
|
||||
test("should have no messages after initialization", () => {
|
||||
const readBuffer = new ReadBuffer();
|
||||
expect(readBuffer.readMessage()).toBeNull();
|
||||
});
|
||||
test("should only yield a message after a newline", () => {
|
||||
const readBuffer = new ReadBuffer();
|
||||
readBuffer.append(Buffer.from(JSON.stringify(testMessage)));
|
||||
expect(readBuffer.readMessage()).toBeNull();
|
||||
readBuffer.append(Buffer.from("\n"));
|
||||
expect(readBuffer.readMessage()).toEqual(testMessage);
|
||||
expect(readBuffer.readMessage()).toBeNull();
|
||||
});
|
||||
test("should be reusable after clearing", () => {
|
||||
const readBuffer = new ReadBuffer();
|
||||
readBuffer.append(Buffer.from("foobar"));
|
||||
readBuffer.clear();
|
||||
expect(readBuffer.readMessage()).toBeNull();
|
||||
readBuffer.append(Buffer.from(JSON.stringify(testMessage)));
|
||||
readBuffer.append(Buffer.from("\n"));
|
||||
expect(readBuffer.readMessage()).toEqual(testMessage);
|
||||
});
|
||||
//# sourceMappingURL=stdio.test.js.map
|
||||
1
packages/mcp-typescript/dist/shared/stdio.test.js.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/shared/stdio.test.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"stdio.test.js","sourceRoot":"","sources":["../../src/shared/stdio.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,WAAW,GAAmB;IAClC,OAAO,EAAE,KAAK;IACd,MAAM,EAAE,QAAQ;CACjB,CAAC;AAEF,IAAI,CAAC,8CAA8C,EAAE,GAAG,EAAE;IACxD,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;IACpC,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC9C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6CAA6C,EAAE,GAAG,EAAE;IACvD,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;IAEpC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAE5C,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtD,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC9C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,mCAAmC,EAAE,GAAG,EAAE;IAC7C,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;IAEpC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IACzC,UAAU,CAAC,KAAK,EAAE,CAAC;IACnB,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAE5C,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAC5D,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC"}
|
||||
39
packages/mcp-typescript/dist/shared/transport.d.ts
generated
vendored
Normal file
39
packages/mcp-typescript/dist/shared/transport.d.ts
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import { JSONRPCMessage } from "../types.js";
|
||||
/**
|
||||
* Describes the minimal contract for a MCP transport that a client or server can communicate over.
|
||||
*/
|
||||
export interface Transport {
|
||||
/**
|
||||
* Starts processing messages on the transport, including any connection steps that might need to be taken.
|
||||
*
|
||||
* This method should only be called after callbacks are installed, or else messages may be lost.
|
||||
*
|
||||
* NOTE: This method should not be called explicitly when using Client, Server, or Protocol classes, as they will implicitly call start().
|
||||
*/
|
||||
start(): Promise<void>;
|
||||
/**
|
||||
* Sends a JSON-RPC message (request or response).
|
||||
*/
|
||||
send(message: JSONRPCMessage): Promise<void>;
|
||||
/**
|
||||
* Closes the connection.
|
||||
*/
|
||||
close(): Promise<void>;
|
||||
/**
|
||||
* Callback for when the connection is closed for any reason.
|
||||
*
|
||||
* This should be invoked when close() is called as well.
|
||||
*/
|
||||
onclose?: () => void;
|
||||
/**
|
||||
* Callback for when an error occurs.
|
||||
*
|
||||
* Note that errors are not necessarily fatal; they are used for reporting any kind of exceptional condition out of band.
|
||||
*/
|
||||
onerror?: (error: Error) => void;
|
||||
/**
|
||||
* Callback for when a message (request or response) is received over the connection.
|
||||
*/
|
||||
onmessage?: (message: JSONRPCMessage) => void;
|
||||
}
|
||||
//# sourceMappingURL=transport.d.ts.map
|
||||
1
packages/mcp-typescript/dist/shared/transport.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/shared/transport.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/shared/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;;OAMG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;CAC/C"}
|
||||
2
packages/mcp-typescript/dist/shared/transport.js
generated
vendored
Normal file
2
packages/mcp-typescript/dist/shared/transport.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export {};
|
||||
//# sourceMappingURL=transport.js.map
|
||||
1
packages/mcp-typescript/dist/shared/transport.js.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/shared/transport.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/shared/transport.ts"],"names":[],"mappings":""}
|
||||
10396
packages/mcp-typescript/dist/types.d.ts
generated
vendored
Normal file
10396
packages/mcp-typescript/dist/types.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
packages/mcp-typescript/dist/types.d.ts.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/types.d.ts.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
802
packages/mcp-typescript/dist/types.js
generated
vendored
Normal file
802
packages/mcp-typescript/dist/types.js
generated
vendored
Normal file
@@ -0,0 +1,802 @@
|
||||
import { z } from "zod";
|
||||
export const PROTOCOL_VERSION = "2024-10-07";
|
||||
/* JSON-RPC types */
|
||||
export const JSONRPC_VERSION = "2.0";
|
||||
/**
|
||||
* A progress token, used to associate progress notifications with the original request.
|
||||
*/
|
||||
export const ProgressTokenSchema = z.union([z.string(), z.number().int()]);
|
||||
/**
|
||||
* An opaque token used to represent a cursor for pagination.
|
||||
*/
|
||||
export const CursorSchema = z.string();
|
||||
const BaseRequestParamsSchema = z
|
||||
.object({
|
||||
_meta: z.optional(z
|
||||
.object({
|
||||
/**
|
||||
* If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications.
|
||||
*/
|
||||
progressToken: z.optional(ProgressTokenSchema),
|
||||
})
|
||||
.passthrough()),
|
||||
})
|
||||
.passthrough();
|
||||
export const RequestSchema = z.object({
|
||||
method: z.string(),
|
||||
params: z.optional(BaseRequestParamsSchema),
|
||||
});
|
||||
export const NotificationSchema = z.object({
|
||||
method: z.string(),
|
||||
params: z.optional(z
|
||||
.object({
|
||||
/**
|
||||
* This parameter name is reserved by MCP to allow clients and servers to attach additional metadata to their notifications.
|
||||
*/
|
||||
_meta: z.optional(z.object({}).passthrough()),
|
||||
})
|
||||
.passthrough()),
|
||||
});
|
||||
export const ResultSchema = z
|
||||
.object({
|
||||
/**
|
||||
* This result property is reserved by the protocol to allow clients and servers to attach additional metadata to their responses.
|
||||
*/
|
||||
_meta: z.optional(z.object({}).passthrough()),
|
||||
})
|
||||
.passthrough();
|
||||
/**
|
||||
* A uniquely identifying ID for a request in JSON-RPC.
|
||||
*/
|
||||
export const RequestIdSchema = z.union([z.string(), z.number().int()]);
|
||||
/**
|
||||
* A request that expects a response.
|
||||
*/
|
||||
export const JSONRPCRequestSchema = z
|
||||
.object({
|
||||
jsonrpc: z.literal(JSONRPC_VERSION),
|
||||
id: RequestIdSchema,
|
||||
})
|
||||
.merge(RequestSchema)
|
||||
.strict();
|
||||
/**
|
||||
* A notification which does not expect a response.
|
||||
*/
|
||||
export const JSONRPCNotificationSchema = z
|
||||
.object({
|
||||
jsonrpc: z.literal(JSONRPC_VERSION),
|
||||
})
|
||||
.merge(NotificationSchema)
|
||||
.strict();
|
||||
/**
|
||||
* A successful (non-error) response to a request.
|
||||
*/
|
||||
export const JSONRPCResponseSchema = z
|
||||
.object({
|
||||
jsonrpc: z.literal(JSONRPC_VERSION),
|
||||
id: RequestIdSchema,
|
||||
result: ResultSchema,
|
||||
})
|
||||
.strict();
|
||||
/**
|
||||
* An incomplete set of error codes that may appear in JSON-RPC responses.
|
||||
*/
|
||||
export var ErrorCode;
|
||||
(function (ErrorCode) {
|
||||
// SDK error codes
|
||||
ErrorCode[ErrorCode["ConnectionClosed"] = -1] = "ConnectionClosed";
|
||||
// Standard JSON-RPC error codes
|
||||
ErrorCode[ErrorCode["ParseError"] = -32700] = "ParseError";
|
||||
ErrorCode[ErrorCode["InvalidRequest"] = -32600] = "InvalidRequest";
|
||||
ErrorCode[ErrorCode["MethodNotFound"] = -32601] = "MethodNotFound";
|
||||
ErrorCode[ErrorCode["InvalidParams"] = -32602] = "InvalidParams";
|
||||
ErrorCode[ErrorCode["InternalError"] = -32603] = "InternalError";
|
||||
})(ErrorCode || (ErrorCode = {}));
|
||||
/**
|
||||
* A response to a request that indicates an error occurred.
|
||||
*/
|
||||
export const JSONRPCErrorSchema = z
|
||||
.object({
|
||||
jsonrpc: z.literal(JSONRPC_VERSION),
|
||||
id: RequestIdSchema,
|
||||
error: z.object({
|
||||
/**
|
||||
* The error type that occurred.
|
||||
*/
|
||||
code: z.number().int(),
|
||||
/**
|
||||
* A short description of the error. The message SHOULD be limited to a concise single sentence.
|
||||
*/
|
||||
message: z.string(),
|
||||
/**
|
||||
* Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.).
|
||||
*/
|
||||
data: z.optional(z.unknown()),
|
||||
}),
|
||||
})
|
||||
.strict();
|
||||
export const JSONRPCMessageSchema = z.union([
|
||||
JSONRPCRequestSchema,
|
||||
JSONRPCNotificationSchema,
|
||||
JSONRPCResponseSchema,
|
||||
JSONRPCErrorSchema,
|
||||
]);
|
||||
/* Empty result */
|
||||
/**
|
||||
* A response that indicates success but carries no data.
|
||||
*/
|
||||
export const EmptyResultSchema = ResultSchema.strict();
|
||||
/* Initialization */
|
||||
/**
|
||||
* Text provided to or from an LLM.
|
||||
*/
|
||||
export const TextContentSchema = z.object({
|
||||
type: z.literal("text"),
|
||||
/**
|
||||
* The text content of the message.
|
||||
*/
|
||||
text: z.string(),
|
||||
});
|
||||
/**
|
||||
* An image provided to or from an LLM.
|
||||
*/
|
||||
export const ImageContentSchema = z.object({
|
||||
type: z.literal("image"),
|
||||
/**
|
||||
* The base64-encoded image data.
|
||||
*/
|
||||
data: z.string().base64(),
|
||||
/**
|
||||
* The MIME type of the image. Different providers may support different image types.
|
||||
*/
|
||||
mimeType: z.string(),
|
||||
});
|
||||
/**
|
||||
* Describes a message issued to or received from an LLM API.
|
||||
*/
|
||||
export const SamplingMessageSchema = z.object({
|
||||
role: z.enum(["user", "assistant"]),
|
||||
content: z.union([TextContentSchema, ImageContentSchema]),
|
||||
});
|
||||
/**
|
||||
* Describes the name and version of an MCP implementation.
|
||||
*/
|
||||
export const ImplementationSchema = z.object({
|
||||
name: z.string(),
|
||||
version: z.string(),
|
||||
});
|
||||
/**
|
||||
* Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.
|
||||
*/
|
||||
export const ClientCapabilitiesSchema = z.object({
|
||||
/**
|
||||
* Experimental, non-standard capabilities that the client supports.
|
||||
*/
|
||||
experimental: z.optional(z.object({}).passthrough()),
|
||||
/**
|
||||
* Present if the client supports sampling from an LLM.
|
||||
*/
|
||||
sampling: z.optional(z.object({}).passthrough()),
|
||||
});
|
||||
/**
|
||||
* This request is sent from the client to the server when it first connects, asking it to begin initialization.
|
||||
*/
|
||||
export const InitializeRequestSchema = RequestSchema.extend({
|
||||
method: z.literal("initialize"),
|
||||
params: BaseRequestParamsSchema.extend({
|
||||
/**
|
||||
* The latest version of the Model Context Protocol that the client supports. The client MAY decide to support older versions as well.
|
||||
*/
|
||||
protocolVersion: z.string().or(z.number().int()),
|
||||
capabilities: ClientCapabilitiesSchema,
|
||||
clientInfo: ImplementationSchema,
|
||||
}),
|
||||
});
|
||||
/**
|
||||
* Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a closed set: any server can define its own, additional capabilities.
|
||||
*/
|
||||
export const ServerCapabilitiesSchema = z.object({
|
||||
/**
|
||||
* Experimental, non-standard capabilities that the server supports.
|
||||
*/
|
||||
experimental: z.optional(z.object({}).passthrough()),
|
||||
/**
|
||||
* Present if the server supports sending log messages to the client.
|
||||
*/
|
||||
logging: z.optional(z.object({}).passthrough()),
|
||||
/**
|
||||
* Present if the server offers any prompt templates.
|
||||
*/
|
||||
prompts: z.optional(z
|
||||
.object({
|
||||
/**
|
||||
* Whether this server supports notifications for changes to the prompt list.
|
||||
*/
|
||||
listChanged: z.optional(z.boolean()),
|
||||
})
|
||||
.passthrough()),
|
||||
/**
|
||||
* Present if the server offers any resources to read.
|
||||
*/
|
||||
resources: z.optional(z
|
||||
.object({
|
||||
/**
|
||||
* Whether this server supports subscribing to resource updates.
|
||||
*/
|
||||
subscribe: z.optional(z.boolean()),
|
||||
/**
|
||||
* Whether this server supports notifications for changes to the resource list.
|
||||
*/
|
||||
listChanged: z.optional(z.boolean()),
|
||||
})
|
||||
.passthrough()),
|
||||
/**
|
||||
* Present if the server offers any tools to call.
|
||||
*/
|
||||
tools: z.optional(z
|
||||
.object({
|
||||
/**
|
||||
* Whether this server supports notifications for changes to the tool list.
|
||||
*/
|
||||
listChanged: z.optional(z.boolean()),
|
||||
})
|
||||
.passthrough()),
|
||||
});
|
||||
/**
|
||||
* After receiving an initialize request from the client, the server sends this response.
|
||||
*/
|
||||
export const InitializeResultSchema = ResultSchema.extend({
|
||||
/**
|
||||
* The version of the Model Context Protocol that the server wants to use. This may not match the version that the client requested. If the client cannot support this version, it MUST disconnect.
|
||||
*/
|
||||
protocolVersion: z.string().or(z.number().int()),
|
||||
capabilities: ServerCapabilitiesSchema,
|
||||
serverInfo: ImplementationSchema,
|
||||
});
|
||||
/**
|
||||
* This notification is sent from the client to the server after initialization has finished.
|
||||
*/
|
||||
export const InitializedNotificationSchema = NotificationSchema.extend({
|
||||
method: z.literal("notifications/initialized"),
|
||||
});
|
||||
/* Ping */
|
||||
/**
|
||||
* A ping, issued by either the server or the client, to check that the other party is still alive. The receiver must promptly respond, or else may be disconnected.
|
||||
*/
|
||||
export const PingRequestSchema = RequestSchema.extend({
|
||||
method: z.literal("ping"),
|
||||
});
|
||||
/* Progress notifications */
|
||||
export const ProgressSchema = z.object({
|
||||
/**
|
||||
* The progress thus far. This should increase every time progress is made, even if the total is unknown.
|
||||
*/
|
||||
progress: z.number(),
|
||||
/**
|
||||
* Total number of items to process (or total progress required), if known.
|
||||
*/
|
||||
total: z.optional(z.number()),
|
||||
});
|
||||
/**
|
||||
* An out-of-band notification used to inform the receiver of a progress update for a long-running request.
|
||||
*/
|
||||
export const ProgressNotificationSchema = NotificationSchema.extend({
|
||||
method: z.literal("notifications/progress"),
|
||||
params: ProgressSchema.extend({
|
||||
/**
|
||||
* The progress token which was given in the initial request, used to associate this notification with the request that is proceeding.
|
||||
*/
|
||||
progressToken: z.optional(ProgressTokenSchema),
|
||||
}),
|
||||
});
|
||||
/* Pagination */
|
||||
export const PaginatedRequestSchema = RequestSchema.extend({
|
||||
params: BaseRequestParamsSchema.extend({
|
||||
/**
|
||||
* An opaque token representing the current pagination position.
|
||||
* If provided, the server should return results starting after this cursor.
|
||||
*/
|
||||
cursor: z.optional(CursorSchema),
|
||||
}),
|
||||
});
|
||||
export const PaginatedResultSchema = ResultSchema.extend({
|
||||
/**
|
||||
* An opaque token representing the pagination position after the last returned result.
|
||||
* If present, there may be more results available.
|
||||
*/
|
||||
nextCursor: z.optional(CursorSchema),
|
||||
});
|
||||
/* Resources */
|
||||
/**
|
||||
* The contents of a specific resource or sub-resource.
|
||||
*/
|
||||
export const ResourceContentsSchema = z.object({
|
||||
/**
|
||||
* The URI of this resource.
|
||||
*/
|
||||
uri: z.string(),
|
||||
/**
|
||||
* The MIME type of this resource, if known.
|
||||
*/
|
||||
mimeType: z.optional(z.string()),
|
||||
});
|
||||
export const TextResourceContentsSchema = ResourceContentsSchema.extend({
|
||||
/**
|
||||
* The text of the item. This must only be set if the item can actually be represented as text (not binary data).
|
||||
*/
|
||||
text: z.string(),
|
||||
});
|
||||
export const BlobResourceContentsSchema = ResourceContentsSchema.extend({
|
||||
/**
|
||||
* A base64-encoded string representing the binary data of the item.
|
||||
*/
|
||||
blob: z.string().base64(),
|
||||
});
|
||||
/**
|
||||
* A known resource that the server is capable of reading.
|
||||
*/
|
||||
export const ResourceSchema = z.object({
|
||||
/**
|
||||
* The URI of this resource.
|
||||
*/
|
||||
uri: z.string(),
|
||||
/**
|
||||
* A human-readable name for this resource.
|
||||
*
|
||||
* This can be used by clients to populate UI elements.
|
||||
*/
|
||||
name: z.string(),
|
||||
/**
|
||||
* A description of what this resource represents.
|
||||
*
|
||||
* This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model.
|
||||
*/
|
||||
description: z.optional(z.string()),
|
||||
/**
|
||||
* The MIME type of this resource, if known.
|
||||
*/
|
||||
mimeType: z.optional(z.string()),
|
||||
});
|
||||
/**
|
||||
* A template description for resources available on the server.
|
||||
*/
|
||||
export const ResourceTemplateSchema = z.object({
|
||||
/**
|
||||
* A URI template (according to RFC 6570) that can be used to construct resource URIs.
|
||||
*/
|
||||
uriTemplate: z.string(),
|
||||
/**
|
||||
* A human-readable name for the type of resource this template refers to.
|
||||
*
|
||||
* This can be used by clients to populate UI elements.
|
||||
*/
|
||||
name: z.string(),
|
||||
/**
|
||||
* A description of what this template is for.
|
||||
*
|
||||
* This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model.
|
||||
*/
|
||||
description: z.optional(z.string()),
|
||||
/**
|
||||
* The MIME type for all resources that match this template. This should only be included if all resources matching this template have the same type.
|
||||
*/
|
||||
mimeType: z.optional(z.string()),
|
||||
});
|
||||
/**
|
||||
* Sent from the client to request a list of resources the server has.
|
||||
*/
|
||||
export const ListResourcesRequestSchema = PaginatedRequestSchema.extend({
|
||||
method: z.literal("resources/list"),
|
||||
});
|
||||
/**
|
||||
* The server's response to a resources/list request from the client.
|
||||
*/
|
||||
export const ListResourcesResultSchema = PaginatedResultSchema.extend({
|
||||
resources: z.array(ResourceSchema),
|
||||
});
|
||||
/**
|
||||
* Sent from the client to request a list of resource templates the server has.
|
||||
*/
|
||||
export const ListResourceTemplatesRequestSchema = PaginatedRequestSchema.extend({
|
||||
method: z.literal("resources/templates/list"),
|
||||
});
|
||||
/**
|
||||
* The server's response to a resources/templates/list request from the client.
|
||||
*/
|
||||
export const ListResourceTemplatesResultSchema = PaginatedResultSchema.extend({
|
||||
resourceTemplates: z.array(ResourceTemplateSchema),
|
||||
});
|
||||
/**
|
||||
* Sent from the client to the server, to read a specific resource URI.
|
||||
*/
|
||||
export const ReadResourceRequestSchema = RequestSchema.extend({
|
||||
method: z.literal("resources/read"),
|
||||
params: BaseRequestParamsSchema.extend({
|
||||
/**
|
||||
* The URI of the resource to read. The URI can use any protocol; it is up to the server how to interpret it.
|
||||
*/
|
||||
uri: z.string(),
|
||||
}),
|
||||
});
|
||||
/**
|
||||
* The server's response to a resources/read request from the client.
|
||||
*/
|
||||
export const ReadResourceResultSchema = ResultSchema.extend({
|
||||
contents: z.array(z.union([TextResourceContentsSchema, BlobResourceContentsSchema])),
|
||||
});
|
||||
/**
|
||||
* An optional notification from the server to the client, informing it that the list of resources it can read from has changed. This may be issued by servers without any previous subscription from the client.
|
||||
*/
|
||||
export const ResourceListChangedNotificationSchema = NotificationSchema.extend({
|
||||
method: z.literal("notifications/resources/list_changed"),
|
||||
});
|
||||
/**
|
||||
* Sent from the client to request resources/updated notifications from the server whenever a particular resource changes.
|
||||
*/
|
||||
export const SubscribeRequestSchema = RequestSchema.extend({
|
||||
method: z.literal("resources/subscribe"),
|
||||
params: BaseRequestParamsSchema.extend({
|
||||
/**
|
||||
* The URI of the resource to subscribe to. The URI can use any protocol; it is up to the server how to interpret it.
|
||||
*/
|
||||
uri: z.string(),
|
||||
}),
|
||||
});
|
||||
/**
|
||||
* Sent from the client to request cancellation of resources/updated notifications from the server. This should follow a previous resources/subscribe request.
|
||||
*/
|
||||
export const UnsubscribeRequestSchema = RequestSchema.extend({
|
||||
method: z.literal("resources/unsubscribe"),
|
||||
params: BaseRequestParamsSchema.extend({
|
||||
/**
|
||||
* The URI of the resource to unsubscribe from.
|
||||
*/
|
||||
uri: z.string(),
|
||||
}),
|
||||
});
|
||||
/**
|
||||
* A notification from the server to the client, informing it that a resource has changed and may need to be read again. This should only be sent if the client previously sent a resources/subscribe request.
|
||||
*/
|
||||
export const ResourceUpdatedNotificationSchema = NotificationSchema.extend({
|
||||
method: z.literal("notifications/resources/updated"),
|
||||
params: z.object({
|
||||
/**
|
||||
* The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually subscribed to.
|
||||
*/
|
||||
uri: z.string(),
|
||||
}),
|
||||
});
|
||||
/* Prompts */
|
||||
/**
|
||||
* Describes an argument that a prompt can accept.
|
||||
*/
|
||||
export const PromptArgumentSchema = z.object({
|
||||
/**
|
||||
* The name of the argument.
|
||||
*/
|
||||
name: z.string(),
|
||||
/**
|
||||
* A human-readable description of the argument.
|
||||
*/
|
||||
description: z.optional(z.string()),
|
||||
/**
|
||||
* Whether this argument must be provided.
|
||||
*/
|
||||
required: z.optional(z.boolean()),
|
||||
});
|
||||
/**
|
||||
* A prompt or prompt template that the server offers.
|
||||
*/
|
||||
export const PromptSchema = z.object({
|
||||
/**
|
||||
* The name of the prompt or prompt template.
|
||||
*/
|
||||
name: z.string(),
|
||||
/**
|
||||
* An optional description of what this prompt provides
|
||||
*/
|
||||
description: z.optional(z.string()),
|
||||
/**
|
||||
* A list of arguments to use for templating the prompt.
|
||||
*/
|
||||
arguments: z.optional(z.array(PromptArgumentSchema)),
|
||||
});
|
||||
/**
|
||||
* Sent from the client to request a list of prompts and prompt templates the server has.
|
||||
*/
|
||||
export const ListPromptsRequestSchema = PaginatedRequestSchema.extend({
|
||||
method: z.literal("prompts/list"),
|
||||
});
|
||||
/**
|
||||
* The server's response to a prompts/list request from the client.
|
||||
*/
|
||||
export const ListPromptsResultSchema = PaginatedResultSchema.extend({
|
||||
prompts: z.array(PromptSchema),
|
||||
});
|
||||
/**
|
||||
* Used by the client to get a prompt provided by the server.
|
||||
*/
|
||||
export const GetPromptRequestSchema = RequestSchema.extend({
|
||||
method: z.literal("prompts/get"),
|
||||
params: BaseRequestParamsSchema.extend({
|
||||
/**
|
||||
* The name of the prompt or prompt template.
|
||||
*/
|
||||
name: z.string(),
|
||||
/**
|
||||
* Arguments to use for templating the prompt.
|
||||
*/
|
||||
arguments: z.optional(z.record(z.string())),
|
||||
}),
|
||||
});
|
||||
/**
|
||||
* The server's response to a prompts/get request from the client.
|
||||
*/
|
||||
export const GetPromptResultSchema = ResultSchema.extend({
|
||||
/**
|
||||
* An optional description for the prompt.
|
||||
*/
|
||||
description: z.optional(z.string()),
|
||||
messages: z.array(SamplingMessageSchema),
|
||||
});
|
||||
/**
|
||||
* An optional notification from the server to the client, informing it that the list of prompts it offers has changed. This may be issued by servers without any previous subscription from the client.
|
||||
*/
|
||||
export const PromptListChangedNotificationSchema = NotificationSchema.extend({
|
||||
method: z.literal("notifications/prompts/list_changed"),
|
||||
});
|
||||
/* Tools */
|
||||
/**
|
||||
* Definition for a tool the client can call.
|
||||
*/
|
||||
export const ToolSchema = z.object({
|
||||
/**
|
||||
* The name of the tool.
|
||||
*/
|
||||
name: z.string(),
|
||||
/**
|
||||
* A human-readable description of the tool.
|
||||
*/
|
||||
description: z.optional(z.string()),
|
||||
/**
|
||||
* A JSON Schema object defining the expected parameters for the tool.
|
||||
*/
|
||||
inputSchema: z.object({
|
||||
type: z.literal("object"),
|
||||
properties: z.optional(z.object({}).passthrough()),
|
||||
}),
|
||||
});
|
||||
/**
|
||||
* Sent from the client to request a list of tools the server has.
|
||||
*/
|
||||
export const ListToolsRequestSchema = PaginatedRequestSchema.extend({
|
||||
method: z.literal("tools/list"),
|
||||
});
|
||||
/**
|
||||
* The server's response to a tools/list request from the client.
|
||||
*/
|
||||
export const ListToolsResultSchema = PaginatedResultSchema.extend({
|
||||
tools: z.array(ToolSchema),
|
||||
});
|
||||
/**
|
||||
* The server's response to a tool call.
|
||||
*/
|
||||
export const CallToolResultSchema = ResultSchema.extend({
|
||||
toolResult: z.unknown(),
|
||||
});
|
||||
/**
|
||||
* Used by the client to invoke a tool provided by the server.
|
||||
*/
|
||||
export const CallToolRequestSchema = RequestSchema.extend({
|
||||
method: z.literal("tools/call"),
|
||||
params: BaseRequestParamsSchema.extend({
|
||||
name: z.string(),
|
||||
arguments: z.optional(z.record(z.unknown())),
|
||||
}),
|
||||
});
|
||||
/**
|
||||
* An optional notification from the server to the client, informing it that the list of tools it offers has changed. This may be issued by servers without any previous subscription from the client.
|
||||
*/
|
||||
export const ToolListChangedNotificationSchema = NotificationSchema.extend({
|
||||
method: z.literal("notifications/tools/list_changed"),
|
||||
});
|
||||
/* Logging */
|
||||
/**
|
||||
* The severity of a log message.
|
||||
*/
|
||||
export const LoggingLevelSchema = z.enum(["debug", "info", "warning", "error"]);
|
||||
/**
|
||||
* A request from the client to the server, to enable or adjust logging.
|
||||
*/
|
||||
export const SetLevelRequestSchema = RequestSchema.extend({
|
||||
method: z.literal("logging/setLevel"),
|
||||
params: BaseRequestParamsSchema.extend({
|
||||
/**
|
||||
* The level of logging that the client wants to receive from the server. The server should send all logs at this level and higher (i.e., more severe) to the client as notifications/logging/message.
|
||||
*/
|
||||
level: LoggingLevelSchema,
|
||||
}),
|
||||
});
|
||||
/**
|
||||
* Notification of a log message passed from server to client. If no logging/setLevel request has been sent from the client, the server MAY decide which messages to send automatically.
|
||||
*/
|
||||
export const LoggingMessageNotificationSchema = NotificationSchema.extend({
|
||||
method: z.literal("notifications/message"),
|
||||
params: z.object({
|
||||
/**
|
||||
* The severity of this log message.
|
||||
*/
|
||||
level: LoggingLevelSchema,
|
||||
/**
|
||||
* An optional name of the logger issuing this message.
|
||||
*/
|
||||
logger: z.optional(z.string()),
|
||||
/**
|
||||
* The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here.
|
||||
*/
|
||||
data: z.unknown(),
|
||||
}),
|
||||
});
|
||||
/* Sampling */
|
||||
/**
|
||||
* A request from the server to sample an LLM via the client. The client has full discretion over which model to select. The client should also inform the user before beginning sampling, to allow them to inspect the request (human in the loop) and decide whether to approve it.
|
||||
*/
|
||||
export const CreateMessageRequestSchema = RequestSchema.extend({
|
||||
method: z.literal("sampling/createMessage"),
|
||||
params: BaseRequestParamsSchema.extend({
|
||||
messages: z.array(SamplingMessageSchema),
|
||||
/**
|
||||
* An optional system prompt the server wants to use for sampling. The client MAY modify or omit this prompt.
|
||||
*/
|
||||
systemPrompt: z.optional(z.string()),
|
||||
/**
|
||||
* A request to include context from one or more MCP servers (including the caller), to be attached to the prompt. The client MAY ignore this request.
|
||||
*/
|
||||
includeContext: z.optional(z.enum(["none", "thisServer", "allServers"])),
|
||||
temperature: z.optional(z.number()),
|
||||
/**
|
||||
* The maximum number of tokens to sample, as requested by the server. The client MAY choose to sample fewer tokens than requested.
|
||||
*/
|
||||
maxTokens: z.number().int(),
|
||||
stopSequences: z.optional(z.array(z.string())),
|
||||
/**
|
||||
* Optional metadata to pass through to the LLM provider. The format of this metadata is provider-specific.
|
||||
*/
|
||||
metadata: z.optional(z.object({}).passthrough()),
|
||||
}),
|
||||
});
|
||||
/**
|
||||
* The client's response to a sampling/create_message request from the server. The client should inform the user before returning the sampled message, to allow them to inspect the response (human in the loop) and decide whether to allow the server to see it.
|
||||
*/
|
||||
export const CreateMessageResultSchema = ResultSchema.extend({
|
||||
/**
|
||||
* The name of the model that generated the message.
|
||||
*/
|
||||
model: z.string(),
|
||||
/**
|
||||
* The reason why sampling stopped.
|
||||
*/
|
||||
stopReason: z.enum(["endTurn", "stopSequence", "maxTokens"]),
|
||||
role: z.enum(["user", "assistant"]),
|
||||
content: z.discriminatedUnion("type", [
|
||||
TextContentSchema,
|
||||
ImageContentSchema,
|
||||
]),
|
||||
});
|
||||
/* Autocomplete */
|
||||
/**
|
||||
* A reference to a resource or resource template definition.
|
||||
*/
|
||||
export const ResourceReferenceSchema = z.object({
|
||||
type: z.literal("ref/resource"),
|
||||
/**
|
||||
* The URI or URI template of the resource.
|
||||
*/
|
||||
uri: z.string(),
|
||||
});
|
||||
/**
|
||||
* Identifies a prompt.
|
||||
*/
|
||||
export const PromptReferenceSchema = z.object({
|
||||
type: z.literal("ref/prompt"),
|
||||
/**
|
||||
* The name of the prompt or prompt template
|
||||
*/
|
||||
name: z.string(),
|
||||
});
|
||||
/**
|
||||
* A request from the client to the server, to ask for completion options.
|
||||
*/
|
||||
export const CompleteRequestSchema = RequestSchema.extend({
|
||||
method: z.literal("completion/complete"),
|
||||
params: BaseRequestParamsSchema.extend({
|
||||
ref: z.union([PromptReferenceSchema, ResourceReferenceSchema]),
|
||||
/**
|
||||
* The argument's information
|
||||
*/
|
||||
argument: z.object({
|
||||
/**
|
||||
* The name of the argument
|
||||
*/
|
||||
name: z.string(),
|
||||
/**
|
||||
* The value of the argument to use for completion matching.
|
||||
*/
|
||||
value: z.string(),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
/**
|
||||
* The server's response to a completion/complete request
|
||||
*/
|
||||
export const CompleteResultSchema = ResultSchema.extend({
|
||||
completion: z.object({
|
||||
/**
|
||||
* An array of completion values. Must not exceed 100 items.
|
||||
*/
|
||||
values: z.array(z.string()).max(100),
|
||||
/**
|
||||
* The total number of completion options available. This can exceed the number of values actually sent in the response.
|
||||
*/
|
||||
total: z.optional(z.number().int()),
|
||||
/**
|
||||
* Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.
|
||||
*/
|
||||
hasMore: z.optional(z.boolean()),
|
||||
}),
|
||||
});
|
||||
/* Client messages */
|
||||
export const ClientRequestSchema = z.union([
|
||||
PingRequestSchema,
|
||||
InitializeRequestSchema,
|
||||
CompleteRequestSchema,
|
||||
SetLevelRequestSchema,
|
||||
GetPromptRequestSchema,
|
||||
ListPromptsRequestSchema,
|
||||
ListResourcesRequestSchema,
|
||||
ReadResourceRequestSchema,
|
||||
SubscribeRequestSchema,
|
||||
UnsubscribeRequestSchema,
|
||||
CallToolRequestSchema,
|
||||
ListToolsRequestSchema,
|
||||
]);
|
||||
export const ClientNotificationSchema = z.union([
|
||||
ProgressNotificationSchema,
|
||||
InitializedNotificationSchema,
|
||||
]);
|
||||
export const ClientResultSchema = z.union([
|
||||
EmptyResultSchema,
|
||||
CreateMessageResultSchema,
|
||||
]);
|
||||
/* Server messages */
|
||||
export const ServerRequestSchema = z.union([
|
||||
PingRequestSchema,
|
||||
CreateMessageRequestSchema,
|
||||
]);
|
||||
export const ServerNotificationSchema = z.union([
|
||||
ProgressNotificationSchema,
|
||||
LoggingMessageNotificationSchema,
|
||||
ResourceUpdatedNotificationSchema,
|
||||
ResourceListChangedNotificationSchema,
|
||||
ToolListChangedNotificationSchema,
|
||||
PromptListChangedNotificationSchema,
|
||||
]);
|
||||
export const ServerResultSchema = z.union([
|
||||
EmptyResultSchema,
|
||||
InitializeResultSchema,
|
||||
CompleteResultSchema,
|
||||
GetPromptResultSchema,
|
||||
ListPromptsResultSchema,
|
||||
ListResourcesResultSchema,
|
||||
ReadResourceResultSchema,
|
||||
CallToolResultSchema,
|
||||
ListToolsResultSchema,
|
||||
]);
|
||||
export class McpError extends Error {
|
||||
constructor(code, message, data) {
|
||||
super(`MCP error ${code}: ${message}`);
|
||||
this.code = code;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=types.js.map
|
||||
1
packages/mcp-typescript/dist/types.js.map
generated
vendored
Normal file
1
packages/mcp-typescript/dist/types.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
19
packages/mcp-typescript/eslint.config.mjs
generated
Normal file
19
packages/mcp-typescript/eslint.config.mjs
generated
Normal file
@@ -0,0 +1,19 @@
|
||||
// @ts-check
|
||||
|
||||
import eslint from '@eslint/js';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default tseslint.config(
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
{
|
||||
linterOptions: {
|
||||
reportUnusedDisableDirectives: false,
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/no-unused-vars": ["error",
|
||||
{ "argsIgnorePattern": "^_" }
|
||||
]
|
||||
}
|
||||
}
|
||||
);
|
||||
12
packages/mcp-typescript/jest.config.js
generated
Normal file
12
packages/mcp-typescript/jest.config.js
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
import { createDefaultEsmPreset } from "ts-jest";
|
||||
|
||||
const defaultEsmPreset = createDefaultEsmPreset();
|
||||
|
||||
/** @type {import('ts-jest').JestConfigWithTsJest} **/
|
||||
export default {
|
||||
...defaultEsmPreset,
|
||||
moduleNameMapper: {
|
||||
"^(\\.{1,2}/.*)\\.js$": "$1",
|
||||
},
|
||||
testPathIgnorePatterns: ["/node_modules/", "/dist/"],
|
||||
};
|
||||
57
packages/mcp-typescript/package.json
generated
Normal file
57
packages/mcp-typescript/package.json
generated
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"name": "mcp-typescript",
|
||||
"version": "0.1.0",
|
||||
"description": "Model Context Protocol implementation for TypeScript",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
"./*": "./dist/*"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./dist/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"lint": "eslint src/",
|
||||
"test": "jest",
|
||||
"start": "yarn server",
|
||||
"server": "tsx watch --clear-screen=false src/cli.ts server",
|
||||
"client": "tsx src/cli.ts client"
|
||||
},
|
||||
"dependencies": {
|
||||
"content-type": "^1.0.5",
|
||||
"raw-body": "^3.0.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.8.0",
|
||||
"@types/content-type": "^1.1.8",
|
||||
"@types/eslint__js": "^8.42.3",
|
||||
"@types/eventsource": "^1.1.15",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^22.0.2",
|
||||
"@types/ws": "^8.5.12",
|
||||
"eslint": "^9.8.0",
|
||||
"eventsource": "^2.0.2",
|
||||
"express": "^4.19.2",
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.2.4",
|
||||
"tsx": "^4.16.5",
|
||||
"typescript": "^5.5.4",
|
||||
"typescript-eslint": "^8.0.0",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"strip-ansi": "6.0.1"
|
||||
}
|
||||
}
|
||||
137
packages/mcp-typescript/src/cli.ts
generated
Normal file
137
packages/mcp-typescript/src/cli.ts
generated
Normal file
@@ -0,0 +1,137 @@
|
||||
import EventSource from "eventsource";
|
||||
import WebSocket from "ws";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(global as any).EventSource = EventSource;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(global as any).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: string, args: string[]) {
|
||||
const client = new Client({
|
||||
name: "mcp-typescript test client",
|
||||
version: "0.1.0",
|
||||
});
|
||||
|
||||
let clientTransport;
|
||||
|
||||
let url: URL | undefined = undefined;
|
||||
try {
|
||||
url = new URL(url_or_command);
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
if (url?.protocol === "http:" || url?.protocol === "https:") {
|
||||
clientTransport = new SSEClientTransport(new URL(url_or_command));
|
||||
} else if (url?.protocol === "ws:" || url?.protocol === "wss:") {
|
||||
clientTransport = new WebSocketClientTransport(new URL(url_or_command));
|
||||
} else {
|
||||
clientTransport = new StdioClientTransport({
|
||||
command: url_or_command,
|
||||
args,
|
||||
});
|
||||
}
|
||||
|
||||
console.log("Connected to server.");
|
||||
|
||||
await client.connect(clientTransport);
|
||||
console.log("Initialized.");
|
||||
|
||||
await client.close();
|
||||
console.log("Closed.");
|
||||
}
|
||||
|
||||
async function runServer(port: number | null) {
|
||||
if (port !== null) {
|
||||
const app = express();
|
||||
|
||||
let servers: Server[] = [];
|
||||
|
||||
app.get("/sse", async (req, res) => {
|
||||
console.log("Got new SSE connection");
|
||||
|
||||
const transport = new SSEServerTransport("/message", res);
|
||||
const server = new Server({
|
||||
name: "mcp-typescript test server",
|
||||
version: "0.1.0",
|
||||
});
|
||||
|
||||
servers.push(server);
|
||||
|
||||
server.onclose = () => {
|
||||
console.log("SSE connection closed");
|
||||
servers = servers.filter((s) => s !== server);
|
||||
};
|
||||
|
||||
await server.connect(transport);
|
||||
});
|
||||
|
||||
app.post("/message", async (req, res) => {
|
||||
console.log("Received message");
|
||||
|
||||
const sessionId = req.query.sessionId as string;
|
||||
const transport = servers
|
||||
.map((s) => s.transport as SSEServerTransport)
|
||||
.find((t) => t.sessionId === sessionId);
|
||||
if (!transport) {
|
||||
res.status(404).send("Session not found");
|
||||
return;
|
||||
}
|
||||
|
||||
await transport.handlePostMessage(req, res);
|
||||
});
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server running on http://localhost:${port}/sse`);
|
||||
});
|
||||
} else {
|
||||
const server = new Server({
|
||||
name: "mcp-typescript test server",
|
||||
version: "0.1.0",
|
||||
});
|
||||
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
|
||||
console.log("Server running on stdio");
|
||||
}
|
||||
}
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const command = args[0];
|
||||
switch (command) {
|
||||
case "client":
|
||||
if (args.length < 2) {
|
||||
console.error("Usage: client <server_url_or_command> [args...]");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
runClient(args[1], args.slice(2)).catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
case "server": {
|
||||
const port = args[1] ? parseInt(args[1]) : null;
|
||||
runServer(port).catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
console.error("Unrecognized command:", command);
|
||||
}
|
||||
79
packages/mcp-typescript/src/client/index.ts
generated
Normal file
79
packages/mcp-typescript/src/client/index.ts
generated
Normal file
@@ -0,0 +1,79 @@
|
||||
import { Protocol } from "../shared/protocol.js";
|
||||
import { Transport } from "../shared/transport.js";
|
||||
import {
|
||||
ClientNotification,
|
||||
ClientRequest,
|
||||
ClientResult,
|
||||
Implementation,
|
||||
InitializeResultSchema,
|
||||
PROTOCOL_VERSION,
|
||||
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 class Client extends Protocol<
|
||||
ClientRequest,
|
||||
ClientNotification,
|
||||
ClientResult
|
||||
> {
|
||||
private _serverCapabilities?: ServerCapabilities;
|
||||
private _serverVersion?: Implementation;
|
||||
|
||||
/**
|
||||
* Initializes this client with the given name and version information.
|
||||
*/
|
||||
constructor(private _clientInfo: Implementation) {
|
||||
super();
|
||||
}
|
||||
|
||||
override async connect(transport: Transport): Promise<void> {
|
||||
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(): ServerCapabilities | undefined {
|
||||
return this._serverCapabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* After initialization has completed, this will be populated with information about the server's name and version.
|
||||
*/
|
||||
getServerVersion(): Implementation | undefined {
|
||||
return this._serverVersion;
|
||||
}
|
||||
}
|
||||
113
packages/mcp-typescript/src/client/sse.ts
generated
Normal file
113
packages/mcp-typescript/src/client/sse.ts
generated
Normal file
@@ -0,0 +1,113 @@
|
||||
import { Transport } from "../shared/transport.js";
|
||||
import { JSONRPCMessage, 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 implements Transport {
|
||||
private _eventSource?: EventSource;
|
||||
private _endpoint?: URL;
|
||||
private _abortController?: AbortController;
|
||||
private _url: URL;
|
||||
|
||||
onclose?: () => void;
|
||||
onerror?: (error: Error) => void;
|
||||
onmessage?: (message: JSONRPCMessage) => void;
|
||||
|
||||
constructor(url: URL) {
|
||||
this._url = url;
|
||||
}
|
||||
|
||||
start(): Promise<void> {
|
||||
if (this._eventSource) {
|
||||
throw new Error(
|
||||
"SSEClientTransport already started! If using Client class, note that connect() calls start() automatically.",
|
||||
);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this._eventSource = new EventSource(this._url.href);
|
||||
this._abortController = new AbortController();
|
||||
|
||||
this._eventSource.onerror = (event) => {
|
||||
const error = new Error(`SSE error: ${JSON.stringify(event)}`);
|
||||
reject(error);
|
||||
this.onerror?.(error);
|
||||
};
|
||||
|
||||
this._eventSource.onopen = () => {
|
||||
// The connection is open, but we need to wait for the endpoint to be received.
|
||||
};
|
||||
|
||||
this._eventSource.addEventListener("endpoint", (event: Event) => {
|
||||
const messageEvent = event as MessageEvent;
|
||||
|
||||
try {
|
||||
this._endpoint = new URL(messageEvent.data, this._url);
|
||||
if (this._endpoint.origin !== this._url.origin) {
|
||||
throw new Error(
|
||||
`Endpoint origin does not match connection origin: ${this._endpoint.origin}`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
this.onerror?.(error as Error);
|
||||
|
||||
void this.close();
|
||||
return;
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
|
||||
this._eventSource.onmessage = (event: Event) => {
|
||||
const messageEvent = event as MessageEvent;
|
||||
let message: JSONRPCMessage;
|
||||
try {
|
||||
message = JSONRPCMessageSchema.parse(JSON.parse(messageEvent.data));
|
||||
} catch (error) {
|
||||
this.onerror?.(error as Error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.onmessage?.(message);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
this._abortController?.abort();
|
||||
this._eventSource?.close();
|
||||
this.onclose?.();
|
||||
}
|
||||
|
||||
async send(message: JSONRPCMessage): Promise<void> {
|
||||
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: this._abortController?.signal,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text().catch(() => null);
|
||||
throw new Error(
|
||||
`Error POSTing to endpoint (HTTP ${response.status}): ${text}`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
this.onerror?.(error as Error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
61
packages/mcp-typescript/src/client/stdio.test.ts
generated
Normal file
61
packages/mcp-typescript/src/client/stdio.test.ts
generated
Normal file
@@ -0,0 +1,61 @@
|
||||
import { JSONRPCMessage } from "../types.js";
|
||||
import { StdioClientTransport, StdioServerParameters } from "./stdio.js";
|
||||
|
||||
const serverParameters: StdioServerParameters = {
|
||||
command: "/usr/bin/tee",
|
||||
};
|
||||
|
||||
test("should start then close cleanly", async () => {
|
||||
const client = new StdioClientTransport(serverParameters);
|
||||
client.onerror = (error) => {
|
||||
throw error;
|
||||
};
|
||||
|
||||
let didClose = false;
|
||||
client.onclose = () => {
|
||||
didClose = true;
|
||||
};
|
||||
|
||||
await client.start();
|
||||
expect(didClose).toBeFalsy();
|
||||
await client.close();
|
||||
expect(didClose).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should read messages", async () => {
|
||||
const client = new StdioClientTransport(serverParameters);
|
||||
client.onerror = (error) => {
|
||||
throw error;
|
||||
};
|
||||
|
||||
const messages: JSONRPCMessage[] = [
|
||||
{
|
||||
jsonrpc: "2.0",
|
||||
id: 1,
|
||||
method: "ping",
|
||||
},
|
||||
{
|
||||
jsonrpc: "2.0",
|
||||
method: "notifications/initialized",
|
||||
},
|
||||
];
|
||||
|
||||
const readMessages: JSONRPCMessage[] = [];
|
||||
const finished = new Promise<void>((resolve) => {
|
||||
client.onmessage = (message) => {
|
||||
readMessages.push(message);
|
||||
|
||||
if (JSON.stringify(message) === JSON.stringify(messages[1])) {
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
await client.start();
|
||||
await client.send(messages[0]);
|
||||
await client.send(messages[1]);
|
||||
await finished;
|
||||
expect(readMessages).toEqual(messages);
|
||||
|
||||
await client.close();
|
||||
});
|
||||
139
packages/mcp-typescript/src/client/stdio.ts
generated
Normal file
139
packages/mcp-typescript/src/client/stdio.ts
generated
Normal file
@@ -0,0 +1,139 @@
|
||||
import { ChildProcess, spawn } from "node:child_process";
|
||||
import { ReadBuffer, serializeMessage } from "../shared/stdio.js";
|
||||
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 class StdioClientTransport implements Transport {
|
||||
private _process?: ChildProcess;
|
||||
private _abortController: AbortController = new AbortController();
|
||||
private _readBuffer: ReadBuffer = new ReadBuffer();
|
||||
private _serverParams: StdioServerParameters;
|
||||
|
||||
onclose?: () => void;
|
||||
onerror?: (error: Error) => void;
|
||||
onmessage?: (message: JSONRPCMessage) => void;
|
||||
|
||||
constructor(server: StdioServerParameters) {
|
||||
this._serverParams = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the server process and prepares to communicate with it.
|
||||
*/
|
||||
async start(): Promise<void> {
|
||||
if (this._process) {
|
||||
throw new Error(
|
||||
"StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.",
|
||||
);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this._process = spawn(
|
||||
this._serverParams.command,
|
||||
this._serverParams.args ?? [],
|
||||
{
|
||||
// The parent process may have sensitive secrets in its env, so don't inherit it automatically.
|
||||
env:
|
||||
this._serverParams.env === undefined
|
||||
? {}
|
||||
: { ...this._serverParams.env },
|
||||
stdio: ["pipe", "pipe", "inherit"],
|
||||
signal: this._abortController.signal,
|
||||
},
|
||||
);
|
||||
|
||||
this._process.on("error", (error) => {
|
||||
if (error.name === "AbortError") {
|
||||
// Expected when close() is called.
|
||||
this.onclose?.();
|
||||
return;
|
||||
}
|
||||
|
||||
reject(error);
|
||||
this.onerror?.(error);
|
||||
});
|
||||
|
||||
this._process.on("spawn", () => {
|
||||
resolve();
|
||||
});
|
||||
|
||||
this._process.on("close", (_code) => {
|
||||
this._process = undefined;
|
||||
this.onclose?.();
|
||||
});
|
||||
|
||||
this._process.stdin?.on("error", (error) => {
|
||||
this.onerror?.(error);
|
||||
});
|
||||
|
||||
this._process.stdout?.on("data", (chunk) => {
|
||||
this._readBuffer.append(chunk);
|
||||
this.processReadBuffer();
|
||||
});
|
||||
|
||||
this._process.stdout?.on("error", (error) => {
|
||||
this.onerror?.(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private processReadBuffer() {
|
||||
while (true) {
|
||||
try {
|
||||
const message = this._readBuffer.readMessage();
|
||||
if (message === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
this.onmessage?.(message);
|
||||
} catch (error) {
|
||||
this.onerror?.(error as Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
this._abortController.abort();
|
||||
this._process = undefined;
|
||||
this._readBuffer.clear();
|
||||
}
|
||||
|
||||
send(message: JSONRPCMessage): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
if (!this._process?.stdin) {
|
||||
throw new Error("Not connected");
|
||||
}
|
||||
|
||||
const json = serializeMessage(message);
|
||||
if (this._process.stdin.write(json)) {
|
||||
resolve();
|
||||
} else {
|
||||
this._process.stdin.once("drain", resolve);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
77
packages/mcp-typescript/src/client/websocket.ts
generated
Normal file
77
packages/mcp-typescript/src/client/websocket.ts
generated
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Transport } from "../shared/transport.js";
|
||||
import { JSONRPCMessage, JSONRPCMessageSchema } from "../types.js";
|
||||
|
||||
const SUBPROTOCOL = "mcp";
|
||||
|
||||
/**
|
||||
* Client transport for WebSocket: this will connect to a server over the WebSocket protocol.
|
||||
*/
|
||||
export class WebSocketClientTransport implements Transport {
|
||||
private _socket?: WebSocket;
|
||||
private _url: URL;
|
||||
|
||||
onclose?: () => void;
|
||||
onerror?: (error: Error) => void;
|
||||
onmessage?: (message: JSONRPCMessage) => void;
|
||||
|
||||
constructor(url: URL) {
|
||||
this._url = url;
|
||||
}
|
||||
|
||||
start(): Promise<void> {
|
||||
if (this._socket) {
|
||||
throw new Error(
|
||||
"WebSocketClientTransport already started! If using Client class, note that connect() calls start() automatically.",
|
||||
);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this._socket = new WebSocket(this._url, SUBPROTOCOL);
|
||||
|
||||
this._socket.onerror = (event) => {
|
||||
const error =
|
||||
"error" in event
|
||||
? (event.error as Error)
|
||||
: new Error(`WebSocket error: ${JSON.stringify(event)}`);
|
||||
reject(error);
|
||||
this.onerror?.(error);
|
||||
};
|
||||
|
||||
this._socket.onopen = () => {
|
||||
resolve();
|
||||
};
|
||||
|
||||
this._socket.onclose = () => {
|
||||
this.onclose?.();
|
||||
};
|
||||
|
||||
this._socket.onmessage = (event: MessageEvent) => {
|
||||
let message: JSONRPCMessage;
|
||||
try {
|
||||
message = JSONRPCMessageSchema.parse(JSON.parse(event.data));
|
||||
} catch (error) {
|
||||
this.onerror?.(error as Error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.onmessage?.(message);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
this._socket?.close();
|
||||
}
|
||||
|
||||
send(message: JSONRPCMessage): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._socket) {
|
||||
reject(new Error("Not connected"));
|
||||
return;
|
||||
}
|
||||
|
||||
this._socket?.send(JSON.stringify(message));
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
}
|
||||
102
packages/mcp-typescript/src/server/index.ts
generated
Normal file
102
packages/mcp-typescript/src/server/index.ts
generated
Normal file
@@ -0,0 +1,102 @@
|
||||
import { Protocol } from "../shared/protocol.js";
|
||||
import {
|
||||
ClientCapabilities,
|
||||
ClientRequest,
|
||||
Implementation,
|
||||
InitializedNotificationSchema,
|
||||
InitializeRequest,
|
||||
InitializeRequestSchema,
|
||||
InitializeResult,
|
||||
PROTOCOL_VERSION,
|
||||
ServerNotification,
|
||||
ServerRequest,
|
||||
ServerResult,
|
||||
ServerCapabilities,
|
||||
ListResourcesRequestSchema,
|
||||
ListToolsRequestSchema,
|
||||
ListPromptsRequestSchema,
|
||||
SetLevelRequestSchema,
|
||||
} from "../types.js";
|
||||
|
||||
/**
|
||||
* An MCP server on top of a pluggable transport.
|
||||
*
|
||||
* This server will automatically respond to the initialization flow as initiated from the client.
|
||||
*/
|
||||
export class Server extends Protocol<
|
||||
ServerRequest,
|
||||
ServerNotification,
|
||||
ServerResult
|
||||
> {
|
||||
private _clientCapabilities?: ClientCapabilities;
|
||||
private _clientVersion?: Implementation;
|
||||
|
||||
/**
|
||||
* 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(private _serverInfo: Implementation) {
|
||||
super();
|
||||
|
||||
this.setRequestHandler(InitializeRequestSchema, (request) =>
|
||||
this._oninitialize(request),
|
||||
);
|
||||
this.setNotificationHandler(InitializedNotificationSchema, () =>
|
||||
this.oninitialized?.(),
|
||||
);
|
||||
}
|
||||
|
||||
private async _oninitialize(
|
||||
request: InitializeRequest,
|
||||
): Promise<InitializeResult> {
|
||||
if (request.params.protocolVersion !== PROTOCOL_VERSION) {
|
||||
throw new Error(
|
||||
`Client's protocol version is not supported: ${request.params.protocolVersion}`,
|
||||
);
|
||||
}
|
||||
|
||||
this._clientCapabilities = request.params.capabilities;
|
||||
this._clientVersion = request.params.clientInfo;
|
||||
|
||||
return {
|
||||
protocolVersion: PROTOCOL_VERSION,
|
||||
capabilities: this.getCapabilities(),
|
||||
serverInfo: this._serverInfo,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* After initialization has completed, this will be populated with the client's reported capabilities.
|
||||
*/
|
||||
getClientCapabilities(): ClientCapabilities | undefined {
|
||||
return this._clientCapabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* After initialization has completed, this will be populated with information about the client's name and version.
|
||||
*/
|
||||
getClientVersion(): Implementation | undefined {
|
||||
return this._clientVersion;
|
||||
}
|
||||
|
||||
private getCapability(
|
||||
reqType: ClientRequest["method"],
|
||||
): ServerCapabilities[keyof ServerCapabilities] {
|
||||
return this._requestHandlers.has(reqType as string) ? {} : undefined;
|
||||
}
|
||||
|
||||
private getCapabilities(): ServerCapabilities {
|
||||
return {
|
||||
prompts: this.getCapability(ListPromptsRequestSchema.shape.method.value),
|
||||
resources: this.getCapability(
|
||||
ListResourcesRequestSchema.shape.method.value,
|
||||
),
|
||||
tools: this.getCapability(ListToolsRequestSchema.shape.method.value),
|
||||
logging: this.getCapability(SetLevelRequestSchema.shape.method.value),
|
||||
};
|
||||
}
|
||||
}
|
||||
144
packages/mcp-typescript/src/server/sse.ts
generated
Normal file
144
packages/mcp-typescript/src/server/sse.ts
generated
Normal file
@@ -0,0 +1,144 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { IncomingMessage, ServerResponse } from "node:http";
|
||||
import { Transport } from "../shared/transport.js";
|
||||
import { JSONRPCMessage, 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 implements Transport {
|
||||
private _sseResponse?: ServerResponse;
|
||||
private _sessionId: string;
|
||||
|
||||
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(
|
||||
private _endpoint: string,
|
||||
private res: ServerResponse,
|
||||
) {
|
||||
this._sessionId = randomUUID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the initial SSE connection request.
|
||||
*
|
||||
* This should be called when a GET request is made to establish the SSE stream.
|
||||
*/
|
||||
async start(): Promise<void> {
|
||||
if (this._sseResponse) {
|
||||
throw new Error(
|
||||
"SSEServerTransport already started! If using Server class, note that connect() calls start() automatically.",
|
||||
);
|
||||
}
|
||||
|
||||
this.res.writeHead(200, {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
Connection: "keep-alive",
|
||||
});
|
||||
|
||||
// Send the endpoint event
|
||||
this.res.write(
|
||||
`event: endpoint\ndata: ${encodeURI(this._endpoint)}?sessionId=${this._sessionId}\n\n`,
|
||||
);
|
||||
|
||||
this._sseResponse = this.res;
|
||||
this.res.on("close", () => {
|
||||
this._sseResponse = undefined;
|
||||
this.onclose?.();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming POST messages.
|
||||
*
|
||||
* This should be called when a POST request is made to send a message to the server.
|
||||
*/
|
||||
async handlePostMessage(
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
): Promise<void> {
|
||||
if (!this._sseResponse) {
|
||||
const message = "SSE connection not established";
|
||||
res.writeHead(500).end(message);
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
let body: string;
|
||||
try {
|
||||
const ct = contentType.parse(req.headers["content-type"] ?? "");
|
||||
if (ct.type !== "application/json") {
|
||||
throw new Error(`Unsupported content-type: ${ct}`);
|
||||
}
|
||||
|
||||
body = await getRawBody(req, {
|
||||
limit: MAXIMUM_MESSAGE_SIZE,
|
||||
encoding: ct.parameters.charset ?? "utf-8",
|
||||
});
|
||||
} catch (error) {
|
||||
res.writeHead(400).end(String(error));
|
||||
this.onerror?.(error as Error);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.handleMessage(JSON.parse(body));
|
||||
} catch {
|
||||
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: unknown): Promise<void> {
|
||||
let parsedMessage: JSONRPCMessage;
|
||||
try {
|
||||
parsedMessage = JSONRPCMessageSchema.parse(message);
|
||||
} catch (error) {
|
||||
this.onerror?.(error as Error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
this.onmessage?.(parsedMessage);
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
this._sseResponse?.end();
|
||||
this._sseResponse = undefined;
|
||||
this.onclose?.();
|
||||
}
|
||||
|
||||
async send(message: JSONRPCMessage): Promise<void> {
|
||||
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(): string {
|
||||
return this._sessionId;
|
||||
}
|
||||
}
|
||||
102
packages/mcp-typescript/src/server/stdio.test.ts
generated
Normal file
102
packages/mcp-typescript/src/server/stdio.test.ts
generated
Normal file
@@ -0,0 +1,102 @@
|
||||
import { Readable, Writable } from "node:stream";
|
||||
import { ReadBuffer, serializeMessage } from "../shared/stdio.js";
|
||||
import { JSONRPCMessage } from "../types.js";
|
||||
import { StdioServerTransport } from "./stdio.js";
|
||||
|
||||
let input: Readable;
|
||||
let outputBuffer: ReadBuffer;
|
||||
let output: Writable;
|
||||
|
||||
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: JSONRPCMessage = {
|
||||
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: JSONRPCMessage[] = [
|
||||
{
|
||||
jsonrpc: "2.0",
|
||||
id: 1,
|
||||
method: "ping",
|
||||
},
|
||||
{
|
||||
jsonrpc: "2.0",
|
||||
method: "notifications/initialized",
|
||||
},
|
||||
];
|
||||
|
||||
const readMessages: JSONRPCMessage[] = [];
|
||||
const finished = new Promise<void>((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);
|
||||
});
|
||||
81
packages/mcp-typescript/src/server/stdio.ts
generated
Normal file
81
packages/mcp-typescript/src/server/stdio.ts
generated
Normal file
@@ -0,0 +1,81 @@
|
||||
import process from "node:process";
|
||||
import { Readable, Writable } from "node:stream";
|
||||
import { ReadBuffer, serializeMessage } from "../shared/stdio.js";
|
||||
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 class StdioServerTransport implements Transport {
|
||||
private _readBuffer: ReadBuffer = new ReadBuffer();
|
||||
private _started = false;
|
||||
|
||||
constructor(
|
||||
private _stdin: Readable = process.stdin,
|
||||
private _stdout: Writable = process.stdout,
|
||||
) {}
|
||||
|
||||
onclose?: () => void;
|
||||
onerror?: (error: Error) => void;
|
||||
onmessage?: (message: JSONRPCMessage) => void;
|
||||
|
||||
// Arrow functions to bind `this` properly, while maintaining function identity.
|
||||
_ondata = (chunk: Buffer) => {
|
||||
this._readBuffer.append(chunk);
|
||||
this.processReadBuffer();
|
||||
};
|
||||
_onerror = (error: Error) => {
|
||||
this.onerror?.(error);
|
||||
};
|
||||
|
||||
/**
|
||||
* Starts listening for messages on stdin.
|
||||
*/
|
||||
async start(): Promise<void> {
|
||||
if (this._started) {
|
||||
throw new Error(
|
||||
"StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.",
|
||||
);
|
||||
}
|
||||
|
||||
this._started = true;
|
||||
this._stdin.on("data", this._ondata);
|
||||
this._stdin.on("error", this._onerror);
|
||||
}
|
||||
|
||||
private processReadBuffer() {
|
||||
while (true) {
|
||||
try {
|
||||
const message = this._readBuffer.readMessage();
|
||||
if (message === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
this.onmessage?.(message);
|
||||
} catch (error) {
|
||||
this.onerror?.(error as Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
this._stdin.off("data", this._ondata);
|
||||
this._stdin.off("error", this._onerror);
|
||||
this._readBuffer.clear();
|
||||
this.onclose?.();
|
||||
}
|
||||
|
||||
send(message: JSONRPCMessage): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
const json = serializeMessage(message);
|
||||
if (this._stdout.write(json)) {
|
||||
resolve();
|
||||
} else {
|
||||
this._stdout.once("drain", resolve);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
363
packages/mcp-typescript/src/shared/protocol.ts
generated
Normal file
363
packages/mcp-typescript/src/shared/protocol.ts
generated
Normal file
@@ -0,0 +1,363 @@
|
||||
import { AnyZodObject, ZodLiteral, ZodObject, z } from "zod";
|
||||
import {
|
||||
ErrorCode,
|
||||
JSONRPCError,
|
||||
JSONRPCNotification,
|
||||
JSONRPCRequest,
|
||||
JSONRPCResponse,
|
||||
McpError,
|
||||
Notification,
|
||||
PingRequestSchema,
|
||||
Progress,
|
||||
ProgressNotification,
|
||||
ProgressNotificationSchema,
|
||||
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 class Protocol<
|
||||
SendRequestT extends Request,
|
||||
SendNotificationT extends Notification,
|
||||
SendResultT extends Result,
|
||||
> {
|
||||
private _transport?: Transport;
|
||||
private _requestMessageId = 0;
|
||||
protected _requestHandlers: Map<
|
||||
string,
|
||||
(request: JSONRPCRequest) => Promise<SendResultT>
|
||||
> = new Map();
|
||||
private _notificationHandlers: Map<
|
||||
string,
|
||||
(notification: JSONRPCNotification) => Promise<void>
|
||||
> = new Map();
|
||||
private _responseHandlers: Map<
|
||||
number,
|
||||
(response: JSONRPCResponse | Error) => void
|
||||
> = new Map();
|
||||
private _progressHandlers: Map<number, ProgressCallback> = new Map();
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
this.setNotificationHandler(ProgressNotificationSchema, (notification) => {
|
||||
this._onprogress(notification as unknown as ProgressNotification);
|
||||
});
|
||||
|
||||
this.setRequestHandler(
|
||||
PingRequestSchema,
|
||||
// Automatic pong by default.
|
||||
(_request) => ({}) as SendResultT,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches to the given transport, starts it, and starts listening for messages.
|
||||
*
|
||||
* The Protocol object assumes ownership of the Transport, replacing any callbacks that have already been set, and expects that it is the only user of the Transport instance going forward.
|
||||
*/
|
||||
async connect(transport: Transport): Promise<void> {
|
||||
this._transport = transport;
|
||||
this._transport.onclose = () => {
|
||||
this._onclose();
|
||||
};
|
||||
|
||||
this._transport.onerror = (error: Error) => {
|
||||
this._onerror(error);
|
||||
};
|
||||
|
||||
this._transport.onmessage = (message) => {
|
||||
if (!("method" in message)) {
|
||||
this._onresponse(message);
|
||||
} else if ("id" in message) {
|
||||
this._onrequest(message);
|
||||
} else {
|
||||
this._onnotification(message);
|
||||
}
|
||||
};
|
||||
|
||||
await this._transport.start();
|
||||
}
|
||||
|
||||
private _onclose(): void {
|
||||
const responseHandlers = this._responseHandlers;
|
||||
this._responseHandlers = new Map();
|
||||
this._progressHandlers.clear();
|
||||
this._transport = undefined;
|
||||
this.onclose?.();
|
||||
|
||||
const error = new McpError(ErrorCode.ConnectionClosed, "Connection closed");
|
||||
for (const handler of responseHandlers.values()) {
|
||||
handler(error);
|
||||
}
|
||||
}
|
||||
|
||||
private _onerror(error: Error): void {
|
||||
this.onerror?.(error);
|
||||
}
|
||||
|
||||
private _onnotification(notification: JSONRPCNotification): void {
|
||||
const handler =
|
||||
this._notificationHandlers.get(notification.method) ??
|
||||
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}`),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
private _onrequest(request: JSONRPCRequest): void {
|
||||
const handler =
|
||||
this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
|
||||
|
||||
if (handler === undefined) {
|
||||
this._transport
|
||||
?.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) => {
|
||||
this._transport?.send({
|
||||
result,
|
||||
jsonrpc: "2.0",
|
||||
id: request.id,
|
||||
});
|
||||
},
|
||||
(error) => {
|
||||
return this._transport?.send({
|
||||
jsonrpc: "2.0",
|
||||
id: request.id,
|
||||
error: {
|
||||
code: error["code"]
|
||||
? Math.floor(Number(error["code"]))
|
||||
: ErrorCode.InternalError,
|
||||
message: error.message ?? "Internal error",
|
||||
},
|
||||
});
|
||||
},
|
||||
)
|
||||
.catch((error) =>
|
||||
this._onerror(new Error(`Failed to send response: ${error}`)),
|
||||
);
|
||||
}
|
||||
|
||||
private _onprogress(notification: ProgressNotification): void {
|
||||
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 });
|
||||
}
|
||||
|
||||
private _onresponse(response: JSONRPCResponse | JSONRPCError): void {
|
||||
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(): Transport | undefined {
|
||||
return this._transport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the connection.
|
||||
*/
|
||||
async close(): Promise<void> {
|
||||
await this._transport?.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<T extends AnyZodObject>(
|
||||
request: SendRequestT,
|
||||
resultSchema: T,
|
||||
onprogress?: ProgressCallback,
|
||||
): Promise<z.infer<T>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._transport) {
|
||||
reject(new Error("Not connected"));
|
||||
return;
|
||||
}
|
||||
|
||||
const messageId = this._requestMessageId++;
|
||||
const jsonrpcRequest: 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: SendNotificationT): Promise<void> {
|
||||
if (!this._transport) {
|
||||
throw new Error("Not connected");
|
||||
}
|
||||
|
||||
const jsonrpcNotification: 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<
|
||||
T extends ZodObject<{
|
||||
method: ZodLiteral<string>;
|
||||
}>,
|
||||
>(
|
||||
requestSchema: T,
|
||||
handler: (request: z.infer<T>) => SendResultT | Promise<SendResultT>,
|
||||
): void {
|
||||
this._requestHandlers.set(requestSchema.shape.method.value, (request) =>
|
||||
Promise.resolve(handler(requestSchema.parse(request))),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the request handler for the given method.
|
||||
*/
|
||||
removeRequestHandler(method: string): void {
|
||||
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<
|
||||
T extends ZodObject<{
|
||||
method: ZodLiteral<string>;
|
||||
}>,
|
||||
>(
|
||||
notificationSchema: T,
|
||||
handler: (notification: z.infer<T>) => void | Promise<void>,
|
||||
): void {
|
||||
this._notificationHandlers.set(
|
||||
notificationSchema.shape.method.value,
|
||||
(notification) =>
|
||||
Promise.resolve(handler(notificationSchema.parse(notification))),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the notification handler for the given method.
|
||||
*/
|
||||
removeNotificationHandler(method: string): void {
|
||||
this._notificationHandlers.delete(method);
|
||||
}
|
||||
}
|
||||
35
packages/mcp-typescript/src/shared/stdio.test.ts
generated
Normal file
35
packages/mcp-typescript/src/shared/stdio.test.ts
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
import { JSONRPCMessage } from "../types.js";
|
||||
import { ReadBuffer } from "./stdio.js";
|
||||
|
||||
const testMessage: JSONRPCMessage = {
|
||||
jsonrpc: "2.0",
|
||||
method: "foobar",
|
||||
};
|
||||
|
||||
test("should have no messages after initialization", () => {
|
||||
const readBuffer = new ReadBuffer();
|
||||
expect(readBuffer.readMessage()).toBeNull();
|
||||
});
|
||||
|
||||
test("should only yield a message after a newline", () => {
|
||||
const readBuffer = new ReadBuffer();
|
||||
|
||||
readBuffer.append(Buffer.from(JSON.stringify(testMessage)));
|
||||
expect(readBuffer.readMessage()).toBeNull();
|
||||
|
||||
readBuffer.append(Buffer.from("\n"));
|
||||
expect(readBuffer.readMessage()).toEqual(testMessage);
|
||||
expect(readBuffer.readMessage()).toBeNull();
|
||||
});
|
||||
|
||||
test("should be reusable after clearing", () => {
|
||||
const readBuffer = new ReadBuffer();
|
||||
|
||||
readBuffer.append(Buffer.from("foobar"));
|
||||
readBuffer.clear();
|
||||
expect(readBuffer.readMessage()).toBeNull();
|
||||
|
||||
readBuffer.append(Buffer.from(JSON.stringify(testMessage)));
|
||||
readBuffer.append(Buffer.from("\n"));
|
||||
expect(readBuffer.readMessage()).toEqual(testMessage);
|
||||
});
|
||||
39
packages/mcp-typescript/src/shared/stdio.ts
generated
Normal file
39
packages/mcp-typescript/src/shared/stdio.ts
generated
Normal file
@@ -0,0 +1,39 @@
|
||||
import { JSONRPCMessage, JSONRPCMessageSchema } from "../types.js";
|
||||
|
||||
/**
|
||||
* Buffers a continuous stdio stream into discrete JSON-RPC messages.
|
||||
*/
|
||||
export class ReadBuffer {
|
||||
private _buffer?: Buffer;
|
||||
|
||||
append(chunk: Buffer): void {
|
||||
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
||||
}
|
||||
|
||||
readMessage(): JSONRPCMessage | null {
|
||||
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(): void {
|
||||
this._buffer = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function deserializeMessage(line: string): JSONRPCMessage {
|
||||
return JSONRPCMessageSchema.parse(JSON.parse(line));
|
||||
}
|
||||
|
||||
export function serializeMessage(message: JSONRPCMessage): string {
|
||||
return JSON.stringify(message) + "\n";
|
||||
}
|
||||
44
packages/mcp-typescript/src/shared/transport.ts
generated
Normal file
44
packages/mcp-typescript/src/shared/transport.ts
generated
Normal file
@@ -0,0 +1,44 @@
|
||||
import { JSONRPCMessage } from "../types.js";
|
||||
|
||||
/**
|
||||
* Describes the minimal contract for a MCP transport that a client or server can communicate over.
|
||||
*/
|
||||
export interface Transport {
|
||||
/**
|
||||
* Starts processing messages on the transport, including any connection steps that might need to be taken.
|
||||
*
|
||||
* This method should only be called after callbacks are installed, or else messages may be lost.
|
||||
*
|
||||
* NOTE: This method should not be called explicitly when using Client, Server, or Protocol classes, as they will implicitly call start().
|
||||
*/
|
||||
start(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Sends a JSON-RPC message (request or response).
|
||||
*/
|
||||
send(message: JSONRPCMessage): Promise<void>;
|
||||
|
||||
/**
|
||||
* Closes the connection.
|
||||
*/
|
||||
close(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Callback for when the connection is closed for any reason.
|
||||
*
|
||||
* This should be invoked when close() is called as well.
|
||||
*/
|
||||
onclose?: () => void;
|
||||
|
||||
/**
|
||||
* Callback for when an error occurs.
|
||||
*
|
||||
* Note that errors are not necessarily fatal; they are used for reporting any kind of exceptional condition out of band.
|
||||
*/
|
||||
onerror?: (error: Error) => void;
|
||||
|
||||
/**
|
||||
* Callback for when a message (request or response) is received over the connection.
|
||||
*/
|
||||
onmessage?: (message: JSONRPCMessage) => void;
|
||||
}
|
||||
1009
packages/mcp-typescript/src/types.ts
generated
Normal file
1009
packages/mcp-typescript/src/types.ts
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
packages/mcp-typescript/tsconfig.json
generated
Normal file
19
packages/mcp-typescript/tsconfig.json
generated
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2018",
|
||||
"module": "Node16",
|
||||
"moduleResolution": "Node16",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
3528
packages/mcp-typescript/yarn.lock
generated
Normal file
3528
packages/mcp-typescript/yarn.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -17,10 +17,10 @@
|
||||
"typescript": "^5.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "*",
|
||||
"cors": "^2.8.5",
|
||||
"eventsource": "^2.0.2",
|
||||
"express": "^4.21.0",
|
||||
"mcp-typescript": "file:../packages/mcp-typescript",
|
||||
"ws": "^8.18.0",
|
||||
"zod": "^3.23.8"
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import cors from "cors";
|
||||
import EventSource from "eventsource";
|
||||
|
||||
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
||||
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
||||
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
||||
import { SSEServerTransport } from "mcp-typescript/server/sse.js";
|
||||
import express from "express";
|
||||
import { StdioClientTransport } from "mcp-typescript/client/stdio.js";
|
||||
import mcpProxy from "./mcpProxy.js";
|
||||
import { SSEClientTransport } from "mcp-typescript/client/sse.js";
|
||||
|
||||
// Polyfill EventSource for an SSE client in Node.js
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -23,7 +23,7 @@ const createTransport = async (query: express.Request["query"]) => {
|
||||
|
||||
if (transportType === "stdio") {
|
||||
const command = query.command as string;
|
||||
const args = (query.args as string).split(/\s+/);
|
||||
const args = (query.args as string).split(",");
|
||||
console.log(`Stdio transport: command=${command}, args=${args}`);
|
||||
const transport = new StdioClientTransport({ command, args });
|
||||
await transport.start();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
||||
import { Transport } from "mcp-typescript/shared/transport.js";
|
||||
|
||||
export default function mcpProxy({
|
||||
transportToClient,
|
||||
|
||||
Reference in New Issue
Block a user