fix(examples): create fresh McpServer per client in three examples (#1610)
This commit is contained in:
parent
3391bfb57f
commit
52186d1884
1 changed files with 378 additions and 336 deletions
|
|
@ -23,64 +23,68 @@ import type { Request, Response } from 'express';
|
|||
|
||||
import { InMemoryEventStore } from './inMemoryEventStore.js';
|
||||
|
||||
// Create the MCP server
|
||||
const server = new McpServer(
|
||||
{
|
||||
name: 'sse-polling-example',
|
||||
version: '1.0.0'
|
||||
},
|
||||
{
|
||||
capabilities: { logging: {} }
|
||||
}
|
||||
);
|
||||
|
||||
// Register a long-running tool that demonstrates server-initiated disconnect
|
||||
server.registerTool(
|
||||
'long-task',
|
||||
{
|
||||
description: 'A long-running task that sends progress updates. Server will disconnect mid-task to demonstrate polling.'
|
||||
},
|
||||
async (ctx): Promise<CallToolResult> => {
|
||||
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
console.log(`[${ctx.sessionId}] Starting long-task...`);
|
||||
|
||||
// Send first progress notification
|
||||
await ctx.mcpReq.log('info', 'Progress: 25% - Starting work...');
|
||||
await sleep(1000);
|
||||
|
||||
// Send second progress notification
|
||||
await ctx.mcpReq.log('info', 'Progress: 50% - Halfway there...');
|
||||
await sleep(1000);
|
||||
|
||||
// Server decides to disconnect the client to free resources
|
||||
// Client will reconnect via GET with Last-Event-ID after the transport's retryInterval
|
||||
// Use ctx.http?.closeSSE callback - available when eventStore is configured
|
||||
if (ctx.http?.closeSSE) {
|
||||
console.log(`[${ctx.sessionId}] Closing SSE stream to trigger client polling...`);
|
||||
ctx.http?.closeSSE();
|
||||
// Create a fresh MCP server per client connection to avoid shared state between clients
|
||||
const getServer = () => {
|
||||
const server = new McpServer(
|
||||
{
|
||||
name: 'sse-polling-example',
|
||||
version: '1.0.0'
|
||||
},
|
||||
{
|
||||
capabilities: { logging: {} }
|
||||
}
|
||||
);
|
||||
|
||||
// Continue processing while client is disconnected
|
||||
// Events are stored in eventStore and will be replayed on reconnect
|
||||
await sleep(500);
|
||||
await ctx.mcpReq.log('info', 'Progress: 75% - Almost done (sent while client disconnected)...');
|
||||
// Register a long-running tool that demonstrates server-initiated disconnect
|
||||
server.registerTool(
|
||||
'long-task',
|
||||
{
|
||||
description: 'A long-running task that sends progress updates. Server will disconnect mid-task to demonstrate polling.'
|
||||
},
|
||||
async (ctx): Promise<CallToolResult> => {
|
||||
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
await sleep(500);
|
||||
await ctx.mcpReq.log('info', 'Progress: 100% - Complete!');
|
||||
console.log(`[${ctx.sessionId}] Starting long-task...`);
|
||||
|
||||
console.log(`[${ctx.sessionId}] Task complete`);
|
||||
// Send first progress notification
|
||||
await ctx.mcpReq.log('info', 'Progress: 25% - Starting work...');
|
||||
await sleep(1000);
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Long task completed successfully!'
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
);
|
||||
// Send second progress notification
|
||||
await ctx.mcpReq.log('info', 'Progress: 50% - Halfway there...');
|
||||
await sleep(1000);
|
||||
|
||||
// Server decides to disconnect the client to free resources
|
||||
// Client will reconnect via GET with Last-Event-ID after the transport's retryInterval
|
||||
// Use ctx.http?.closeSSE callback - available when eventStore is configured
|
||||
if (ctx.http?.closeSSE) {
|
||||
console.log(`[${ctx.sessionId}] Closing SSE stream to trigger client polling...`);
|
||||
ctx.http?.closeSSE();
|
||||
}
|
||||
|
||||
// Continue processing while client is disconnected
|
||||
// Events are stored in eventStore and will be replayed on reconnect
|
||||
await sleep(500);
|
||||
await ctx.mcpReq.log('info', 'Progress: 75% - Almost done (sent while client disconnected)...');
|
||||
|
||||
await sleep(500);
|
||||
await ctx.mcpReq.log('info', 'Progress: 100% - Complete!');
|
||||
|
||||
console.log(`[${ctx.sessionId}] Task complete`);
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Long task completed successfully!'
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
return server;
|
||||
};
|
||||
|
||||
// Set up Express app
|
||||
const app = createMcpExpressApp();
|
||||
|
|
@ -110,7 +114,8 @@ app.all('/mcp', async (req: Request, res: Response) => {
|
|||
}
|
||||
});
|
||||
|
||||
// Connect the MCP server to the transport
|
||||
// Connect a fresh MCP server to the transport
|
||||
const server = getServer();
|
||||
await server.connect(transport);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue