@@ -30,7 +30,7 @@ import {
3030
3131// Import error handling
3232import {
33- MethodNotFoundError ,
33+ QuipMCPError ,
3434 ResourceNotFoundError } from './errors' ;
3535
3636// Import logger
@@ -378,17 +378,57 @@ export async function main(): Promise<void> {
378378 server . setRequestHandler ( CallToolRequestSchema , async ( request ) => {
379379 logger . info ( `Handling tools/call request for tool: ${ request . params . name } ` ) ;
380380
381- if ( request . params . name === "quip_read_spreadsheet" ) {
381+ try {
382+ if ( request . params . name === "quip_read_spreadsheet" ) {
383+ return {
384+ content : await handleQuipReadSpreadsheet (
385+ request . params . arguments || { } ,
386+ storageInstance ! ,
387+ options . mock
388+ )
389+ } ;
390+ } else {
391+ logger . error ( `Unknown tool: ${ request . params . name } ` ) ;
392+ // Return error as content instead of throwing to ensure response is sent
393+ return {
394+ content : [ {
395+ type : "text" ,
396+ text : JSON . stringify ( {
397+ error : {
398+ code : - 32601 ,
399+ message : `Method not found: ${ request . params . name } `
400+ }
401+ } )
402+ } ]
403+ } ;
404+ }
405+ } catch ( error ) {
406+ // Log the error for debugging
407+ const errorMessage = error instanceof Error ? error . message : String ( error ) ;
408+ logger . error ( `Error in tool call handler for ${ request . params . name } : ${ errorMessage } ` ) ;
409+
410+ // Instead of throwing, return error as content to ensure response is sent
411+ let errorCode = - 32603 ; // Internal error default
412+ let errorMsg = 'Internal server error' ;
413+
414+ if ( error instanceof QuipMCPError ) {
415+ errorCode = error . code ;
416+ errorMsg = error . message ;
417+ } else if ( error instanceof Error ) {
418+ errorMsg = error . message ;
419+ }
420+
382421 return {
383- content : await handleQuipReadSpreadsheet (
384- request . params . arguments || { } ,
385- storageInstance ! ,
386- options . mock
387- )
422+ content : [ {
423+ type : "text" ,
424+ text : JSON . stringify ( {
425+ error : {
426+ code : errorCode ,
427+ message : errorMsg
428+ }
429+ } )
430+ } ]
388431 } ;
389- } else {
390- logger . error ( `Unknown tool: ${ request . params . name } ` ) ;
391- throw new MethodNotFoundError ( `Unknown tool: ${ request . params . name } ` ) ;
392432 }
393433 } ) ;
394434
@@ -442,33 +482,78 @@ export async function main(): Promise<void> {
442482 app . post ( '/mcp' , async ( req : Request , res : Response ) => {
443483 logger . info ( 'Received POST MCP request' ) ;
444484
485+ // Set request timeout to prevent hanging connections
486+ const requestTimeout = setTimeout ( ( ) => {
487+ if ( ! res . headersSent ) {
488+ logger . error ( 'Request timeout - forcing response' ) ;
489+ res . status ( 408 ) . json ( {
490+ jsonrpc : '2.0' ,
491+ error : {
492+ code : - 32000 ,
493+ message : 'Request timeout'
494+ } ,
495+ id : req . body ?. id || null
496+ } ) ;
497+ }
498+ } , 30000 ) ; // 30 second timeout
499+
445500 try {
446501 // Each request gets its own transport and server instance for stateless mode
447502 const transport = new StreamableHTTPServerTransport ( {
448503 sessionIdGenerator : undefined , // No sessions in stateless mode
449504 enableJsonResponse : true
450505 } ) ;
451506
452- // Clean up on request close
507+ // Clean up on request close or completion
508+ const cleanup = ( ) => {
509+ clearTimeout ( requestTimeout ) ;
510+ transport . close ( ) ;
511+ } ;
512+
453513 res . on ( 'close' , ( ) => {
454514 logger . info ( 'Request closed' ) ;
455- transport . close ( ) ;
515+ cleanup ( ) ;
516+ } ) ;
517+
518+ res . on ( 'finish' , ( ) => {
519+ logger . info ( 'Request finished' ) ;
520+ cleanup ( ) ;
456521 } ) ;
457522
458523 await server . connect ( transport ) ;
459524 await transport . handleRequest ( req , res , req . body ) ;
525+
526+ // Clear timeout on successful completion
527+ clearTimeout ( requestTimeout ) ;
528+
460529 } catch ( error ) {
530+ // Clear timeout on error
531+ clearTimeout ( requestTimeout ) ;
532+
461533 const errorMessage = error instanceof Error ? error . message : String ( error ) ;
462534 logger . error ( 'Error handling MCP request:' , { error : errorMessage } ) ;
463535
464536 if ( ! res . headersSent ) {
537+ // Determine appropriate error code and message based on error type
538+ let errorCode = - 32603 ; // Internal error default
539+ let errorMsg = 'Internal server error' ;
540+
541+ // Handle specific error types
542+ if ( error instanceof Error ) {
543+ const err = error as any ;
544+ if ( err . code && typeof err . code === 'number' ) {
545+ errorCode = err . code ;
546+ errorMsg = error . message ;
547+ }
548+ }
549+
465550 res . status ( 500 ) . json ( {
466551 jsonrpc : '2.0' ,
467552 error : {
468- code : - 32603 ,
469- message : 'Internal server error'
553+ code : errorCode ,
554+ message : errorMsg
470555 } ,
471- id : null
556+ id : req . body ?. id || null
472557 } ) ;
473558 }
474559 }
0 commit comments