Skip to content

Commit 27989ca

Browse files
committed
save commit
1 parent f512df4 commit 27989ca

14 files changed

Lines changed: 348 additions & 676 deletions

File tree

examples/client/src/simpleStreamableHttpBuilder.ts

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ import {
3838
ListPromptsResultSchema,
3939
ListResourcesResultSchema,
4040
ListToolsResultSchema,
41-
LoggingMessageNotificationSchema
42-
,
41+
LoggingMessageNotificationSchema,
4342
ReadResourceResultSchema,
4443
StreamableHTTPClientTransport
4544
} from '@modelcontextprotocol/client';
@@ -120,7 +119,6 @@ export function createClientLoggingMiddleware(options: ClientLoggingMiddlewareOp
120119
};
121120
}
122121

123-
124122
/**
125123
* Options for retry middleware.
126124
*/
@@ -169,7 +167,6 @@ export function createRetryMiddleware(options: RetryMiddlewareOptions = {}): Out
169167
};
170168
}
171169

172-
173170
/**
174171
* Custom tool call instrumentation middleware.
175172
* Logs tool calls with timing information.
@@ -260,7 +257,7 @@ function printHelp(): void {
260257
}
261258

262259
function commandLoop(): void {
263-
readline.question('\n> ', async (input) => {
260+
readline.question('\n> ', async input => {
264261
const args = input.trim().split(/\s+/);
265262
const command = args[0]?.toLowerCase();
266263

@@ -488,14 +485,10 @@ async function connect(url?: string): Promise<void> {
488485
createRetryMiddleware({
489486
maxRetries: 3,
490487
baseDelay: 100,
491-
isRetryable: (error) => {
488+
isRetryable: error => {
492489
// Retry on network errors
493490
const message = error instanceof Error ? error.message : String(error);
494-
return (
495-
message.includes('ECONNREFUSED') ||
496-
message.includes('ETIMEDOUT') ||
497-
message.includes('network')
498-
);
491+
return message.includes('ECONNREFUSED') || message.includes('ETIMEDOUT') || message.includes('network');
499492
}
500493
})
501494
)
@@ -506,7 +499,7 @@ async function connect(url?: string): Promise<void> {
506499
// ─── Request Handlers ───
507500

508501
// Sampling request handler (when server requests LLM completion)
509-
.onSamplingRequest(async (params) => {
502+
.onSamplingRequest(async params => {
510503
console.log('\n[SAMPLING] Received sampling request from server');
511504
console.log('[SAMPLING] Messages:', JSON.stringify(params, null, 2));
512505

@@ -523,7 +516,7 @@ async function connect(url?: string): Promise<void> {
523516
})
524517

525518
// Elicitation handler (when server requests user input)
526-
.onElicitation(async (params) => {
519+
.onElicitation(async params => {
527520
const elicitParams = params as { mode?: string; message?: string; requestedSchema?: unknown };
528521
console.log('\n[ELICITATION] Received elicitation request from server');
529522
console.log('[ELICITATION] Mode:', elicitParams.mode);
@@ -574,7 +567,7 @@ async function connect(url?: string): Promise<void> {
574567
.build();
575568

576569
// Set up client error handler
577-
client.onerror = (error) => {
570+
client.onerror = error => {
578571
console.error('\n[CLIENT] Error event:', error);
579572
};
580573

@@ -584,7 +577,7 @@ async function connect(url?: string): Promise<void> {
584577
});
585578

586579
// Set up notification handler for logging messages
587-
client.setNotificationHandler(LoggingMessageNotificationSchema, (notification) => {
580+
client.setNotificationHandler(LoggingMessageNotificationSchema, notification => {
588581
notificationCount++;
589582
console.log(`\n[NOTIFICATION #${notificationCount}] ${notification.params.level}: ${notification.params.data}`);
590583
process.stdout.write('> ');

examples/server/src/simpleStreamableHttpBuilder.ts

Lines changed: 39 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
* This example demonstrates using the McpServer.builder() fluent API
55
* to create and configure an MCP server with:
66
* - Tools, resources, and prompts registration
7-
* - Middleware (logging, rate limiting, custom metrics)
7+
* - Middleware (logging, custom metrics)
88
* - Per-tool middleware (authorization)
99
* - Error handlers (onError, onProtocolError)
10-
* - Session management with SessionStore
1110
* - Context helpers (logging, notifications)
1211
*
1312
* Run with: npx tsx src/simpleStreamableHttpBuilder.ts
@@ -17,14 +16,8 @@ import { randomUUID } from 'node:crypto';
1716

1817
import { createMcpExpressApp } from '@modelcontextprotocol/express';
1918
import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
20-
import type { CallToolResult, GetPromptResult, ReadResourceResult ,ToolMiddleware} from '@modelcontextprotocol/server';
21-
import {
22-
createLoggingMiddleware,
23-
createSessionStore,
24-
isInitializeRequest,
25-
McpServer,
26-
text
27-
} from '@modelcontextprotocol/server';
19+
import type { CallToolResult, GetPromptResult, ReadResourceResult, ToolMiddleware } from '@modelcontextprotocol/server';
20+
import { createLoggingMiddleware, isInitializeRequest, McpServer, text } from '@modelcontextprotocol/server';
2821
import type { Request, Response } from 'express';
2922
import * as z from 'zod/v4';
3023

@@ -68,7 +61,7 @@ const adminAuthMiddleware: ToolMiddleware = async (ctx, next) => {
6861
};
6962

7063
// ═══════════════════════════════════════════════════════════════════════════
71-
// Session Store Setup
64+
// Session Management
7265
// ═══════════════════════════════════════════════════════════════════════════
7366

7467
/**
@@ -80,25 +73,9 @@ interface SessionData {
8073
}
8174

8275
/**
83-
* Create session store with lifecycle events and timeout.
84-
* This replaces the manual session map management.
76+
* Simple Map-based session storage.
8577
*/
86-
const sessionStore = createSessionStore<SessionData>({
87-
sessionTimeout: 30 * 60 * 1000, // 30 minutes
88-
maxSessions: 100,
89-
cleanupInterval: 60_000, // Check for expired sessions every minute
90-
events: {
91-
onSessionCreated: (id) => {
92-
console.log(`[SESSION] Created: ${id}`);
93-
},
94-
onSessionDestroyed: (id) => {
95-
console.log(`[SESSION] Destroyed: ${id}`);
96-
},
97-
onSessionUpdated: (id) => {
98-
console.log(`[SESSION] Updated: ${id}`);
99-
}
100-
}
101-
});
78+
const sessions = new Map<string, SessionData>();
10279

