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+
100+ // Setup routes for the server
101+ const setupServer = async ( ) => {
102+ await server . connect ( transport ) ;
103+ } ;
104+
105+ app . post ( '/mcp' , async ( req : Request , res : Response ) => {
106+ console . log ( 'Received MCP request:' , req . body ) ;
107+ try {
108+ await transport . handleRequest ( req , res , req . body ) ;
109+ } catch ( error ) {
110+ console . error ( 'Error handling MCP request:' , error ) ;
111+ if ( ! res . headersSent ) {
112+ res . status ( 500 ) . json ( {
113+ jsonrpc : '2.0' ,
114+ error : {
115+ code : - 32603 ,
116+ message : 'Internal server error' ,
117+ } ,
118+ id : null ,
119+ } ) ;
120+ }
121+ }
122+ } ) ;
123+
124+ app . get ( '/mcp' , async ( req : Request , res : Response ) => {
125+ console . log ( 'Received GET MCP request' ) ;
126+ res . writeHead ( 405 ) . end ( JSON . stringify ( {
127+ jsonrpc : "2.0" ,
128+ error : {
129+ code : - 32000 ,
130+ message : "Method not allowed."
131+ } ,
132+ id : null
133+ } ) ) ;
134+ } ) ;
135+
136+ app . delete ( '/mcp' , async ( req : Request , res : Response ) => {
137+ console . log ( 'Received DELETE MCP request' ) ;
138+ res . writeHead ( 405 ) . end ( JSON . stringify ( {
139+ jsonrpc : "2.0" ,
140+ error : {
141+ code : - 32000 ,
142+ message : "Method not allowed."
143+ } ,
144+ id : null
145+ } ) ) ;
146+ } ) ;
147+
148+ // Start the server
149+ 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+ } ) ;
158+
159+ // Handle server shutdown
160+ process . on ( 'SIGINT' , async ( ) => {
161+ 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+ process . exit ( 0 ) ;
172+ } ) ;
0 commit comments