Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions packages/middleware/node/src/streamableHttp.examples.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* Type-checked examples for `streamableHttp.ts`.
*
* These examples are synced into JSDoc comments via the sync-snippets script.
* Each function's region markers define the code snippet that appears in the docs.
*
* @module
*/

import { randomUUID } from 'node:crypto';
import type { IncomingMessage, ServerResponse } from 'node:http';

import { McpServer } from '@modelcontextprotocol/server';

import { NodeStreamableHTTPServerTransport } from './streamableHttp.js';

/**
* Example: Stateful Streamable HTTP transport (Node.js).
*/
async function NodeStreamableHTTPServerTransport_stateful() {
//#region NodeStreamableHTTPServerTransport_stateful
const server = new McpServer({ name: 'my-server', version: '1.0.0' });

const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID()
});

await server.connect(transport);
//#endregion NodeStreamableHTTPServerTransport_stateful
}

/**
* Example: Stateless Streamable HTTP transport (Node.js).
*/
async function NodeStreamableHTTPServerTransport_stateless() {
//#region NodeStreamableHTTPServerTransport_stateless
const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined
});
//#endregion NodeStreamableHTTPServerTransport_stateless
return transport;
}

// Stubs for Express-style app
declare const app: { post(path: string, handler: (req: IncomingMessage & { body?: unknown }, res: ServerResponse) => void): void };