10380
// ═══════════════════════════════════════════════════════════════════════════
10481
// Server Factory
@@ -140,12 +117,10 @@ const getServer = () => {
140117
)
141118

142119
// ─── Tool-Specific Middleware ───
143-
.useToolMiddleware(
144-
async (ctx, next) => {
145-
console.log(`Tool '${ctx.name}' called`);
146-
return next();
147-
}
148-
)
120+
.useToolMiddleware(async (ctx, next) => {
121+
console.log(`Tool '${ctx.name}' called`);
122+
return next();
123+
})
149124

150125
// Custom metrics middleware
151126
.useToolMiddleware(metricsMiddleware)
@@ -199,7 +174,7 @@ const getServer = () => {
199174
}
200175
},
201176
async function ({ name }, ctx): Promise<CallToolResult> {
202-
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
177+
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
203178

204179
// Use context logging helper
205180
await ctx.loggingNotification.debug(`Starting multi-greet for ${name}`);
@@ -304,7 +279,10 @@ const getServer = () => {
304279
}
305280
},
306281
async ({ errorType }): Promise<CallToolResult> => {
307-
const error = errorType === 'application' ? new Error('This is a test application error') : new Error('Validation failed: invalid input format');
282+
const error =
283+
errorType === 'application'
284+
? new Error('This is a test application error')
285+
: new Error('Validation failed: invalid input format');
308286
throw error;
309287
}
310288
)
@@ -330,23 +308,23 @@ const getServer = () => {
330308
}
331309
)
332310

