From 2d8a74394bd88db6e48bf728acdb756b86249e78 Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Mon, 9 Feb 2026 14:54:57 -0600 Subject: [PATCH 1/6] Add type-checked code snippets to `docs/server.md` Use the `sync-snippets` mechanism to inject type-checked code from `serverGuide.examples.ts` into `docs/server.md`. 10 snippet regions covering transports, tools, resources, prompts, `completable()`, `ResourceLink`, `ResourceTemplate`, and DNS rebinding. Fixes three bugs in existing illustrative snippets where `inputSchema`, `outputSchema`, and `argsSchema` used raw objects instead of `z.object()`. Removes four broken links to `simpleSseServer.ts` and `sseAndStreamableHttpCompatibleServer.ts` (deleted in v2 when `SSEServerTransport` was removed). Updates the deprecated SSE section to reflect this. Adds `> [!NOTE]` callouts linking to full runnable examples alongside each inline snippet. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/server.md | 215 ++++++++++++----- examples/server/src/serverGuide.examples.ts | 251 ++++++++++++++++++++ 2 files changed, 403 insertions(+), 63 deletions(-) create mode 100644 examples/server/src/serverGuide.examples.ts diff --git a/docs/server.md b/docs/server.md index 105871bc1..7660487eb 100644 --- a/docs/server.md +++ b/docs/server.md @@ -7,7 +7,6 @@ title: Server This SDK lets you build MCP servers in TypeScript and connect them to different transports. For most use cases you will use `McpServer` from `@modelcontextprotocol/server` and choose one of: - **Streamable HTTP** (recommended for remote servers) -- **HTTP + SSE** (deprecated, for backwards compatibility only) - **stdio** (for local, process‑spawned integrations) For a complete, runnable example server, see: @@ -15,8 +14,6 @@ For a complete, runnable example server, see: - [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) – feature‑rich Streamable HTTP server - [`jsonResponseStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/jsonResponseStreamableHttp.ts) – Streamable HTTP with JSON response mode - [`simpleStatelessStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStatelessStreamableHttp.ts) – stateless Streamable HTTP server -- [`simpleSseServer.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleSseServer.ts) – deprecated HTTP+SSE transport -- [`sseAndStreamableHttpCompatibleServer.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/sseAndStreamableHttpCompatibleServer.ts) – backwards‑compatible server for old and new clients ## Transports @@ -29,11 +26,20 @@ Streamable HTTP is the modern, fully featured transport. It supports: - Optional JSON‑only response mode with no SSE - Session management and resumability -Key examples: +A minimal stateful setup: -- [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) – sessions, logging, tasks, elicitation, auth hooks -- [`jsonResponseStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/jsonResponseStreamableHttp.ts) – `enableJsonResponse: true`, no SSE -- [`standaloneSseWithGetStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/standaloneSseWithGetStreamableHttp.ts) – notifications with Streamable HTTP GET + SSE +```ts source="../examples/server/src/serverGuide.examples.ts#streamableHttp_stateful" +const server = new McpServer({ name: 'my-server', version: '1.0.0' }); + +const transport = new NodeStreamableHTTPServerTransport({ + sessionIdGenerator: () => randomUUID() +}); + +await server.connect(transport); +``` + +> [!NOTE] +> For full runnable examples, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) (sessions, logging, tasks, elicitation, auth hooks), [`jsonResponseStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/jsonResponseStreamableHttp.ts) (`enableJsonResponse: true`, no SSE), and [`standaloneSseWithGetStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/standaloneSseWithGetStreamableHttp.ts) (notifications with Streamable HTTP GET + SSE). See the MCP spec for full transport details: `https://modelcontextprotocol.io/specification/2025-11-25/basic/transports` @@ -44,53 +50,58 @@ Streamable HTTP can run: - **Stateless** – no session tracking, ideal for simple API‑style servers. - **Stateful** – sessions have IDs, and you can enable resumability and advanced features. -Examples: +The key difference is the `sessionIdGenerator` option. Pass `undefined` for stateless mode: -- Stateless Streamable HTTP: [`simpleStatelessStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStatelessStreamableHttp.ts) -- Stateful with resumability: [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) +```ts source="../examples/server/src/serverGuide.examples.ts#streamableHttp_stateless" +const server = new McpServer({ name: 'my-server', version: '1.0.0' }); -### Deprecated HTTP + SSE +const transport = new NodeStreamableHTTPServerTransport({ + sessionIdGenerator: undefined +}); -The older HTTP+SSE transport (protocol version 2024‑11‑05) is supported only for backwards compatibility. New implementations should prefer Streamable HTTP. +await server.connect(transport); +``` + +> [!NOTE] +> For full runnable examples, see [`simpleStatelessStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStatelessStreamableHttp.ts) (stateless) and [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) (stateful with resumability). + +### Deprecated HTTP + SSE -Examples: +The older HTTP+SSE server transport (protocol version 2024‑11‑05) has been removed from the SDK. New implementations should use Streamable HTTP. -- Legacy SSE server: [`simpleSseServer.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleSseServer.ts) -- Backwards‑compatible server (Streamable HTTP + SSE): - [`sseAndStreamableHttpCompatibleServer.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/sseAndStreamableHttpCompatibleServer.ts) +Clients can still connect to legacy SSE servers using `SSEClientTransport` from `@modelcontextprotocol/client`. ## Running your server -For a minimal “getting started” experience: +For a minimal "getting started" experience: -1. Start from [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts). -2. Remove features you do not need (tasks, advanced logging, OAuth, etc.). -3. Register your own tools, resources and prompts. +1. Register your tools, resources, and prompts (see [below](#tools-resources-and-prompts)). +2. Create a transport and connect it to your server. +3. Wire the transport into your HTTP framework or use stdio. -For more detailed patterns (stateless vs stateful, JSON response mode, CORS, DNS rebind protection), see the examples above and the MCP spec sections on transports. +For more detailed patterns (stateless vs stateful, JSON response mode, CORS, DNS rebind protection), see the examples and the MCP spec sections on transports. -## DNS rebinding protection +> [!NOTE] +> For a feature‑rich starting point, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts). Remove features you do not need (tasks, advanced logging, OAuth, etc.) and register your own tools, resources and prompts. -MCP servers running on localhost are vulnerable to DNS rebinding attacks. Use `createMcpExpressApp()` to create an Express app with DNS rebinding protection enabled by default: +## DNS rebinding protection -```typescript -import { createMcpExpressApp } from '@modelcontextprotocol/express'; +MCP servers running on localhost are vulnerable to DNS rebinding attacks. Use `createMcpExpressApp()` from `@modelcontextprotocol/express` to create an Express app with DNS rebinding protection enabled by default: -// Protection auto-enabled (default host is 127.0.0.1) +```ts source="../examples/server/src/serverGuide.examples.ts#dnsRebinding_basic" +// Default: DNS rebinding protection auto-enabled (host is 127.0.0.1) const app = createMcpExpressApp(); -// Protection auto-enabled for localhost -const app = createMcpExpressApp({ host: 'localhost' }); +// DNS rebinding protection also auto-enabled for localhost +const appLocal = createMcpExpressApp({ host: 'localhost' }); -// No auto protection when binding to all interfaces, unless you provide allowedHosts -const app = createMcpExpressApp({ host: '0.0.0.0' }); +// No automatic protection when binding to all interfaces +const appOpen = createMcpExpressApp({ host: '0.0.0.0' }); ``` When binding to `0.0.0.0` / `::`, provide an allow-list of hosts: -```typescript -import { createMcpExpressApp } from '@modelcontextprotocol/express'; - +```ts source="../examples/server/src/serverGuide.examples.ts#dnsRebinding_allowedHosts" const app = createMcpExpressApp({ host: '0.0.0.0', allowedHosts: ['localhost', '127.0.0.1', 'myhost.local'] @@ -103,19 +114,19 @@ const app = createMcpExpressApp({ Tools let MCP clients ask your server to take actions. They are usually the main way that LLMs call into your application. -A typical registration with `registerTool` looks like this: +A typical registration with `registerTool`: -```typescript +```ts source="../examples/server/src/serverGuide.examples.ts#registerTool_basic" server.registerTool( 'calculate-bmi', { title: 'BMI Calculator', description: 'Calculate Body Mass Index', - inputSchema: { + inputSchema: z.object({ weightKg: z.number(), heightM: z.number() - }, - outputSchema: { bmi: z.number() } + }), + outputSchema: z.object({ bmi: z.number() }) }, async ({ weightKg, heightM }) => { const output = { bmi: weightKg / (heightM * heightM) }; @@ -127,24 +138,50 @@ server.registerTool( ); ``` -This snippet is illustrative only; for runnable servers that expose tools, see: - -- [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) -- [`toolWithSampleServer.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/toolWithSampleServer.ts) +> [!NOTE] +> For full runnable examples, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) and [`toolWithSampleServer.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/toolWithSampleServer.ts). #### ResourceLink outputs -Tools can return `resource_link` content items to reference large resources without embedding them directly, allowing clients to fetch only what they need. +Tools can return `resource_link` content items to reference large resources without embedding them directly, allowing clients to fetch only what they need: -The README’s `list-files` example shows the pattern conceptually; for concrete usage, see the Streamable HTTP examples in `examples/server/src`. +```ts source="../examples/server/src/serverGuide.examples.ts#registerTool_resourceLink" +server.registerTool( + 'list-files', + { + title: 'List Files', + description: 'Returns files as resource links without embedding content' + }, + async (): Promise => { + const links: ResourceLink[] = [ + { + type: 'resource_link', + uri: 'file:///projects/readme.md', + name: 'README', + mimeType: 'text/markdown' + }, + { + type: 'resource_link', + uri: 'file:///projects/config.json', + name: 'Config', + mimeType: 'application/json' + } + ]; + return { content: links }; + } +); +``` + +> [!NOTE] +> For a full runnable example with `ResourceLink` outputs, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts). ### Resources Resources expose data to clients, but should not perform heavy computation or side‑effects. They are ideal for configuration, documents, or other reference data. -Conceptually, you might register resources like: +A static resource at a fixed URI: -```typescript +```ts source="../examples/server/src/serverGuide.examples.ts#registerResource_static" server.registerResource( 'config', 'config://app', @@ -159,9 +196,37 @@ server.registerResource( ); ``` -Dynamic resources use `ResourceTemplate` and can support completions on path parameters. For full runnable examples of resources: +Dynamic resources use `ResourceTemplate` and can support completions on path parameters: -- [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) +```ts source="../examples/server/src/serverGuide.examples.ts#registerResource_template" +server.registerResource( + 'user-profile', + new ResourceTemplate('user://{userId}/profile', { + list: async () => ({ + resources: [ + { uri: 'user://123/profile', name: 'Alice' }, + { uri: 'user://456/profile', name: 'Bob' } + ] + }) + }), + { + title: 'User Profile', + description: 'User profile data', + mimeType: 'application/json' + }, + async (uri, { userId }) => ({ + contents: [ + { + uri: uri.href, + text: JSON.stringify({ userId, name: 'Example User' }) + } + ] + }) +); +``` + +> [!NOTE] +> For full runnable examples of resources, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts). ### Prompts @@ -169,20 +234,22 @@ Prompts are reusable templates that help humans (or client UIs) talk to models i A minimal prompt: -```typescript +```ts source="../examples/server/src/serverGuide.examples.ts#registerPrompt_basic" server.registerPrompt( 'review-code', { title: 'Code Review', description: 'Review code for best practices and potential issues', - argsSchema: { code: z.string() } + argsSchema: z.object({ + code: z.string() + }) }, ({ code }) => ({ messages: [ { - role: 'user', + role: 'user' as const, content: { - type: 'text', + type: 'text' as const, text: `Please review this code:\n\n${code}` } } @@ -191,15 +258,40 @@ server.registerPrompt( ); ``` -For prompts integrated into a full server, see: - -- [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) +> [!NOTE] +> For prompts integrated into a full server, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts). ### Completions -Both prompts and resources can support argument completions. On the client side, you use `client.complete()` with a reference to the prompt or resource and the partially‑typed argument. +Both prompts and resources can support argument completions. Wrap a field in the `argsSchema` with `completable()` to provide autocompletion suggestions: + +```ts source="../examples/server/src/serverGuide.examples.ts#registerPrompt_completion" +server.registerPrompt( + 'review-code', + { + title: 'Code Review', + description: 'Review code for best practices', + argsSchema: z.object({ + language: completable(z.string().describe('Programming language'), value => + ['typescript', 'javascript', 'python', 'rust', 'go'].filter(lang => lang.startsWith(value)) + ) + }) + }, + ({ language }) => ({ + messages: [ + { + role: 'user' as const, + content: { + type: 'text' as const, + text: `Review this ${language} code for best practices.` + } + } + ] + }) +); +``` -See the MCP spec sections on prompts and resources for complete details, and [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/client/src/simpleStreamableHttp.ts) for client‑side usage patterns. +On the client side, you use `client.complete()` with a reference to the prompt or resource and the partially‑typed argument. See the MCP spec sections on prompts and resources for complete details, and [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/client/src/simpleStreamableHttp.ts) for client‑side usage patterns. ### Display names and metadata @@ -215,11 +307,8 @@ The SDK supports multi‑node deployments using Streamable HTTP. The high‑leve ## Backwards compatibility -To handle both modern and legacy clients: +To handle both modern and legacy clients, use a client that falls back from Streamable HTTP to SSE: -- Run a backwards‑compatible server: - - [`sseAndStreamableHttpCompatibleServer.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/sseAndStreamableHttpCompatibleServer.ts) -- Use a client that falls back from Streamable HTTP to SSE: - - [`streamableHttpWithSseFallbackClient.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/client/src/streamableHttpWithSseFallbackClient.ts) +- [`streamableHttpWithSseFallbackClient.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/client/src/streamableHttpWithSseFallbackClient.ts) -For the detailed protocol rules, see the “Backwards compatibility” section of the MCP spec. +For the detailed protocol rules, see the "Backwards compatibility" section of the MCP spec. diff --git a/examples/server/src/serverGuide.examples.ts b/examples/server/src/serverGuide.examples.ts new file mode 100644 index 000000000..6ed08a6ec --- /dev/null +++ b/examples/server/src/serverGuide.examples.ts @@ -0,0 +1,251 @@ +/** + * Type-checked examples for docs/server.md. + * + * Regions are synced into markdown code fences via `pnpm sync:snippets`. + * Each function wraps a single region. The function name matches the region name. + * + * @module + */ + +import { randomUUID } from 'node:crypto'; + +import { createMcpExpressApp } from '@modelcontextprotocol/express'; +import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node'; +import type { CallToolResult, ResourceLink } from '@modelcontextprotocol/server'; +import { completable, McpServer, ResourceTemplate } from '@modelcontextprotocol/server'; +import * as z from 'zod/v4'; + +// --------------------------------------------------------------------------- +// Tools, resources, and prompts +// --------------------------------------------------------------------------- + +/** Example: Registering a tool with inputSchema, outputSchema, and structuredContent. */ +function registerTool_basic(server: McpServer) { + //#region registerTool_basic + server.registerTool( + 'calculate-bmi', + { + title: 'BMI Calculator', + description: 'Calculate Body Mass Index', + inputSchema: z.object({ + weightKg: z.number(), + heightM: z.number() + }), + outputSchema: z.object({ bmi: z.number() }) + }, + async ({ weightKg, heightM }) => { + const output = { bmi: weightKg / (heightM * heightM) }; + return { + content: [{ type: 'text', text: JSON.stringify(output) }], + structuredContent: output + }; + } + ); + //#endregion registerTool_basic +} + +/** Example: Tool returning resource_link content items. */ +function registerTool_resourceLink(server: McpServer) { + //#region registerTool_resourceLink + server.registerTool( + 'list-files', + { + title: 'List Files', + description: 'Returns files as resource links without embedding content' + }, + async (): Promise => { + const links: ResourceLink[] = [ + { + type: 'resource_link', + uri: 'file:///projects/readme.md', + name: 'README', + mimeType: 'text/markdown' + }, + { + type: 'resource_link', + uri: 'file:///projects/config.json', + name: 'Config', + mimeType: 'application/json' + } + ]; + return { content: links }; + } + ); + //#endregion registerTool_resourceLink +} + +/** Example: Registering a static resource at a fixed URI. */ +function registerResource_static(server: McpServer) { + //#region registerResource_static + server.registerResource( + 'config', + 'config://app', + { + title: 'Application Config', + description: 'Application configuration data', + mimeType: 'text/plain' + }, + async uri => ({ + contents: [{ uri: uri.href, text: 'App configuration here' }] + }) + ); + //#endregion registerResource_static +} + +/** Example: Dynamic resource with ResourceTemplate and listing. */ +function registerResource_template(server: McpServer) { + //#region registerResource_template + server.registerResource( + 'user-profile', + new ResourceTemplate('user://{userId}/profile', { + list: async () => ({ + resources: [ + { uri: 'user://123/profile', name: 'Alice' }, + { uri: 'user://456/profile', name: 'Bob' } + ] + }) + }), + { + title: 'User Profile', + description: 'User profile data', + mimeType: 'application/json' + }, + async (uri, { userId }) => ({ + contents: [ + { + uri: uri.href, + text: JSON.stringify({ userId, name: 'Example User' }) + } + ] + }) + ); + //#endregion registerResource_template +} + +/** Example: Registering a prompt with argsSchema. */ +function registerPrompt_basic(server: McpServer) { + //#region registerPrompt_basic + server.registerPrompt( + 'review-code', + { + title: 'Code Review', + description: 'Review code for best practices and potential issues', + argsSchema: z.object({ + code: z.string() + }) + }, + ({ code }) => ({ + messages: [ + { + role: 'user' as const, + content: { + type: 'text' as const, + text: `Please review this code:\n\n${code}` + } + } + ] + }) + ); + //#endregion registerPrompt_basic +} + +/** Example: Prompt with completable argsSchema for autocompletion. */ +function registerPrompt_completion(server: McpServer) { + //#region registerPrompt_completion + server.registerPrompt( + 'review-code', + { + title: 'Code Review', + description: 'Review code for best practices', + argsSchema: z.object({ + language: completable(z.string().describe('Programming language'), value => + ['typescript', 'javascript', 'python', 'rust', 'go'].filter(lang => lang.startsWith(value)) + ) + }) + }, + ({ language }) => ({ + messages: [ + { + role: 'user' as const, + content: { + type: 'text' as const, + text: `Review this ${language} code for best practices.` + } + } + ] + }) + ); + //#endregion registerPrompt_completion +} + +// --------------------------------------------------------------------------- +// Transports +// --------------------------------------------------------------------------- + +/** Example: Stateful Streamable HTTP transport with session management. */ +async function streamableHttp_stateful() { + //#region streamableHttp_stateful + const server = new McpServer({ name: 'my-server', version: '1.0.0' }); + + const transport = new NodeStreamableHTTPServerTransport({ + sessionIdGenerator: () => randomUUID() + }); + + await server.connect(transport); + //#endregion streamableHttp_stateful +} + +/** Example: Stateless Streamable HTTP transport (no session persistence). */ +async function streamableHttp_stateless() { + //#region streamableHttp_stateless + const server = new McpServer({ name: 'my-server', version: '1.0.0' }); + + const transport = new NodeStreamableHTTPServerTransport({ + sessionIdGenerator: undefined + }); + + await server.connect(transport); + //#endregion streamableHttp_stateless +} + +// --------------------------------------------------------------------------- +// DNS rebinding protection +// --------------------------------------------------------------------------- + +/** Example: createMcpExpressApp with different host bindings. */ +function dnsRebinding_basic() { + //#region dnsRebinding_basic + // Default: DNS rebinding protection auto-enabled (host is 127.0.0.1) + const app = createMcpExpressApp(); + + // DNS rebinding protection also auto-enabled for localhost + const appLocal = createMcpExpressApp({ host: 'localhost' }); + + // No automatic protection when binding to all interfaces + const appOpen = createMcpExpressApp({ host: '0.0.0.0' }); + //#endregion dnsRebinding_basic + return { app, appLocal, appOpen }; +} + +/** Example: createMcpExpressApp with allowedHosts for non-localhost binding. */ +function dnsRebinding_allowedHosts() { + //#region dnsRebinding_allowedHosts + const app = createMcpExpressApp({ + host: '0.0.0.0', + allowedHosts: ['localhost', '127.0.0.1', 'myhost.local'] + }); + //#endregion dnsRebinding_allowedHosts + return app; +} + +// Suppress unused-function warnings (functions exist solely for type-checking) +void registerTool_basic; +void registerTool_resourceLink; +void registerResource_static; +void registerResource_template; +void registerPrompt_basic; +void registerPrompt_completion; +void streamableHttp_stateful; +void streamableHttp_stateless; +void dnsRebinding_basic; +void dnsRebinding_allowedHosts; From 8066e016ca2ab4cca8a3b8598c9e375217af5a94 Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Mon, 9 Feb 2026 15:33:09 -0600 Subject: [PATCH 2/6] Remove vestigial references to deprecated SSE transport from `docs/server.md` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SSE-only server transport was removed from the SDK, but the server guide still had subtle language implying it existed as an alternative: - "recommended for remote servers" → "for remote servers" (it is the only remote transport, not merely recommended) - "modern, fully featured transport" → "HTTP‑based transport" (no older alternative to contrast against) - Removed the "Deprecated HTTP + SSE" section entirely — this is a client‑side concern already covered in `docs/client.md` - Removed the "Backwards compatibility" section — also a client‑side concern already covered in `docs/client.md` Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/server.md | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/docs/server.md b/docs/server.md index 7660487eb..e84b51bc8 100644 --- a/docs/server.md +++ b/docs/server.md @@ -6,7 +6,7 @@ title: Server This SDK lets you build MCP servers in TypeScript and connect them to different transports. For most use cases you will use `McpServer` from `@modelcontextprotocol/server` and choose one of: -- **Streamable HTTP** (recommended for remote servers) +- **Streamable HTTP** (for remote servers) - **stdio** (for local, process‑spawned integrations) For a complete, runnable example server, see: @@ -19,7 +19,7 @@ For a complete, runnable example server, see: ### Streamable HTTP -Streamable HTTP is the modern, fully featured transport. It supports: +Streamable HTTP is the HTTP‑based transport. It supports: - Request/response over HTTP POST - Server‑to‑client notifications over SSE (when enabled) @@ -65,12 +65,6 @@ await server.connect(transport); > [!NOTE] > For full runnable examples, see [`simpleStatelessStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStatelessStreamableHttp.ts) (stateless) and [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) (stateful with resumability). -### Deprecated HTTP + SSE - -The older HTTP+SSE server transport (protocol version 2024‑11‑05) has been removed from the SDK. New implementations should use Streamable HTTP. - -Clients can still connect to legacy SSE servers using `SSEClientTransport` from `@modelcontextprotocol/client`. - ## Running your server For a minimal "getting started" experience: @@ -305,10 +299,3 @@ The SDK supports multi‑node deployments using Streamable HTTP. The high‑leve - [`examples/server/README.md`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/README.md#multi-node-deployment-patterns) -## Backwards compatibility - -To handle both modern and legacy clients, use a client that falls back from Streamable HTTP to SSE: - -- [`streamableHttpWithSseFallbackClient.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/client/src/streamableHttpWithSseFallbackClient.ts) - -For the detailed protocol rules, see the "Backwards compatibility" section of the MCP spec. From dce8963d1dd68e3e3dee0952fe7c78620452d931 Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Mon, 9 Feb 2026 15:44:42 -0600 Subject: [PATCH 3/6] Remove client-side content from `docs/server.md` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Completions section included a paragraph about `client.complete()` and a link to a client example — replaced with a brief cross-reference to the Client guide. The "Display names and metadata" subsection only described the client-side `getDisplayName` helper; every inline example already demonstrates the `title` field, so the section was redundant for server authors. Dropped it entirely. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/server.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/server.md b/docs/server.md index e84b51bc8..4861745bb 100644 --- a/docs/server.md +++ b/docs/server.md @@ -285,13 +285,7 @@ server.registerPrompt( ); ``` -On the client side, you use `client.complete()` with a reference to the prompt or resource and the partially‑typed argument. See the MCP spec sections on prompts and resources for complete details, and [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/client/src/simpleStreamableHttp.ts) for client‑side usage patterns. - -### Display names and metadata - -Tools, resources and prompts support a `title` field for human‑readable names. Older APIs can also attach `annotations.title`. To compute the correct display name on the client, use: - -- `getDisplayName` from `@modelcontextprotocol/client` +For client-side completion usage, see the [Client guide](client.md). ## Multi‑node deployment patterns From b311af7ce7f05dedb4c41879ed55883d03f3940e Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Mon, 9 Feb 2026 16:01:21 -0600 Subject: [PATCH 4/6] Add `{@linkcode}` cross-references to `docs/server.md` Replace plain backtick code references with TypeDoc `{@linkcode}` links for `McpServer`, `McpServer#registerTool`, `ResourceTemplate`, and `completable()`. Also add backtick formatting to the `ResourceLink` heading. These link to the `@modelcontextprotocol/server` package using fully-qualified module paths required by TypeDoc's `entryPointStrategy: "packages"` mode. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/server.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/server.md b/docs/server.md index 4861745bb..769aa7ae8 100644 --- a/docs/server.md +++ b/docs/server.md @@ -4,7 +4,7 @@ title: Server ## Server overview -This SDK lets you build MCP servers in TypeScript and connect them to different transports. For most use cases you will use `McpServer` from `@modelcontextprotocol/server` and choose one of: +This SDK lets you build MCP servers in TypeScript and connect them to different transports. For most use cases you will use {@linkcode @modelcontextprotocol/server!server/mcp.McpServer | McpServer} from `@modelcontextprotocol/server` and choose one of: - **Streamable HTTP** (for remote servers) - **stdio** (for local, process‑spawned integrations) @@ -108,7 +108,7 @@ const app = createMcpExpressApp({ Tools let MCP clients ask your server to take actions. They are usually the main way that LLMs call into your application. -A typical registration with `registerTool`: +A typical registration with {@linkcode @modelcontextprotocol/server!server/mcp.McpServer#registerTool | registerTool}: ```ts source="../examples/server/src/serverGuide.examples.ts#registerTool_basic" server.registerTool( @@ -135,7 +135,7 @@ server.registerTool( > [!NOTE] > For full runnable examples, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) and [`toolWithSampleServer.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/toolWithSampleServer.ts). -#### ResourceLink outputs +#### `ResourceLink` outputs Tools can return `resource_link` content items to reference large resources without embedding them directly, allowing clients to fetch only what they need: @@ -190,7 +190,7 @@ server.registerResource( ); ``` -Dynamic resources use `ResourceTemplate` and can support completions on path parameters: +Dynamic resources use {@linkcode @modelcontextprotocol/server!server/mcp.ResourceTemplate | ResourceTemplate} and can support completions on path parameters: ```ts source="../examples/server/src/serverGuide.examples.ts#registerResource_template" server.registerResource( @@ -257,7 +257,7 @@ server.registerPrompt( ### Completions -Both prompts and resources can support argument completions. Wrap a field in the `argsSchema` with `completable()` to provide autocompletion suggestions: +Both prompts and resources can support argument completions. Wrap a field in the `argsSchema` with {@linkcode @modelcontextprotocol/server!server/completable.completable | completable()} to provide autocompletion suggestions: ```ts source="../examples/server/src/serverGuide.examples.ts#registerPrompt_completion" server.registerPrompt( From 508f86d59b682a18e0f3876edff2f64e387340e2 Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Mon, 9 Feb 2026 17:40:37 -0600 Subject: [PATCH 5/6] Add new `docs/server.md` sections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expand `docs/server.md` with three new inline sections: - `#### JSON response mode` — `enableJsonResponse: true` transport option - `### stdio` — `StdioServerTransport` pattern with `{@linkcode}` - `#### Logging` — `ctx.mcpReq.log()` in tool handlers, with `logging` capability snippet Add a "More server features" table at the end of `docs/server.md` linking eight additional capabilities (elicitation, sampling, tool annotations, Web Standard transport, session management, resumability, CORS, tasks) to runnable examples and `docs/capabilities.md`. Demote "Stateless vs stateful sessions" and "JSON response mode" from `h3` to `h4` so they nest under the `### Streamable HTTP` parent. Add three new synced regions to `serverGuide.examples.ts`: `logging_capability`, `registerTool_logging`, `streamableHttp_jsonResponse`, `stdio_basic`. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/server.md | 81 +++++++++++++++++++-- examples/server/src/serverGuide.examples.ts | 57 ++++++++++++++- 2 files changed, 130 insertions(+), 8 deletions(-) diff --git a/docs/server.md b/docs/server.md index 769aa7ae8..d4d2499e5 100644 --- a/docs/server.md +++ b/docs/server.md @@ -43,7 +43,7 @@ await server.connect(transport); See the MCP spec for full transport details: `https://modelcontextprotocol.io/specification/2025-11-25/basic/transports` -### Stateless vs stateful sessions +#### Stateless vs stateful sessions Streamable HTTP can run: @@ -65,6 +65,34 @@ await server.connect(transport); > [!NOTE] > For full runnable examples, see [`simpleStatelessStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStatelessStreamableHttp.ts) (stateless) and [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) (stateful with resumability). +#### JSON response mode + +If you do not need SSE streaming, set `enableJsonResponse: true`. The server will return plain JSON responses to every POST and reject GET requests with `405`: + +```ts source="../examples/server/src/serverGuide.examples.ts#streamableHttp_jsonResponse" +const server = new McpServer({ name: 'my-server', version: '1.0.0' }); + +const transport = new NodeStreamableHTTPServerTransport({ + sessionIdGenerator: () => randomUUID(), + enableJsonResponse: true +}); + +await server.connect(transport); +``` + +> [!NOTE] +> For a full runnable example, see [`jsonResponseStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/jsonResponseStreamableHttp.ts). + +### stdio + +For local, process‑spawned integrations (Claude Desktop, CLI tools), use {@linkcode @modelcontextprotocol/server!server/stdio.StdioServerTransport | StdioServerTransport}: + +```ts source="../examples/server/src/serverGuide.examples.ts#stdio_basic" +const server = new McpServer({ name: 'my-server', version: '1.0.0' }); +const transport = new StdioServerTransport(); +await server.connect(transport); +``` + ## Running your server For a minimal "getting started" experience: @@ -169,6 +197,36 @@ server.registerTool( > [!NOTE] > For a full runnable example with `ResourceLink` outputs, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts). +#### Logging + +Use `ctx.mcpReq.log(level, data)` (from {@linkcode @modelcontextprotocol/server!index.ServerContext | ServerContext}) inside a tool handler to send structured log messages to the client. The server must declare the `logging` capability: + +```ts source="../examples/server/src/serverGuide.examples.ts#logging_capability" +const server = new McpServer({ name: 'my-server', version: '1.0.0' }, { capabilities: { logging: {} } }); +``` + +Then log from any tool callback: + +```ts source="../examples/server/src/serverGuide.examples.ts#registerTool_logging" +server.registerTool( + 'fetch-data', + { + description: 'Fetch data from an API', + inputSchema: z.object({ url: z.string() }) + }, + async ({ url }, ctx): Promise => { + await ctx.mcpReq.log('info', `Fetching ${url}`); + const res = await fetch(url); + await ctx.mcpReq.log('debug', `Response status: ${res.status}`); + const text = await res.text(); + return { content: [{ type: 'text', text }] }; + } +); +``` + +> [!NOTE] +> For logging in a full server, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) and [`jsonResponseStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/jsonResponseStreamableHttp.ts). + ### Resources Resources expose data to clients, but should not perform heavy computation or side‑effects. They are ideal for configuration, documents, or other reference data. @@ -287,9 +345,18 @@ server.registerPrompt( For client-side completion usage, see the [Client guide](client.md). -## Multi‑node deployment patterns - -The SDK supports multi‑node deployments using Streamable HTTP. The high‑level patterns and diagrams live with the runnable server examples: - -- [`examples/server/README.md`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/README.md#multi-node-deployment-patterns) - +## More server features + +The sections above cover the essentials. The SDK supports several additional capabilities — each is demonstrated in the runnable examples and covered in more detail in the linked references. + +| Feature | Description | Reference | +|---------|-------------|-----------| +| Web Standard transport | Deploy on Cloudflare Workers, Deno, or Bun | [`honoWebStandardStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/honoWebStandardStreamableHttp.ts) | +| Session management | Per-session transport routing, initialization, and cleanup | [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) | +| Resumability | Replay missed SSE events via an event store | [`inMemoryEventStore.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/inMemoryEventStore.ts) | +| CORS | Expose MCP headers (`mcp-session-id`, etc.) for browser clients | [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) | +| Tool annotations | Hint whether tools are read-only, destructive, etc. | [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) | +| Elicitation | Request user input (forms or URLs) during tool execution | [Capabilities guide](capabilities.md#elicitation), [`elicitationFormExample.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/elicitationFormExample.ts) | +| Sampling | Request LLM completions from the connected client | [Capabilities guide](capabilities.md#sampling), [`toolWithSampleServer.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/toolWithSampleServer.ts) | +| Tasks (experimental) | Long-running operations with polling and resumption | [Capabilities guide](capabilities.md#task-based-execution-experimental), [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) | +| Multi‑node deployment | Stateless, persistent‑storage, and distributed routing patterns | [`examples/server/README.md`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/README.md#multi-node-deployment-patterns) | diff --git a/examples/server/src/serverGuide.examples.ts b/examples/server/src/serverGuide.examples.ts index 6ed08a6ec..271d0d39b 100644 --- a/examples/server/src/serverGuide.examples.ts +++ b/examples/server/src/serverGuide.examples.ts @@ -12,7 +12,7 @@ import { randomUUID } from 'node:crypto'; import { createMcpExpressApp } from '@modelcontextprotocol/express'; import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node'; import type { CallToolResult, ResourceLink } from '@modelcontextprotocol/server'; -import { completable, McpServer, ResourceTemplate } from '@modelcontextprotocol/server'; +import { completable, McpServer, ResourceTemplate, StdioServerTransport } from '@modelcontextprotocol/server'; import * as z from 'zod/v4'; // --------------------------------------------------------------------------- @@ -178,6 +178,35 @@ function registerPrompt_completion(server: McpServer) { //#endregion registerPrompt_completion } +// --------------------------------------------------------------------------- +// Logging +// --------------------------------------------------------------------------- + +/** Example: Server with logging capability + tool that logs progress messages. */ +function registerTool_logging() { + //#region logging_capability + const server = new McpServer({ name: 'my-server', version: '1.0.0' }, { capabilities: { logging: {} } }); + //#endregion logging_capability + + //#region registerTool_logging + server.registerTool( + 'fetch-data', + { + description: 'Fetch data from an API', + inputSchema: z.object({ url: z.string() }) + }, + async ({ url }, ctx): Promise => { + await ctx.mcpReq.log('info', `Fetching ${url}`); + const res = await fetch(url); + await ctx.mcpReq.log('debug', `Response status: ${res.status}`); + const text = await res.text(); + return { content: [{ type: 'text', text }] }; + } + ); + //#endregion registerTool_logging + return server; +} + // --------------------------------------------------------------------------- // Transports // --------------------------------------------------------------------------- @@ -208,6 +237,29 @@ async function streamableHttp_stateless() { //#endregion streamableHttp_stateless } +/** Example: Streamable HTTP with JSON response mode (no SSE). */ +async function streamableHttp_jsonResponse() { + //#region streamableHttp_jsonResponse + const server = new McpServer({ name: 'my-server', version: '1.0.0' }); + + const transport = new NodeStreamableHTTPServerTransport({ + sessionIdGenerator: () => randomUUID(), + enableJsonResponse: true + }); + + await server.connect(transport); + //#endregion streamableHttp_jsonResponse +} + +/** Example: stdio transport for local process-spawned integrations. */ +async function stdio_basic() { + //#region stdio_basic + const server = new McpServer({ name: 'my-server', version: '1.0.0' }); + const transport = new StdioServerTransport(); + await server.connect(transport); + //#endregion stdio_basic +} + // --------------------------------------------------------------------------- // DNS rebinding protection // --------------------------------------------------------------------------- @@ -241,11 +293,14 @@ function dnsRebinding_allowedHosts() { // Suppress unused-function warnings (functions exist solely for type-checking) void registerTool_basic; void registerTool_resourceLink; +void registerTool_logging; void registerResource_static; void registerResource_template; void registerPrompt_basic; void registerPrompt_completion; void streamableHttp_stateful; void streamableHttp_stateless; +void streamableHttp_jsonResponse; +void stdio_basic; void dnsRebinding_basic; void dnsRebinding_allowedHosts; From fd01ec3c7144b62565a1364d9e9f3a347c8b96c5 Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Wed, 11 Feb 2026 12:12:20 -0600 Subject: [PATCH 6/6] Dissolve `Running your server` section into `Server overview` The `Running your server` section sat awkwardly between Transports and DNS rebinding protection, containing no code and significant overlap with the overview (duplicate `simpleStreamableHttp.ts` link, duplicate Transports spec link, a 3-step list that recapped what the Transports section already showed in code). Rework the overview into a concise roadmap: - Replace the bullet-list of transport choices and example links with a 3-step numbered list that names `McpServer`, links to both transport sections, and forward-links to tools/resources/prompts - Fold the "start from `simpleStreamableHttp.ts` and strip what you don't need" advice into the overview's closing paragraph - Tease stateless and JSON-response-mode variants with a sentence pointing to Transports, rather than duplicating the example links - Add section-specific spec links to NOTE callouts (Tools, Resources, Prompts) following the established pattern - Fix the Streamable HTTP spec link to use the standard NOTE callout format instead of a bare URL in body text Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/server.md | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/docs/server.md b/docs/server.md index d4d2499e5..941ca8740 100644 --- a/docs/server.md +++ b/docs/server.md @@ -4,16 +4,15 @@ title: Server ## Server overview -This SDK lets you build MCP servers in TypeScript and connect them to different transports. For most use cases you will use {@linkcode @modelcontextprotocol/server!server/mcp.McpServer | McpServer} from `@modelcontextprotocol/server` and choose one of: +This guide covers SDK usage for building MCP servers in TypeScript. For protocol-level details and message formats, see the [MCP specification](https://modelcontextprotocol.io/specification/latest/). -- **Streamable HTTP** (for remote servers) -- **stdio** (for local, process‑spawned integrations) +Building a server takes three steps: -For a complete, runnable example server, see: +1. Create an {@linkcode @modelcontextprotocol/server!server/mcp.McpServer | McpServer} and register your [tools, resources, and prompts](#tools-resources-and-prompts). +2. Create a transport — [Streamable HTTP](#streamable-http) for remote servers or [stdio](#stdio) for local, process‑spawned integrations. +3. Wire the transport into your HTTP framework (or use stdio directly) and call `server.connect(transport)`. -- [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) – feature‑rich Streamable HTTP server -- [`jsonResponseStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/jsonResponseStreamableHttp.ts) – Streamable HTTP with JSON response mode -- [`simpleStatelessStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStatelessStreamableHttp.ts) – stateless Streamable HTTP server +The sections below cover each of these. For a feature‑rich starting point, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) — remove what you don't need and register your own tools, resources, and prompts. For stateless or JSON‑response‑mode alternatives, see the examples linked in [Transports](#transports) below. ## Transports @@ -40,8 +39,8 @@ await server.connect(transport); > [!NOTE] > For full runnable examples, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) (sessions, logging, tasks, elicitation, auth hooks), [`jsonResponseStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/jsonResponseStreamableHttp.ts) (`enableJsonResponse: true`, no SSE), and [`standaloneSseWithGetStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/standaloneSseWithGetStreamableHttp.ts) (notifications with Streamable HTTP GET + SSE). - -See the MCP spec for full transport details: `https://modelcontextprotocol.io/specification/2025-11-25/basic/transports` +> +> For protocol details, see [Transports](https://modelcontextprotocol.io/specification/latest/basic/transports) in the MCP specification. #### Stateless vs stateful sessions @@ -93,19 +92,6 @@ const transport = new StdioServerTransport(); await server.connect(transport); ``` -## Running your server - -For a minimal "getting started" experience: - -1. Register your tools, resources, and prompts (see [below](#tools-resources-and-prompts)). -2. Create a transport and connect it to your server. -3. Wire the transport into your HTTP framework or use stdio. - -For more detailed patterns (stateless vs stateful, JSON response mode, CORS, DNS rebind protection), see the examples and the MCP spec sections on transports. - -> [!NOTE] -> For a feature‑rich starting point, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts). Remove features you do not need (tasks, advanced logging, OAuth, etc.) and register your own tools, resources and prompts. - ## DNS rebinding protection MCP servers running on localhost are vulnerable to DNS rebinding attacks. Use `createMcpExpressApp()` from `@modelcontextprotocol/express` to create an Express app with DNS rebinding protection enabled by default: @@ -162,6 +148,8 @@ server.registerTool( > [!NOTE] > For full runnable examples, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) and [`toolWithSampleServer.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/toolWithSampleServer.ts). +> +> For protocol details, see [Tools](https://modelcontextprotocol.io/specification/latest/server/tools) in the MCP specification. #### `ResourceLink` outputs @@ -226,6 +214,8 @@ server.registerTool( > [!NOTE] > For logging in a full server, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) and [`jsonResponseStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/jsonResponseStreamableHttp.ts). +> +> For protocol details, see [Logging](https://modelcontextprotocol.io/specification/latest/server/utilities/logging) in the MCP specification. ### Resources @@ -279,6 +269,8 @@ server.registerResource( > [!NOTE] > For full runnable examples of resources, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts). +> +> For protocol details, see [Resources](https://modelcontextprotocol.io/specification/latest/server/resources) in the MCP specification. ### Prompts @@ -312,6 +304,8 @@ server.registerPrompt( > [!NOTE] > For prompts integrated into a full server, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts). +> +> For protocol details, see [Prompts](https://modelcontextprotocol.io/specification/latest/server/prompts) in the MCP specification. ### Completions