/**
* Example: Using with a pre-parsed request body (e.g. Express).
*/
function NodeStreamableHTTPServerTransport_express(transport: NodeStreamableHTTPServerTransport) {
//#region NodeStreamableHTTPServerTransport_express
app.post('/mcp', (req, res) => {
transport.handleRequest(req, res, req.body);
});
//#endregion NodeStreamableHTTPServerTransport_express
}
44 changes: 25 additions & 19 deletions packages/middleware/node/src/streamableHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,6 @@ export type StreamableHTTPServerTransportOptions = WebStandardStreamableHTTPServ
* This is a wrapper around {@linkcode WebStandardStreamableHTTPServerTransport} that provides Node.js HTTP compatibility.
* It uses the `@hono/node-server` library to convert between Node.js HTTP and Web Standard APIs.
*
* Usage example:
*
* ```typescript
* // Stateful mode - server sets the session ID
* const statefulTransport = new StreamableHTTPServerTransport({
* sessionIdGenerator: () => randomUUID(),
* });
*
* // Stateless mode - explicitly set session ID to undefined
* const statelessTransport = new StreamableHTTPServerTransport({
* sessionIdGenerator: undefined,
* });
*
* // Using with pre-parsed request body
* app.post('/mcp', (req, res) => {
* transport.handleRequest(req, res, req.body);
* });
* ```
*
* In stateful mode:
* - Session ID is generated and included in response headers
* - Session ID is always included in initialization responses
Expand All @@ -57,6 +38,31 @@ export type StreamableHTTPServerTransportOptions = WebStandardStreamableHTTPServ
* In stateless mode:
* - No Session ID is included in any responses
* - No session validation is performed
*
* @example Stateful setup
* ```ts source="./streamableHttp.examples.ts#NodeStreamableHTTPServerTransport_stateful"
* const server = new McpServer({ name: 'my-server', version: '1.0.0' });
*
* const transport = new NodeStreamableHTTPServerTransport({
* sessionIdGenerator: () => randomUUID()
* });
*
* await server.connect(transport);
* ```
*
* @example Stateless setup
* ```ts source="./streamableHttp.examples.ts#NodeStreamableHTTPServerTransport_stateless"
* const transport = new NodeStreamableHTTPServerTransport({
* sessionIdGenerator: undefined
* });
* ```
*
* @example Using with a pre-parsed request body (e.g. Express)
* ```ts source="./streamableHttp.examples.ts#NodeStreamableHTTPServerTransport_express"
* app.post('/mcp', (req, res) => {
* transport.handleRequest(req, res, req.body);
* });
* ```
*/
export class NodeStreamableHTTPServerTransport implements Transport {
private _webStandardTransport: WebStandardStreamableHTTPServerTransport;
Expand Down
46 changes: 46 additions & 0 deletions packages/server/src/server/completable.examples.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Type-checked examples for `completable.ts`.
*
* These examples are synced into JSDoc comments via the sync-snippets script.
* Each function's region markers define the code snippet that appears in the docs.
*
* @module
*/

import * as z from 'zod/v4';

import { completable } from './completable.js';
import { McpServer } from './mcp.js';

/**
* Example: Using completable() in a prompt registration.
*/
function completable_basicUsage() {
const server = new McpServer({ name: 'my-server', version: '1.0.0' });

//#region completable_basicUsage
server.registerPrompt(
'review-code',
{
title: 'Code Review',
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.`
}
}
]
})
);
//#endregion completable_basicUsage
return server;
}
26 changes: 26 additions & 0 deletions packages/server/src/server/completable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,32 @@ export type CompletableSchema<T extends AnySchema> = T & {
/**
* Wraps a Zod type to provide autocompletion capabilities. Useful for, e.g., prompt arguments in MCP.
*
* @example
* ```ts source="./completable.examples.ts#completable_basicUsage"
* server.registerPrompt(
* 'review-code',
* {
* title: 'Code Review',
* 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.`
* }
* }
* ]
* })
* );
* ```
*
* @see {@linkcode server/mcp.McpServer.registerPrompt | McpServer.registerPrompt} for using completable schemas in prompt argument definitions
*/
export function completable<T extends AnySchema>(schema: T, complete: CompleteCallback<T>): CompletableSchema<T> {
Expand Down
145 changes: 145 additions & 0 deletions packages/server/src/server/mcp.examples.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/**
* Type-checked examples for `mcp.ts`.
*
* These examples are synced into JSDoc comments via the sync-snippets script.
* Each function's region markers define the code snippet that appears in the docs.
*
* @module
*/

import type { CallToolResult } from '@modelcontextprotocol/core';
import * as z from 'zod/v4';

import { McpServer } from './mcp.js';
import { StdioServerTransport } from './stdio.js';

/**
* Example: Creating a new McpServer.
*/
function McpServer_basicUsage() {
//#region McpServer_basicUsage
const server = new McpServer({
name: 'my-server',
version: '1.0.0'
});
//#endregion McpServer_basicUsage
return server;
}

/**
* Example: Registering a tool with inputSchema and outputSchema.
*/
function McpServer_registerTool_basic(server: McpServer) {
//#region McpServer_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 McpServer_registerTool_basic
}

/**
* Example: Registering a static resource at a fixed URI.
*/
function McpServer_registerResource_static(server: McpServer) {
//#region McpServer_registerResource_static
server.registerResource(
'config',
'config://app',
{
title: 'Application Config',
mimeType: 'text/plain'
},
async uri => ({
contents: [{ uri: uri.href, text: 'App configuration here' }]
})
);
//#endregion McpServer_registerResource_static
}

/**
* Example: Registering a prompt with an argument schema.
*/
function McpServer_registerPrompt_basic(server: McpServer) {
//#region McpServer_registerPrompt_basic
server.registerPrompt(
'review-code',
{
title: 'Code Review',
description: 'Review code for best practices',
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 McpServer_registerPrompt_basic
}

/**
* Example: Connecting an McpServer to a stdio transport.
*/
async function McpServer_connect_stdio() {
//#region McpServer_connect_stdio
const server = new McpServer({ name: 'my-server', version: '1.0.0' });
const transport = new StdioServerTransport();
await server.connect(transport);
//#endregion McpServer_connect_stdio
}

/**
* Example: Sending a log message to the client.
*/
async function McpServer_sendLoggingMessage_basic(server: McpServer) {
//#region McpServer_sendLoggingMessage_basic
await server.sendLoggingMessage({
level: 'info',
data: 'Processing complete'
});
//#endregion McpServer_sendLoggingMessage_basic
}

/**
* Example: Logging from inside a tool handler via ctx.mcpReq.log().
*/
function McpServer_registerTool_logging(server: McpServer) {
//#region McpServer_registerTool_logging
server.registerTool(
'fetch-data',
{
description: 'Fetch data from an API',
inputSchema: z.object({ url: z.string() })
},
async ({ url }, ctx): Promise<CallToolResult> => {
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 McpServer_registerTool_logging
}
Loading
Loading