|
Download node_modules/@modelcontextprotocol/sdk/README.md from pgits/mcp-jokes: direct link, hf CLI and curl.
- Browser
- Download file 22.7 kB
-
https://huggingface.co/spaces/pgits/mcp-jokes/resolve/main/node_modules/%40modelcontextprotocol/sdk/README.md
- Command line
-
hf download hf://spaces/pgits/mcp-jokes/node_modules/@modelcontextprotocol/sdk/README.md
-
curl -L -o README.md https://huggingface.co/spaces/pgits/mcp-jokes/resolve/main/node_modules/%40modelcontextprotocol/sdk/README.md
22.7 kB
| # MCP TypeScript SDK   | |
| ## Table of Contents | |
| - [Overview](#overview) | |
| - [Installation](#installation) | |
| - [Quickstart](#quickstart) | |
| - [What is MCP?](#what-is-mcp) | |
| - [Core Concepts](#core-concepts) | |
| - [Server](#server) | |
| - [Resources](#resources) | |
| - [Tools](#tools) | |
| - [Prompts](#prompts) | |
| - [Running Your Server](#running-your-server) | |
| - [stdio](#stdio) | |
| - [Streamable HTTP](#streamable-http) | |
| - [Testing and Debugging](#testing-and-debugging) | |
| - [Examples](#examples) | |
| - [Echo Server](#echo-server) | |
| - [SQLite Explorer](#sqlite-explorer) | |
| - [Advanced Usage](#advanced-usage) | |
| - [Low-Level Server](#low-level-server) | |
| - [Writing MCP Clients](#writing-mcp-clients) | |
| - [Server Capabilities](#server-capabilities) | |
| - [Proxy OAuth Server](#proxy-authorization-requests-upstream) | |
| - [Backwards Compatibility](#backwards-compatibility) | |
| ## Overview | |
| The Model Context Protocol allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction. This TypeScript SDK implements the full MCP specification, making it easy to: | |
| - Build MCP clients that can connect to any MCP server | |
| - Create MCP servers that expose resources, prompts and tools | |
| - Use standard transports like stdio and Streamable HTTP | |
| - Handle all MCP protocol messages and lifecycle events | |
| ## Installation | |
| ```bash | |
| npm install @modelcontextprotocol/sdk | |
| ``` | |
| ## Quick Start | |
| Let's create a simple MCP server that exposes a calculator tool and some data: | |
| ```typescript | |
| import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; | |
| import { z } from "zod"; | |
| // Create an MCP server | |
| const server = new McpServer({ | |
| name: "Demo", | |
| version: "1.0.0" | |
| }); | |
| // Add an addition tool | |
| server.tool("add", | |
| { a: z.number(), b: z.number() }, | |
| async ({ a, b }) => ({ | |
| content: [{ type: "text", text: String(a + b) }] | |
| }) | |
| ); | |
| // Add a dynamic greeting resource | |
| server.resource( | |
| "greeting", | |
| new ResourceTemplate("greeting://{name}", { list: undefined }), | |
| async (uri, { name }) => ({ | |
| contents: [{ | |
| uri: uri.href, | |
| text: `Hello, ${name}!` | |
| }] | |
| }) | |
| ); | |
| // Start receiving messages on stdin and sending messages on stdout | |
| const transport = new StdioServerTransport(); | |
| await server.connect(transport); | |
| ``` | |
| ## What is MCP? | |
| The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. Think of it like a web API, but specifically designed for LLM interactions. MCP servers can: | |
| - Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context) | |
| - Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect) | |
| - Define interaction patterns through **Prompts** (reusable templates for LLM interactions) | |
| - And more! | |
| ## Core Concepts | |
| ### Server | |
| The McpServer is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing: | |
| ```typescript | |
| const server = new McpServer({ | |
| name: "My App", | |
| version: "1.0.0" | |
| }); | |
| ``` | |
| ### Resources | |
| Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects: | |
| ```typescript | |
| // Static resource | |
| server.resource( | |
| "config", | |
| "config://app", | |
| async (uri) => ({ | |
| contents: [{ | |
| uri: uri.href, | |
| text: "App configuration here" | |
| }] | |
| }) | |
| ); | |
| // Dynamic resource with parameters | |
| server.resource( | |
| "user-profile", | |
| new ResourceTemplate("users://{userId}/profile", { list: undefined }), | |
| async (uri, { userId }) => ({ | |
| contents: [{ | |
| uri: uri.href, | |
| text: `Profile data for user ${userId}` | |
| }] | |
| }) | |
| ); | |
| ``` | |
| ### Tools | |
| Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects: | |
| ```typescript | |
| // Simple tool with parameters | |
| server.tool( | |
| "calculate-bmi", | |
| { | |
| weightKg: z.number(), | |
| heightM: z.number() | |
| }, | |
| async ({ weightKg, heightM }) => ({ | |
| content: [{ | |
| type: "text", | |
| text: String(weightKg / (heightM * heightM)) | |
| }] | |
| }) | |
| ); | |
| // Async tool with external API call | |
| server.tool( | |
| "fetch-weather", | |
| { city: z.string() }, | |
| async ({ city }) => { | |
| const response = await fetch(`https://api.weather.com/${city}`); | |
| const data = await response.text(); | |
| return { | |
| content: [{ type: "text", text: data }] | |
| }; | |
| } | |
| ); | |
| ``` | |
| ### Prompts | |
| Prompts are reusable templates that help LLMs interact with your server effectively: | |
| ```typescript | |
| server.prompt( | |
| "review-code", | |
| { code: z.string() }, | |
| ({ code }) => ({ | |
| messages: [{ | |
| role: "user", | |
| content: { | |
| type: "text", | |
| text: `Please review this code:\n\n${code}` | |
| } | |
| }] | |
| }) | |
| ); | |
| ``` | |
| ## Running Your Server | |
| MCP servers in TypeScript need to be connected to a transport to communicate with clients. How you start the server depends on the choice of transport: | |
| ### stdio | |
| For command-line tools and direct integrations: | |
| ```typescript | |
| import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; | |
| const server = new McpServer({ | |
| name: "example-server", | |
| version: "1.0.0" | |
| }); | |
| // ... set up server resources, tools, and prompts ... | |
| const transport = new StdioServerTransport(); | |
| await server.connect(transport); | |
| ``` | |
| ### Streamable HTTP | |
| For remote servers, set up a Streamable HTTP transport that handles both client requests and server-to-client notifications. | |
| #### With Session Management | |
| In some cases, servers need to be stateful. This is achieved by [session management](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#session-management). | |
| ```typescript | |
| import express from "express"; | |
| import { randomUUID } from "node:crypto"; | |
| import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; | |
| import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js" | |
| const app = express(); | |
| app.use(express.json()); | |
| // Map to store transports by session ID | |
| const transports: { [sessionId: string]: StreamableHTTPServerTransport } = {}; | |
| // Handle POST requests for client-to-server communication | |
| app.post('/mcp', async (req, res) => { | |
| // Check for existing session ID | |
| const sessionId = req.headers['mcp-session-id'] as string | undefined; | |
| let transport: StreamableHTTPServerTransport; | |
| if (sessionId && transports[sessionId]) { | |
| // Reuse existing transport | |
| transport = transports[sessionId]; | |
| } else if (!sessionId && isInitializeRequest(req.body)) { | |
| // New initialization request | |
| transport = new StreamableHTTPServerTransport({ | |
| sessionIdGenerator: () => randomUUID(), | |
| onsessioninitialized: (sessionId) => { | |
| // Store the transport by session ID | |
| transports[sessionId] = transport; | |
| } | |
| }); | |
| // Clean up transport when closed | |
| transport.onclose = () => { | |
| if (transport.sessionId) { | |
| delete transports[transport.sessionId]; | |
| } | |
| }; | |
| const server = new McpServer({ | |
| name: "example-server", | |
| version: "1.0.0" | |
| }); | |
| // ... set up server resources, tools, and prompts ... | |
| // Connect to the MCP server | |
| await server.connect(transport); | |
| } else { | |
| // Invalid request | |
| res.status(400).json({ | |
| jsonrpc: '2.0', | |
| error: { | |
| code: -32000, | |
| message: 'Bad Request: No valid session ID provided', | |
| }, | |
| id: null, | |
| }); | |
| return; | |
| } | |
| // Handle the request | |
| await transport.handleRequest(req, res, req.body); | |
| }); | |
| // Reusable handler for GET and DELETE requests | |
| const handleSessionRequest = async (req: express.Request, res: express.Response) => { | |
| const sessionId = req.headers['mcp-session-id'] as string | undefined; | |
| if (!sessionId || !transports[sessionId]) { | |
| res.status(400).send('Invalid or missing session ID'); | |
| return; | |
| } | |
| const transport = transports[sessionId]; | |
| await transport.handleRequest(req, res); | |
| }; | |
| // Handle GET requests for server-to-client notifications via SSE | |
| app.get('/mcp', handleSessionRequest); | |
| // Handle DELETE requests for session termination | |
| app.delete('/mcp', handleSessionRequest); | |
| app.listen(3000); | |
| ``` | |
| #### Without Session Management (Stateless) | |
| For simpler use cases where session management isn't needed: | |
| ```typescript | |
| const app = express(); | |
| app.use(express.json()); | |
| app.post('/mcp', async (req: Request, res: Response) => { | |
| // In stateless mode, create a new instance of transport and server for each request | |
| // to ensure complete isolation. A single instance would cause request ID collisions | |
| // when multiple clients connect concurrently. | |
| try { | |
| const server = getServer(); | |
| const transport: StreamableHTTPServerTransport = new StreamableHTTPServerTransport({ | |
| sessionIdGenerator: undefined, | |
| }); | |
| res.on('close', () => { | |
| console.log('Request closed'); | |
| transport.close(); | |
| server.close(); | |
| }); | |
| await server.connect(transport); | |
| await transport.handleRequest(req, res, req.body); | |
| } catch (error) { | |
| console.error('Error handling MCP request:', error); | |
| if (!res.headersSent) { | |
| res.status(500).json({ | |
| jsonrpc: '2.0', | |
| error: { | |
| code: -32603, | |
| message: 'Internal server error', | |
| }, | |
| id: null, | |
| }); | |
| } | |
| } | |
| }); | |
| app.get('/mcp', async (req: Request, res: Response) => { | |
| console.log('Received GET MCP request'); | |
| res.writeHead(405).end(JSON.stringify({ | |
| jsonrpc: "2.0", | |
| error: { | |
| code: -32000, | |
| message: "Method not allowed." | |
| }, | |
| id: null | |
| })); | |
| }); | |
| app.delete('/mcp', async (req: Request, res: Response) => { | |
| console.log('Received DELETE MCP request'); | |
| res.writeHead(405).end(JSON.stringify({ | |
| jsonrpc: "2.0", | |
| error: { | |
| code: -32000, | |
| message: "Method not allowed." | |
| }, | |
| id: null | |
| })); | |
| }); | |
| // Start the server | |
| const PORT = 3000; | |
| app.listen(PORT, () => { | |
| console.log(`MCP Stateless Streamable HTTP Server listening on port ${PORT}`); | |
| }); | |
| ``` | |
| This stateless approach is useful for: | |
| - Simple API wrappers | |
| - RESTful scenarios where each request is independent | |
| - Horizontally scaled deployments without shared session state | |
| ### Testing and Debugging | |
| To test your server, you can use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector). See its README for more information. | |
| ## Examples | |
| ### Echo Server | |
| A simple server demonstrating resources, tools, and prompts: | |
| ```typescript | |
| import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| import { z } from "zod"; | |
| const server = new McpServer({ | |
| name: "Echo", | |
| version: "1.0.0" | |
| }); | |
| server.resource( | |
| "echo", | |
| new ResourceTemplate("echo://{message}", { list: undefined }), | |
| async (uri, { message }) => ({ | |
| contents: [{ | |
| uri: uri.href, | |
| text: `Resource echo: ${message}` | |
| }] | |
| }) | |
| ); | |
| server.tool( | |
| "echo", | |
| { message: z.string() }, | |
| async ({ message }) => ({ | |
| content: [{ type: "text", text: `Tool echo: ${message}` }] | |
| }) | |
| ); | |
| server.prompt( | |
| "echo", | |
| { message: z.string() }, | |
| ({ message }) => ({ | |
| messages: [{ | |
| role: "user", | |
| content: { | |
| type: "text", | |
| text: `Please process this message: ${message}` | |
| } | |
| }] | |
| }) | |
| ); | |
| ``` | |
| ### SQLite Explorer | |
| A more complex example showing database integration: | |
| ```typescript | |
| import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| import sqlite3 from "sqlite3"; | |
| import { promisify } from "util"; | |
| import { z } from "zod"; | |
| const server = new McpServer({ | |
| name: "SQLite Explorer", | |
| version: "1.0.0" | |
| }); | |
| // Helper to create DB connection | |
| const getDb = () => { | |
| const db = new sqlite3.Database("database.db"); | |
| return { | |
| all: promisify<string, any[]>(db.all.bind(db)), | |
| close: promisify(db.close.bind(db)) | |
| }; | |
| }; | |
| server.resource( | |
| "schema", | |
| "schema://main", | |
| async (uri) => { | |
| const db = getDb(); | |
| try { | |
| const tables = await db.all( | |
| "SELECT sql FROM sqlite_master WHERE type='table'" | |
| ); | |
| return { | |
| contents: [{ | |
| uri: uri.href, | |
| text: tables.map((t: {sql: string}) => t.sql).join("\n") | |
| }] | |
| }; | |
| } finally { | |
| await db.close(); | |
| } | |
| } | |
| ); | |
| server.tool( | |
| "query", | |
| { sql: z.string() }, | |
| async ({ sql }) => { | |
| const db = getDb(); | |
| try { | |
| const results = await db.all(sql); | |
| return { | |
| content: [{ | |
| type: "text", | |
| text: JSON.stringify(results, null, 2) | |
| }] | |
| }; | |
| } catch (err: unknown) { | |
| const error = err as Error; | |
| return { | |
| content: [{ | |
| type: "text", | |
| text: `Error: ${error.message}` | |
| }], | |
| isError: true | |
| }; | |
| } finally { | |
| await db.close(); | |
| } | |
| } | |
| ); | |
| ``` | |
| ## Advanced Usage | |
| ### Dynamic Servers | |
| If you want to offer an initial set of tools/prompts/resources, but later add additional ones based on user action or external state change, you can add/update/remove them _after_ the Server is connected. This will automatically emit the corresponding `listChanged` notificaions: | |
| ```ts | |
| import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| import { z } from "zod"; | |
| const server = new McpServer({ | |
| name: "Dynamic Example", | |
| version: "1.0.0" | |
| }); | |
| const listMessageTool = server.tool( | |
| "listMessages", | |
| { channel: z.string() }, | |
| async ({ channel }) => ({ | |
| content: [{ type: "text", text: await listMessages(channel) }] | |
| }) | |
| ); | |
| const putMessageTool = server.tool( | |
| "putMessage", | |
| { channel: z.string(), message: z.string() }, | |
| async ({ channel, message }) => ({ | |
| content: [{ type: "text", text: await putMessage(channel, string) }] | |
| }) | |
| ); | |
| // Until we upgrade auth, `putMessage` is disabled (won't show up in listTools) | |
| putMessageTool.disable() | |
| const upgradeAuthTool = server.tool( | |
| "upgradeAuth", | |
| { permission: z.enum(["write', vadmin"])}, | |
| // Any mutations here will automatically emit `listChanged` notifications | |
| async ({ permission }) => { | |
| const { ok, err, previous } = await upgradeAuthAndStoreToken(permission) | |
| if (!ok) return {content: [{ type: "text", text: `Error: ${err}` }]} | |
| // If we previously had read-only access, 'putMessage' is now available | |
| if (previous === "read") { | |
| putMessageTool.enable() | |
| } | |
| if (permission === 'write') { | |
| // If we've just upgraded to 'write' permissions, we can still call 'upgradeAuth' | |
| // but can only upgrade to 'admin'. | |
| upgradeAuthTool.update({ | |
| paramSchema: { permission: z.enum(["admin"]) }, // change validation rules | |
| }) | |
| } else { | |
| // If we're now an admin, we no longer have anywhere to upgrade to, so fully remove that tool | |
| upgradeAuthTool.remove() | |
| } | |
| } | |
| ) | |
| // Connect as normal | |
| const transport = new StdioServerTransport(); | |
| await server.connect(transport); | |
| ``` | |
| ### Low-Level Server | |
| For more control, you can use the low-level Server class directly: | |
| ```typescript | |
| import { Server } from "@modelcontextprotocol/sdk/server/index.js"; | |
| import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; | |
| import { | |
| ListPromptsRequestSchema, | |
| GetPromptRequestSchema | |
| } from "@modelcontextprotocol/sdk/types.js"; | |
| const server = new Server( | |
| { | |
| name: "example-server", | |
| version: "1.0.0" | |
| }, | |
| { | |
| capabilities: { | |
| prompts: {} | |
| } | |
| } | |
| ); | |
| server.setRequestHandler(ListPromptsRequestSchema, async () => { | |
| return { | |
| prompts: [{ | |
| name: "example-prompt", | |
| description: "An example prompt template", | |
| arguments: [{ | |
| name: "arg1", | |
| description: "Example argument", | |
| required: true | |
| }] | |
| }] | |
| }; | |
| }); | |
| server.setRequestHandler(GetPromptRequestSchema, async (request) => { | |
| if (request.params.name !== "example-prompt") { | |
| throw new Error("Unknown prompt"); | |
| } | |
| return { | |
| description: "Example prompt", | |
| messages: [{ | |
| role: "user", | |
| content: { | |
| type: "text", | |
| text: "Example prompt text" | |
| } | |
| }] | |
| }; | |
| }); | |
| const transport = new StdioServerTransport(); | |
| await server.connect(transport); | |
| ``` | |
| ### Writing MCP Clients | |
| The SDK provides a high-level client interface: | |
| ```typescript | |
| import { Client } from "@modelcontextprotocol/sdk/client/index.js"; | |
| import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; | |
| const transport = new StdioClientTransport({ | |
| command: "node", | |
| args: ["server.js"] | |
| }); | |
| const client = new Client( | |
| { | |
| name: "example-client", | |
| version: "1.0.0" | |
| } | |
| ); | |
| await client.connect(transport); | |
| // List prompts | |
| const prompts = await client.listPrompts(); | |
| // Get a prompt | |
| const prompt = await client.getPrompt({ | |
| name: "example-prompt", | |
| arguments: { | |
| arg1: "value" | |
| } | |
| }); | |
| // List resources | |
| const resources = await client.listResources(); | |
| // Read a resource | |
| const resource = await client.readResource({ | |
| uri: "file:///example.txt" | |
| }); | |
| // Call a tool | |
| const result = await client.callTool({ | |
| name: "example-tool", | |
| arguments: { | |
| arg1: "value" | |
| } | |
| }); | |
| ``` | |
| ### Proxy Authorization Requests Upstream | |
| You can proxy OAuth requests to an external authorization provider: | |
| ```typescript | |
| import express from 'express'; | |
| import { ProxyOAuthServerProvider, mcpAuthRouter } from '@modelcontextprotocol/sdk'; | |
| const app = express(); | |
| const proxyProvider = new ProxyOAuthServerProvider({ | |
| endpoints: { | |
| authorizationUrl: "https://auth.external.com/oauth2/v1/authorize", | |
| tokenUrl: "https://auth.external.com/oauth2/v1/token", | |
| revocationUrl: "https://auth.external.com/oauth2/v1/revoke", | |
| }, | |
| verifyAccessToken: async (token) => { | |
| return { | |
| token, | |
| clientId: "123", | |
| scopes: ["openid", "email", "profile"], | |
| } | |
| }, | |
| getClient: async (client_id) => { | |
| return { | |
| client_id, | |
| redirect_uris: ["http://localhost:3000/callback"], | |
| } | |
| } | |
| }) | |
| app.use(mcpAuthRouter({ | |
| provider: proxyProvider, | |
| issuerUrl: new URL("http://auth.external.com"), | |
| baseUrl: new URL("http://mcp.example.com"), | |
| serviceDocumentationUrl: new URL("https://docs.example.com/"), | |
| })) | |
| ``` | |
| This setup allows you to: | |
| - Forward OAuth requests to an external provider | |
| - Add custom token validation logic | |
| - Manage client registrations | |
| - Provide custom documentation URLs | |
| - Maintain control over the OAuth flow while delegating to an external provider | |
| ### Backwards Compatibility | |
| Clients and servers with StreamableHttp tranport can maintain [backwards compatibility](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#backwards-compatibility) with the deprecated HTTP+SSE transport (from protocol version 2024-11-05) as follows | |
| #### Client-Side Compatibility | |
| For clients that need to work with both Streamable HTTP and older SSE servers: | |
| ```typescript | |
| import { Client } from "@modelcontextprotocol/sdk/client/index.js"; | |
| import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; | |
| import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; | |
| let client: Client|undefined = undefined | |
| const baseUrl = new URL(url); | |
| try { | |
| client = new Client({ | |
| name: 'streamable-http-client', | |
| version: '1.0.0' | |
| }); | |
| const transport = new StreamableHTTPClientTransport( | |
| new URL(baseUrl) | |
| ); | |
| await client.connect(transport); | |
| console.log("Connected using Streamable HTTP transport"); | |
| } catch (error) { | |
| // If that fails with a 4xx error, try the older SSE transport | |
| console.log("Streamable HTTP connection failed, falling back to SSE transport"); | |
| client = new Client({ | |
| name: 'sse-client', | |
| version: '1.0.0' | |
| }); | |
| const sseTransport = new SSEClientTransport(baseUrl); | |
| await client.connect(sseTransport); | |
| console.log("Connected using SSE transport"); | |
| } | |
| ``` | |
| #### Server-Side Compatibility | |
| For servers that need to support both Streamable HTTP and older clients: | |
| ```typescript | |
| import express from "express"; | |
| import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; | |
| import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; | |
| const server = new McpServer({ | |
| name: "backwards-compatible-server", | |
| version: "1.0.0" | |
| }); | |
| // ... set up server resources, tools, and prompts ... | |
| const app = express(); | |
| app.use(express.json()); | |
| // Store transports for each session type | |
| const transports = { | |
| streamable: {} as Record<string, StreamableHTTPServerTransport>, | |
| sse: {} as Record<string, SSEServerTransport> | |
| }; | |
| // Modern Streamable HTTP endpoint | |
| app.all('/mcp', async (req, res) => { | |
| // Handle Streamable HTTP transport for modern clients | |
| // Implementation as shown in the "With Session Management" example | |
| // ... | |
| }); | |
| // Legacy SSE endpoint for older clients | |
| app.get('/sse', async (req, res) => { | |
| // Create SSE transport for legacy clients | |
| const transport = new SSEServerTransport('/messages', res); | |
| transports.sse[transport.sessionId] = transport; | |
| res.on("close", () => { | |
| delete transports.sse[transport.sessionId]; | |
| }); | |
| await server.connect(transport); | |
| }); | |
| // Legacy message endpoint for older clients | |
| app.post('/messages', async (req, res) => { | |
| const sessionId = req.query.sessionId as string; | |
| const transport = transports.sse[sessionId]; | |
| if (transport) { | |
| await transport.handlePostMessage(req, res, req.body); | |
| } else { | |
| res.status(400).send('No transport found for sessionId'); | |
| } | |
| }); | |
| app.listen(3000); | |
| ``` | |
| **Note**: The SSE transport is now deprecated in favor of Streamable HTTP. New implementations should use Streamable HTTP, and existing SSE implementations should plan to migrate. | |
| ## Documentation | |
| - [Model Context Protocol documentation](https://modelcontextprotocol.io) | |
| - [MCP Specification](https://spec.modelcontextprotocol.io) | |
| - [Example Servers](https://github.com/modelcontextprotocol/servers) | |
| ## Contributing | |
| Issues and pull requests are welcome on GitHub at https://github.com/modelcontextprotocol/typescript-sdk. | |
| ## License | |
| This project is licensed under the MIT License—see the [LICENSE](LICENSE) file for details. | |