@@ -4,108 +4,114 @@ import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js';
4
4
import { z } from 'zod' ;
5
5
import { CallToolResult , GetPromptResult , ReadResourceResult } from '../../types.js' ;
6
6
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
+ } ,
28
30
} ,
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
+ } ;
63
33
}
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 ;
64
47
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
+ } ) ;
70
58
}
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
+ }
92
95
93
96
const app = express ( ) ;
94
97
app . use ( express . json ( ) ) ;
95
98
96
- const transport : StreamableHTTPServerTransport = new StreamableHTTPServerTransport ( {
97
- sessionIdGenerator : undefined ,
98
- } ) ;
99
99
100
- // Setup routes for the server
101
- const setupServer = async ( ) => {
102
- await server . connect ( transport ) ;
103
- } ;
100
+
104
101
105
102
app . post ( '/mcp' , async ( req : Request , res : Response ) => {
106
- console . log ( 'Received MCP request:' , req . body ) ;
103
+ const server = getServer ( ) ;
107
104
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
+ } ) ;
109
115
} catch ( error ) {
110
116
console . error ( 'Error handling MCP request:' , error ) ;
111
117
if ( ! res . headersSent ) {
@@ -145,28 +151,15 @@ app.delete('/mcp', async (req: Request, res: Response) => {
145
151
} ) ) ;
146
152
} ) ;
147
153
154
+
148
155
// Start the server
149
156
const 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 } ` ) ;
157
159
} ) ;
158
160
159
161
// Handle server shutdown
160
162
process . on ( 'SIGINT' , async ( ) => {
161
163
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' ) ;
171
164
process . exit ( 0 ) ;
172
165
} ) ;
0 commit comments