@@ -4,108 +4,114 @@ import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js';
44import { z } from 'zod' ;
55import { CallToolResult , GetPromptResult , ReadResourceResult } from '../../types.js' ;
66
7- // Create an MCP server with implementation details
8- const server = new McpServer ( {
9- name : 'stateless-streamable-http-server' ,
10- version : '1.0.0' ,
11- } , { capabilities : { logging : { } } } ) ;
12-
13- // Register a simple prompt
14- server . prompt (
15- 'greeting-template' ,
16- 'A simple greeting prompt template' ,
17- {
18- name : z . string ( ) . describe ( 'Name to include in greeting' ) ,
19- } ,
20- async ( { name } ) : Promise < GetPromptResult > => {
21- return {
22- messages : [
23- {
24- role : 'user' ,
25- content : {
26- type : 'text' ,
27- text : `Please greet ${ name } in a friendly manner.` ,
7+ const getServer = ( ) => {
8+ // Create an MCP server with implementation details
9+ const server = new McpServer ( {
10+ name : 'stateless-streamable-http-server' ,
11+ version : '1.0.0' ,
12+ } , { capabilities : { logging : { } } } ) ;
13+
14+ // Register a simple prompt
15+ server . prompt (
16+ 'greeting-template' ,
17+ 'A simple greeting prompt template' ,
18+ {
19+ name : z . string ( ) . describe ( 'Name to include in greeting' ) ,
20+ } ,
21+ async ( { name } ) : Promise < GetPromptResult > => {
22+ return {
23+ messages : [
24+ {
25+ role : 'user' ,
26+ content : {
27+ type : 'text' ,
28+ text : `Please greet ${ name } in a friendly manner.` ,
29+ } ,
2830 } ,
29- } ,
30- ] ,
31- } ;
32- }
33- ) ;
34-
35- // Register a tool specifically for testing resumability
36- server . tool (
37- 'start-notification-stream' ,
38- 'Starts sending periodic notifications for testing resumability' ,
39- {
40- interval : z . number ( ) . describe ( 'Interval in milliseconds between notifications' ) . default ( 100 ) ,
41- count : z . number ( ) . describe ( 'Number of notifications to send (0 for 100)' ) . default ( 10 ) ,
42- } ,
43- async ( { interval, count } , { sendNotification } ) : Promise < CallToolResult > => {
44- const sleep = ( ms : number ) => new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
45- let counter = 0 ;
46-
47- while ( count === 0 || counter < count ) {
48- counter ++ ;
49- try {
50- await sendNotification ( {
51- method : "notifications/message" ,
52- params : {
53- level : "info" ,
54- data : `Periodic notification #${ counter } at ${ new Date ( ) . toISOString ( ) } `
55- }
56- } ) ;
57- }
58- catch ( error ) {
59- console . error ( "Error sending notification:" , error ) ;
60- }
61- // Wait for the specified interval
62- await sleep ( interval ) ;
31+ ] ,
32+ } ;
6333 }
34+ ) ;
35+
36+ // Register a tool specifically for testing resumability
37+ server . tool (
38+ 'start-notification-stream' ,
39+ 'Starts sending periodic notifications for testing resumability' ,
40+ {
41+ interval : z . number ( ) . describe ( 'Interval in milliseconds between notifications' ) . default ( 100 ) ,
42+ count : z . number ( ) . describe ( 'Number of notifications to send (0 for 100)' ) . default ( 10 ) ,
43+ } ,
44+ async ( { interval, count } , { sendNotification } ) : Promise < CallToolResult > => {
45+ const sleep = ( ms : number ) => new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
46+ let counter = 0 ;
6447
65- return {
66- content : [
67- {
68- type : 'text' ,
69- text : `Started sending periodic notifications every ${ interval } ms` ,
48+ while ( count === 0 || counter < count ) {
49+ counter ++ ;
50+ try {
51+ await sendNotification ( {
52+ method : "notifications/message" ,
53+ params : {
54+ level : "info" ,
55+ data : `Periodic notification #${ counter } at ${ new Date ( ) . toISOString ( ) } `
56+ }
57+ } ) ;
7058 }
71- ] ,
72- } ;
73- }
74- ) ;
75-
76- // Create a simple resource at a fixed URI
77- server . resource (
78- 'greeting-resource' ,
79- 'https://example.com/greetings/default' ,
80- { mimeType : 'text/plain' } ,
81- async ( ) : Promise < ReadResourceResult > => {
82- return {
83- contents : [
84- {
85- uri : 'https://example.com/greetings/default' ,
86- text : 'Hello, world!' ,
87- } ,
88- ] ,
89- } ;
90- }
91- ) ;
59+ catch ( error ) {
60+ console . error ( "Error sending notification:" , error ) ;
61+ }
62+ // Wait for the specified interval
63+ await sleep ( interval ) ;
64+ }
65+
66+ return {
67+ content : [
68+ {
69+ type : 'text' ,
70+ text : `Started sending periodic notifications every ${ interval } ms` ,
71+ }
72+ ] ,
73+ } ;
74+ }
75+ ) ;
76+
77+ // Create a simple resource at a fixed URI
78+ server . resource (
79+ 'greeting-resource' ,
80+ 'https://example.com/greetings/default' ,
81+ { mimeType : 'text/plain' } ,
82+ async ( ) : Promise < ReadResourceResult > => {
83+ return {
84+ contents : [
85+ {
86+ uri : 'https://example.com/greetings/default' ,
87+ text : 'Hello, world!' ,
88+ } ,
89+ ] ,
90+ } ;
91+ }
92+ ) ;
93+ return server ;
94+ }
9295
9396const app = express ( ) ;
9497app . use ( express . json ( ) ) ;
9598
96- const transport : StreamableHTTPServerTransport = new StreamableHTTPServerTransport ( {
97- sessionIdGenerator : undefined ,
98- } ) ;
9999
100- // Setup routes for the server
101- const setupServer = async ( ) => {
102- await server . connect ( transport ) ;
103- } ;
100+
104101
105102app . post ( '/mcp' , async ( req : Request , res : Response ) => {
106- console . log ( 'Received MCP request:' , req . body ) ;
103+ const server = getServer ( ) ;
107104 try {
108- await transport . handleRequest ( req , res , req . body ) ;
105+ const transport : StreamableHTTPServerTransport = new StreamableHTTPServerTransport ( {
106+ sessionIdGenerator : undefined ,
107+ } ) ;
108+ await server . connect ( transport ) ;
109+ await transport . handleRequest ( req , res , req . body ) ;
110+ res . on ( 'close' , ( ) => {
111+ console . log ( 'Request closed' ) ;
112+ transport . close ( ) ;
113+ server . close ( ) ;
114+ } ) ;
109115 } catch ( error ) {
110116 console . error ( 'Error handling MCP request:' , error ) ;
111117 if ( ! res . headersSent ) {
@@ -145,28 +151,15 @@ app.delete('/mcp', async (req: Request, res: Response) => {
145151 } ) ) ;
146152} ) ;
147153
154+
148155// Start the server
149156const PORT = 3000 ;
150- setupServer ( ) . then ( ( ) => {
151- app . listen ( PORT , ( ) => {
152- console . log ( `MCP Streamable HTTP Server listening on port ${ PORT } ` ) ;
153- } ) ;
154- } ) . catch ( error => {
155- console . error ( 'Failed to set up the server:' , error ) ;
156- process . exit ( 1 ) ;
157+ app . listen ( PORT , ( ) => {
158+ console . log ( `MCP Stateless Streamable HTTP Server listening on port ${ PORT } ` ) ;
157159} ) ;
158160
159161// Handle server shutdown
160162process . on ( 'SIGINT' , async ( ) => {
161163 console . log ( 'Shutting down server...' ) ;
162- try {
163- console . log ( `Closing transport` ) ;
164- await transport . close ( ) ;
165- } catch ( error ) {
166- console . error ( `Error closing transport:` , error ) ;
167- }
168-
169- await server . close ( ) ;
170- console . log ( 'Server shutdown complete' ) ;
171164 process . exit ( 0 ) ;
172165} ) ;
0 commit comments