@@ -91,7 +91,7 @@ const serverTransports: Map<string, Transport> = new Map<string, Transport>(); /
91
91
92
92
const createTransport = async ( req : express . Request ) : Promise < Transport > => {
93
93
const query = req . query ;
94
- console . log ( "Query parameters:" , query ) ;
94
+ console . log ( "Query parameters:" , JSON . stringify ( query ) ) ;
95
95
96
96
const transportType = query . transportType as string ;
97
97
@@ -103,7 +103,7 @@ const createTransport = async (req: express.Request): Promise<Transport> => {
103
103
104
104
const { cmd, args } = findActualExecutable ( command , origArgs ) ;
105
105
106
- console . log ( `Stdio transport: command=${ cmd } , args=${ args } ` ) ;
106
+ console . log ( `STDIO transport: command=${ cmd } , args=${ args } ` ) ;
107
107
108
108
const transport = new StdioClientTransport ( {
109
109
command : cmd ,
@@ -113,8 +113,6 @@ const createTransport = async (req: express.Request): Promise<Transport> => {
113
113
} ) ;
114
114
115
115
await transport . start ( ) ;
116
-
117
- console . log ( "Spawned stdio transport" ) ;
118
116
return transport ;
119
117
} else if ( transportType === "sse" ) {
120
118
const url = query . url as string ;
@@ -132,8 +130,6 @@ const createTransport = async (req: express.Request): Promise<Transport> => {
132
130
} ,
133
131
} ) ;
134
132
await transport . start ( ) ;
135
-
136
- console . log ( "Connected to SSE transport" ) ;
137
133
return transport ;
138
134
} else if ( transportType === "streamable-http" ) {
139
135
const headers = getHttpHeaders ( req , transportType ) ;
@@ -147,7 +143,6 @@ const createTransport = async (req: express.Request): Promise<Transport> => {
147
143
} ,
148
144
) ;
149
145
await transport . start ( ) ;
150
- console . log ( "Connected to Streamable HTTP transport" ) ;
151
146
return transport ;
152
147
} else {
153
148
console . error ( `Invalid transport type: ${ transportType } ` ) ;
@@ -176,11 +171,10 @@ app.get("/mcp", async (req, res) => {
176
171
177
172
app . post ( "/mcp" , async ( req , res ) => {
178
173
const sessionId = req . headers [ "mcp-session-id" ] as string | undefined ;
179
- console . log ( `Received POST message for sessionId ${ sessionId } ` ) ;
180
174
let serverTransport : Transport | undefined ;
181
175
if ( ! sessionId ) {
182
176
try {
183
- console . log ( "New streamable-http connection" ) ;
177
+ console . log ( "New StreamableHttp connection request " ) ;
184
178
try {
185
179
serverTransport = await createTransport ( req ) ;
186
180
} catch ( error ) {
@@ -196,16 +190,17 @@ app.post("/mcp", async (req, res) => {
196
190
throw error ;
197
191
}
198
192
199
- console . log ( "Connected MCP client to server transport" ) ;
193
+ console . log ( "Created StreamableHttp server transport" ) ;
200
194
201
195
const webAppTransport = new StreamableHTTPServerTransport ( {
202
196
sessionIdGenerator : randomUUID ,
203
197
onsessioninitialized : ( sessionId ) => {
204
198
webAppTransports . set ( sessionId , webAppTransport ) ;
205
199
serverTransports . set ( sessionId , serverTransport ! ) ;
206
- console . log ( "Created streamable web app transport " + sessionId ) ;
200
+ console . log ( "Client <-> Proxy sessionId: " + sessionId ) ;
207
201
} ,
208
202
} ) ;
203
+ console . log ( "Created StreamableHttp client transport" ) ;
209
204
210
205
await webAppTransport . start ( ) ;
211
206
@@ -224,6 +219,7 @@ app.post("/mcp", async (req, res) => {
224
219
res . status ( 500 ) . json ( error ) ;
225
220
}
226
221
} else {
222
+ console . log ( `Received POST message for sessionId ${ sessionId } ` ) ;
227
223
try {
228
224
const transport = webAppTransports . get (
229
225
sessionId ,
@@ -272,15 +268,15 @@ app.delete("/mcp", async (req, res) => {
272
268
273
269
app . get ( "/stdio" , async ( req , res ) => {
274
270
try {
275
- console . log ( "New connection" ) ;
271
+ console . log ( "New STDIO connection request " ) ;
276
272
let serverTransport : Transport | undefined ;
277
273
try {
278
274
serverTransport = await createTransport ( req ) ;
275
+ console . log ( "Created server transport" ) ;
279
276
} catch ( error ) {
280
277
if ( error instanceof SseError && error . code === 401 ) {
281
278
console . error (
282
- "Received 401 Unauthorized from MCP server:" ,
283
- error . message ,
279
+ "Received 401 Unauthorized from MCP server. Authentication failure." ,
284
280
) ;
285
281
res . status ( 401 ) . json ( error ) ;
286
282
return ;
@@ -289,31 +285,43 @@ app.get("/stdio", async (req, res) => {
289
285
throw error ;
290
286
}
291
287
292
- console . log ( "Connected MCP client to backing server transport" ) ;
293
-
294
288
const webAppTransport = new SSEServerTransport ( "/message" , res ) ;
289
+ console . log ( "Created client transport" ) ;
290
+
295
291
webAppTransports . set ( webAppTransport . sessionId , webAppTransport ) ;
296
292
serverTransports . set ( webAppTransport . sessionId , serverTransport ) ;
297
- console . log ( "Created client/server transports" ) ;
298
293
299
294
await webAppTransport . start ( ) ;
300
295
301
296
( serverTransport as StdioClientTransport ) . stderr ! . on ( "data" , ( chunk ) => {
302
- webAppTransport . send ( {
303
- jsonrpc : "2.0" ,
304
- method : "notifications/stderr" ,
305
- params : {
306
- content : chunk . toString ( ) ,
307
- } ,
308
- } ) ;
297
+ if ( chunk . toString ( ) . includes ( "MODULE_NOT_FOUND" ) ) {
298
+ webAppTransport . send ( {
299
+ jsonrpc : "2.0" ,
300
+ method : "notifications/stderr" ,
301
+ params : {
302
+ content : "Command not found, transports removed" ,
303
+ } ,
304
+ } ) ;
305
+ webAppTransport . close ( ) ;
306
+ serverTransport . close ( ) ;
307
+ webAppTransports . delete ( webAppTransport . sessionId ) ;
308
+ serverTransports . delete ( webAppTransport . sessionId ) ;
309
+ console . error ( "Command not found, transports removed" ) ;
310
+ } else {
311
+ webAppTransport . send ( {
312
+ jsonrpc : "2.0" ,
313
+ method : "notifications/stderr" ,
314
+ params : {
315
+ content : chunk . toString ( ) ,
316
+ } ,
317
+ } ) ;
318
+ }
309
319
} ) ;
310
320
311
321
mcpProxy ( {
312
322
transportToClient : webAppTransport ,
313
323
transportToServer : serverTransport ,
314
324
} ) ;
315
-
316
- console . log ( "Set up MCP proxy" ) ;
317
325
} catch ( error ) {
318
326
console . error ( "Error in /stdio route:" , error ) ;
319
327
res . status ( 500 ) . json ( error ) ;
@@ -323,40 +331,46 @@ app.get("/stdio", async (req, res) => {
323
331
app . get ( "/sse" , async ( req , res ) => {
324
332
try {
325
333
console . log (
326
- "New SSE connection. NOTE: The sse transport is deprecated and has been replaced by streamable-http " ,
334
+ "New SSE connection request . NOTE: The sse transport is deprecated and has been replaced by StreamableHttp " ,
327
335
) ;
328
336
let serverTransport : Transport | undefined ;
329
337
try {
330
338
serverTransport = await createTransport ( req ) ;
331
339
} catch ( error ) {
332
340
if ( error instanceof SseError && error . code === 401 ) {
333
341
console . error (
334
- "Received 401 Unauthorized from MCP server:" ,
335
- error . message ,
342
+ "Received 401 Unauthorized from MCP server. Authentication failure." ,
336
343
) ;
337
344
res . status ( 401 ) . json ( error ) ;
338
345
return ;
346
+ } else if ( error instanceof SseError && error . code === 404 ) {
347
+ console . error (
348
+ "Received 404 not found from MCP server. Does the MCP server support SSE?" ,
349
+ ) ;
350
+ res . status ( 404 ) . json ( error ) ;
351
+ return ;
352
+ } else if ( JSON . stringify ( error ) . includes ( "ECONNREFUSED" ) ) {
353
+ console . error ( "Connection refused. Is the MCP server running?" ) ;
354
+ res . status ( 500 ) . json ( error ) ;
355
+ } else {
356
+ throw error ;
339
357
}
340
-
341
- throw error ;
342
358
}
343
359
344
- console . log ( "Connected MCP client to backing server transport" ) ;
360
+ if ( serverTransport ) {
361
+ const webAppTransport = new SSEServerTransport ( "/message" , res ) ;
362
+ webAppTransports . set ( webAppTransport . sessionId , webAppTransport ) ;
363
+ console . log ( "Created client transport" ) ;
364
+ serverTransports . set ( webAppTransport . sessionId , serverTransport ! ) ;
365
+ console . log ( "Created server transport" ) ;
345
366
346
- const webAppTransport = new SSEServerTransport ( "/message" , res ) ;
347
- webAppTransports . set ( webAppTransport . sessionId , webAppTransport ) ;
348
- console . log ( "Created client transport" ) ;
349
- serverTransports . set ( webAppTransport . sessionId , serverTransport ) ;
350
- console . log ( "Created server transport" ) ;
351
-
352
- await webAppTransport . start ( ) ;
353
-
354
- mcpProxy ( {
355
- transportToClient : webAppTransport ,
356
- transportToServer : serverTransport ,
357
- } ) ;
367
+ await webAppTransport . start ( ) ;
358
368
359
- console . log ( "Set up MCP proxy" ) ;
369
+ mcpProxy ( {
370
+ transportToClient : webAppTransport ,
371
+ transportToServer : serverTransport ,
372
+ } ) ;
373
+ }
360
374
} catch ( error ) {
361
375
console . error ( "Error in /sse route:" , error ) ;
362
376
res . status ( 500 ) . json ( error ) ;
@@ -366,7 +380,7 @@ app.get("/sse", async (req, res) => {
366
380
app . post ( "/message" , async ( req , res ) => {
367
381
try {
368
382
const sessionId = req . query . sessionId ;
369
- console . log ( `Received message for sessionId ${ sessionId } ` ) ;
383
+ console . log ( `Received POST message for sessionId ${ sessionId } ` ) ;
370
384
371
385
const transport = webAppTransports . get (
372
386
sessionId as string ,
0 commit comments