1+ import express , { Request , Response } from 'express' ;
2+ import { McpServer } from '../../server/mcp.js' ;
3+ import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js' ;
4+ import { z } from 'zod' ;
5+ import { CallToolResult , GetPromptResult , ReadResourceResult } from '../../types.js' ;
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.` ,
28+ } ,
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 ) ;
63+ }
64+
65+ return {
66+ content : [
67+ {
68+ type : 'text' ,
69+ text : `Started sending periodic notifications every ${ interval } ms` ,
70+ }
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+ ) ;
92+
93+ const app = express ( ) ;
94+ app . use ( express . json ( ) ) ;
95+
96+ const transport : StreamableHTTPServerTransport = new StreamableHTTPServerTransport ( {
97+ sessionIdGenerator : undefined ,
98+ } ) ;
99+ await server . connect ( transport ) ;
100+
101+ app . post ( '/mcp' , async ( req : Request , res : Response ) => {
102+ console . log ( 'Received MCP request:' , req . body ) ;
103+ try {
104+ await transport . handleRequest ( req , res , req . body ) ;
105+ } catch ( error ) {
106+ console . error ( 'Error handling MCP request:' , error ) ;
107+ if ( ! res . headersSent ) {
108+ res . status ( 500 ) . json ( {
109+ jsonrpc : '2.0' ,
110+ error : {
111+ code : - 32603 ,
112+ message : 'Internal server error' ,
113+ } ,
114+ id : null ,
115+ } ) ;
116+ }
117+ }
118+ } ) ;
119+
120+ app . get ( '/mcp' , async ( req : Request , res : Response ) => {
121+ console . log ( 'Received GET MCP request' ) ;
122+ res . writeHead ( 405 ) . end ( JSON . stringify ( {
123+ jsonrpc : "2.0" ,
124+ error : {
125+ code : - 32000 ,
126+ message : "Method not allowed."
127+ } ,
128+ id : null
129+ } ) ) ;
130+ } ) ;
131+
132+ app . delete ( '/mcp' , async ( req : Request , res : Response ) => {
133+ console . log ( 'Received DELETE MCP request' ) ;
134+ res . writeHead ( 405 ) . end ( JSON . stringify ( {
135+ jsonrpc : "2.0" ,
136+ error : {
137+ code : - 32000 ,
138+ message : "Method not allowed."
139+ } ,
140+ id : null
141+ } ) ) ;
142+ } ) ;
143+
144+ // Start the server
145+ const PORT = 3000 ;
146+ app . listen ( PORT , ( ) => {
147+ console . log ( `MCP Streamable HTTP Server listening on port ${ PORT } ` ) ;
148+ } ) ;
149+
150+ // Handle server shutdown
151+ process . on ( 'SIGINT' , async ( ) => {
152+ console . log ( 'Shutting down server...' ) ;
153+ try {
154+ console . log ( `Closing transport` ) ;
155+ await transport . close ( ) ;
156+ } catch ( error ) {
157+ console . error ( `Error closing transport:` , error ) ;
158+ }
159+
160+ await server . close ( ) ;
161+ console . log ( 'Server shutdown complete' ) ;
162+ process . exit ( 0 ) ;
163+ } ) ;
0 commit comments