Update server examples and docs (#1285)

This commit is contained in:
Dale Seo 2025-12-11 06:58:47 -05:00 • committed by GitHub
commit 67d79d45ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 65 additions and 48 deletions

View file

@ -31,8 +31,7 @@ Key examples:
- [`jsonResponseStreamableHttp.ts`](../src/examples/server/jsonResponseStreamableHttp.ts) – `enableJsonResponse: true`, no SSE
- [`standaloneSseWithGetStreamableHttp.ts`](../src/examples/server/standaloneSseWithGetStreamableHttp.ts) – notifications with Streamable HTTP GET + SSE
See the MCP spec for full transport details:
`https://modelcontextprotocol.io/specification/2025-03-26/basic/transports`
See the MCP spec for full transport details: `https://modelcontextprotocol.io/specification/2025-11-25/basic/transports`
### Stateless vs stateful sessions

View file

@ -50,7 +50,7 @@ npx tsx src/examples/client/simpleClientCredentials.ts
### Backwards Compatible Client
A client that implements backwards compatibility according to the [MCP specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#backwards-compatibility), allowing it to work with both new and legacy servers. This client demonstrates:
A client that implements backwards compatibility according to the [MCP specification](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#backwards-compatibility), allowing it to work with both new and legacy servers. This client demonstrates:
- The client first POSTs an initialize request to the server URL:
- If successful, it uses the Streamable HTTP transport
@ -83,7 +83,7 @@ These examples demonstrate how to set up an MCP server on a single node with dif
##### Simple Streamable HTTP Server
A server that implements the Streamable HTTP transport (protocol version 2025-03-26).
A server that implements the Streamable HTTP transport (protocol version 2025-11-25).
- Basic server setup with Express and the Streamable HTTP transport
- Session management with an in-memory event store for resumability
@ -166,7 +166,7 @@ npx tsx src/examples/server/simpleSseServer.ts
#### Streamable Http Backwards Compatible Server with SSE
A server that supports both Streamable HTTP and SSE transports, adhering to the [MCP specification for backwards compatibility](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#backwards-compatibility).
A server that supports both Streamable HTTP and SSE transports, adhering to the [MCP specification for backwards compatibility](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#backwards-compatibility).
- Single MCP server instance with multiple transport options
- Support for Streamable HTTP requests at `/mcp` endpoint (GET/POST/DELETE)
@ -337,7 +337,7 @@ To test the backwards compatibility features:
# Legacy SSE server (protocol version 2024-11-05)
npx tsx src/examples/server/simpleSseServer.ts
# Streamable HTTP server (protocol version 2025-03-26)
# Streamable HTTP server (protocol version 2025-11-25)
npx tsx src/examples/server/simpleStreamableHttp.ts
# Backwards compatible server (supports both protocols)

View file

@ -21,11 +21,13 @@ const getServer = () => {
);
// Register a simple tool that returns a greeting
server.tool(
server.registerTool(
'greet',
'A simple greeting tool',
{
name: z.string().describe('Name to greet')
description: 'A simple greeting tool',
inputSchema: {
name: z.string().describe('Name to greet')
}
},
async ({ name }): Promise<CallToolResult> => {
return {
@ -40,11 +42,13 @@ const getServer = () => {
);
// Register a tool that sends multiple greetings with notifications
server.tool(
server.registerTool(
'multi-greet',
'A tool that sends different greetings with delays between them',
{
name: z.string().describe('Name to greet')
description: 'A tool that sends different greetings with delays between them',
inputSchema: {
name: z.string().describe('Name to greet')
}
},
async ({ name }, extra): Promise<CallToolResult> => {
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

View file

@ -25,12 +25,14 @@ const getServer = () => {
{ capabilities: { logging: {} } }
);
server.tool(
server.registerTool(
'start-notification-stream',
'Starts sending periodic notifications',
{
interval: z.number().describe('Interval in milliseconds between notifications').default(1000),
count: z.number().describe('Number of notifications to send').default(10)
description: 'Starts sending periodic notifications',
inputSchema: {
interval: z.number().describe('Interval in milliseconds between notifications').default(1000),
count: z.number().describe('Number of notifications to send').default(10)
}
},
async ({ interval, count }, extra): Promise<CallToolResult> => {
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

View file

@ -16,11 +16,13 @@ const getServer = () => {
);
// Register a simple prompt
server.prompt(
server.registerPrompt(
'greeting-template',
'A simple greeting prompt template',
{
name: z.string().describe('Name to include in greeting')
description: 'A simple greeting prompt template',
argsSchema: {
name: z.string().describe('Name to include in greeting')
}
},
async ({ name }): Promise<GetPromptResult> => {
return {
@ -38,12 +40,14 @@ const getServer = () => {
);
// Register a tool specifically for testing resumability
server.tool(
server.registerTool(
'start-notification-stream',
'Starts sending periodic notifications for testing resumability',
{
interval: z.number().describe('Interval in milliseconds between notifications').default(100),
count: z.number().describe('Number of notifications to send (0 for 100)').default(10)
description: 'Starts sending periodic notifications for testing resumability',
inputSchema: {
interval: z.number().describe('Interval in milliseconds between notifications').default(100),
count: z.number().describe('Number of notifications to send (0 for 100)').default(10)
}
},
async ({ interval, count }, extra): Promise<CallToolResult> => {
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
@ -78,7 +82,7 @@ const getServer = () => {
);
// Create a simple resource at a fixed URI
server.resource(
server.registerResource(
'greeting-resource',
'https://example.com/greetings/default',
{ mimeType: 'text/plain' },

View file

@ -67,16 +67,18 @@ const getServer = () => {
);
// Register a tool that sends multiple greetings with notifications (with annotations)
server.tool(
server.registerTool(
'multi-greet',
'A tool that sends different greetings with delays between them',
{
name: z.string().describe('Name to greet')
},
{
title: 'Multiple Greeting Tool',
readOnlyHint: true,
openWorldHint: false
description: 'A tool that sends different greetings with delays between them',
inputSchema: {
name: z.string().describe('Name to greet')
},
annotations: {
title: 'Multiple Greeting Tool',
readOnlyHint: true,
openWorldHint: false
}
},
async ({ name }, extra): Promise<CallToolResult> => {
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
@ -121,11 +123,13 @@ const getServer = () => {
);
// Register a tool that demonstrates form elicitation (user input collection with a schema)
// This creates a closure that captures the server instance
server.tool(
server.registerTool(
'collect-user-info',
'A tool that collects user information through form elicitation',
{
infoType: z.enum(['contact', 'preferences', 'feedback']).describe('Type of information to collect')
description: 'A tool that collects user information through form elicitation',
inputSchema: {
infoType: z.enum(['contact', 'preferences', 'feedback']).describe('Type of information to collect')
}
},
async ({ infoType }, extra): Promise<CallToolResult> => {
let message: string;
@ -302,12 +306,14 @@ const getServer = () => {
);
// Register a tool specifically for testing resumability
server.tool(
server.registerTool(
'start-notification-stream',
'Starts sending periodic notifications for testing resumability',
{
interval: z.number().describe('Interval in milliseconds between notifications').default(100),
count: z.number().describe('Number of notifications to send (0 for 100)').default(50)
description: 'Starts sending periodic notifications for testing resumability',
inputSchema: {
interval: z.number().describe('Interval in milliseconds between notifications').default(100),
count: z.number().describe('Number of notifications to send (0 for 100)').default(50)
}
},
async ({ interval, count }, extra): Promise<CallToolResult> => {
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

View file

@ -11,7 +11,7 @@ import { createMcpExpressApp } from '../../server/express.js';
/**
* This example server demonstrates backwards compatibility with both:
* 1. The deprecated HTTP+SSE transport (protocol version 2024-11-05)
* 2. The Streamable HTTP transport (protocol version 2025-03-26)
* 2. The Streamable HTTP transport (protocol version 2025-11-25)
*
* It maintains a single MCP server instance but exposes two transport options:
* - /mcp: The new Streamable HTTP endpoint (supports GET/POST/DELETE)
@ -29,12 +29,14 @@ const getServer = () => {
);
// Register a simple tool that sends notifications over time
server.tool(
server.registerTool(
'start-notification-stream',
'Starts sending periodic notifications for testing resumability',
{
interval: z.number().describe('Interval in milliseconds between notifications').default(100),
count: z.number().describe('Number of notifications to send (0 for 100)').default(50)
description: 'Starts sending periodic notifications for testing resumability',
inputSchema: {
interval: z.number().describe('Interval in milliseconds between notifications').default(100),
count: z.number().describe('Number of notifications to send (0 for 100)').default(50)
}
},
async ({ interval, count }, extra): Promise<CallToolResult> => {
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
@ -77,7 +79,7 @@ const app = createMcpExpressApp();
const transports: Record<string, StreamableHTTPServerTransport | SSEServerTransport> = {};
//=============================================================================
// STREAMABLE HTTP TRANSPORT (PROTOCOL VERSION 2025-03-26)
// STREAMABLE HTTP TRANSPORT (PROTOCOL VERSION 2025-11-25)
//=============================================================================
// Handle all MCP Streamable HTTP requests (GET, POST, DELETE) on a single endpoint
@ -214,10 +216,10 @@ app.listen(PORT, error => {
==============================================
SUPPORTED TRANSPORT OPTIONS:
1. Streamable Http(Protocol version: 2025-03-26)
1. Streamable Http(Protocol version: 2025-11-25)
Endpoint: /mcp
Methods: GET, POST, DELETE
Usage:
Usage:
- Initialize with POST to /mcp
- Establish SSE stream with GET to /mcp
- Send requests with POST to /mcp

View file

@ -16,7 +16,7 @@ const transports: { [sessionId: string]: StreamableHTTPServerTransport } = {};
const addResource = (name: string, content: string) => {
const uri = `https://mcp-example.com/dynamic/${encodeURIComponent(name)}`;
server.resource(
server.registerResource(
name,
uri,
{ mimeType: 'text/plain', description: `Dynamic resource: ${name}` },