333-
// Resource demonstrating session info
311+
// Resource demonstrating server info
334312
.resource(
335-
'session-info',
336-
'https://example.com/session/info',
313+
'server-info',
314+
'https://example.com/server/info',
337315
{
338-
title: 'Session Information',
339-
description: 'Returns current session statistics'
316+
title: 'Server Information',
317+
description: 'Returns current server statistics'
340318
},
341319
async (): Promise<ReadResourceResult> => {
342320
const stats = {
343-
activeSessions: sessionStore.size(),
344-
sessionIds: sessionStore.keys()
321+
activeSessions: sessions.size,
322+
uptime: process.uptime()
345323
};
346324
return {
347325
contents: [
348326
{
349-
uri: 'https://example.com/session/info',
327+
uri: 'https://example.com/server/info',
350328
mimeType: 'application/json',
351329
text: JSON.stringify(stats, null, 2)
352330
}
@@ -396,14 +374,14 @@ const app = createMcpExpressApp();
396374

397375
/**
398376
* MCP POST endpoint handler.
399-
* Uses SessionStore for session management.
377+
* Uses a simple Map for session management.
400378
*/
401379
const mcpPostHandler = async (req: Request, res: Response) => {
402380
const sessionId = req.headers['mcp-session-id'] as string | undefined;
403381

404382
try {
405383
// Check for existing session
406-
const session = sessionId ? sessionStore.get(sessionId) : undefined;
384+
const session = sessionId ? sessions.get(sessionId) : undefined;
407385

408386
if (session) {
409387
// Reuse existing transport
@@ -420,9 +398,9 @@ const mcpPostHandler = async (req: Request, res: Response) => {
420398
const transport = new NodeStreamableHTTPServerTransport({
421399
sessionIdGenerator: () => randomUUID(),
422400
eventStore,
423-
onsessioninitialized: (sid) => {
424-
// Store session with SessionStore
425-
sessionStore.set(sid, {
401+
onsessioninitialized: sid => {
402+
// Store session
403+
sessions.set(sid, {
426404
transport,
427405
createdAt: new Date()
428406
});
@@ -433,7 +411,7 @@ const mcpPostHandler = async (req: Request, res: Response) => {
433411
transport.onclose = () => {
434412
const sid = transport.sessionId;
435413
if (sid) {
436-
sessionStore.delete(sid);
414+
sessions.delete(sid);
437415
}
438416
};
439417

@@ -476,7 +454,7 @@ app.post('/mcp', mcpPostHandler);
476454
*/
477455
const mcpGetHandler = async (req: Request, res: Response) => {
478456
const sessionId = req.headers['mcp-session-id'] as string | undefined;
479-
const session = sessionId ? sessionStore.get(sessionId) : undefined;
457+
const session = sessionId ? sessions.get(sessionId) : undefined;
480458

481459
if (!session) {
482460
res.status(400).send('Invalid or missing session ID');
@@ -500,7 +478,7 @@ app.get('/mcp', mcpGetHandler);
500478
*/
501479
const mcpDeleteHandler = async (req: Request, res: Response) => {
502480
const sessionId = req.headers['mcp-session-id'] as string | undefined;
503-
const session = sessionId ? sessionStore.get(sessionId) : undefined;
481+
const session = sessionId ? sessions.get(sessionId) : undefined;
504482

505483
if (!session) {
506484
res.status(400).send('Invalid or missing session ID');
@@ -525,7 +503,7 @@ app.delete('/mcp', mcpDeleteHandler);
525503
// Server Startup
526504
// ═══════════════════════════════════════════════════════════════════════════
527505

528-
app.listen(PORT, (error) => {
506+
app.listen(PORT, error => {
529507
if (error) {
530508
console.error('Failed to start server:', error);
531509
// eslint-disable-next-line unicorn/no-process-exit
@@ -540,10 +518,9 @@ app.listen(PORT, (error) => {
540518
console.log('Features demonstrated:');
541519
console.log(' - Builder pattern for server configuration');
542520
console.log(' - Universal middleware (logging)');
543-
console.log(' - Tool-specific middleware (rate limiting, metrics)');
521+
console.log(' - Tool-specific middleware (metrics)');
544522
console.log(' - Per-tool middleware (authorization)');
545523
console.log(' - Error handlers (onError, onProtocolError)');
546-
console.log(' - Session management with SessionStore');
547524
console.log(' - Context helpers (logging, notifications)');
548525
console.log('═══════════════════════════════════════════════════════════════');
549526
});
@@ -555,23 +532,18 @@ app.listen(PORT, (error) => {
555532
process.on('SIGINT', async () => {
556533
console.log('\n[SHUTDOWN] Received SIGINT, shutting down...');
557534

558-
// Close all sessions using SessionStore
559-
const sessionIds = sessionStore.keys();
560-
for (const sid of sessionIds) {
535+
// Close all sessions
536+
for (const [sid, session] of sessions) {
561537
try {
562-
const session = sessionStore.get(sid);
563-
if (session) {
564-
console.log(`[SHUTDOWN] Closing session ${sid}`);
565-
await session.transport.close();
566-
}
538+
console.log(`[SHUTDOWN] Closing session ${sid}`);
539+
await session.transport.close();
567540
} catch (error) {
568541
console.error(`[SHUTDOWN] Error closing session ${sid}:`, error);
569542
}
570543
}
571544

572-
// Clear the session store (also stops cleanup timer)
573-
sessionStore.clear();
574-
(sessionStore as { dispose?: () => void }).dispose?.();
545+
// Clear the sessions map
546+
sessions.clear();
575547

576548
console.log('[SHUTDOWN] Complete');
577549
process.exit(0);

packages/client/src/client/builder.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,7 @@ export type ElicitationRequestHandler = (
7171
* Handler for roots list requests from the server.
7272
* Receives the full ListRootsRequest and returns the list of roots.
7373
*/
74-
export type RootsListHandler = (
75-
request: ListRootsRequest,
76-
ctx: ClientContextInterface
77-
) => ListRootsResult | Promise<ListRootsResult>;
74+
export type RootsListHandler = (request: ListRootsRequest, ctx: ClientContextInterface) => ListRootsResult | Promise<ListRootsResult>;
7875

7976
/**
8077
* Error handler type for application errors

packages/client/src/client/middleware.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -727,4 +727,4 @@ export class ClientMiddlewareManager {
727727

728728
return dispatch(0);
729729
}
730-
}
730+
}

packages/server/src/experimental/tasks/mcpServer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
import type { AnySchema, TaskToolExecution, ToolAnnotations, ToolExecution, ZodRawShapeCompat } from '@modelcontextprotocol/core';
99

10-
import type { AnyToolHandler, McpServer, RegisteredTool } from '../../server/mcp.js';
10+
import type { AnyToolHandler, McpServer } from '../../server/mcp.js';
11+
import type { RegisteredTool } from '../../server/registries/toolRegistry.js';
1112
import type { ToolTaskHandler } from './interfaces.js';
1213

1314
/**

packages/server/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export * from './server/middleware.js';
66
export * from './server/middleware/hostHeaderValidation.js';
77
export * from './server/registries/index.js';
88
export * from './server/server.js';
9-
export * from './server/sessions.js';
109
export * from './server/stdio.js';
1110
export * from './server/streamableHttp.js';
1211

packages/server/src/server/builder.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
import type { ToolAnnotations, ToolExecution, ZodRawShapeCompat } from '@modelcontextprotocol/core';
2020
import { objectFromShape } from '@modelcontextprotocol/core';
2121

22-
import type { McpServer, PromptCallback, ReadResourceCallback, ResourceMetadata, ToolCallback } from './mcp.js';
22+
import type { PromptCallback, ReadResourceCallback } from '../types/types.js';
23+
import type { McpServer, ResourceMetadata, ToolCallback } from './mcp.js';
2324
import type { PromptMiddleware, ResourceMiddleware, ToolMiddleware, UniversalMiddleware } from './middleware.js';
2425
import { PromptRegistry } from './registries/promptRegistry.js';
2526
import { ResourceRegistry } from './registries/resourceRegistry.js';

0 commit comments

Comments
 (0)