@@ -37,6 +37,11 @@ export type ProtocolOptions = {
37
37
enforceStrictCapabilities ?: boolean ;
38
38
} ;
39
39
40
+ /**
41
+ * The default request timeout, in miliseconds.
42
+ */
43
+ export const DEFAULT_REQUEST_TIMEOUT_MSEC = 60000 ;
44
+
40
45
/**
41
46
* Options that can be given per request.
42
47
*/
@@ -50,6 +55,13 @@ export type RequestOptions = {
50
55
* Can be used to cancel an in-flight request. This will cause an AbortError to be raised from request().
51
56
*/
52
57
signal ?: AbortSignal ;
58
+
59
+ /**
60
+ * A timeout (in milliseconds) for this request. If exceeded, an McpError with code `RequestTimeout` will be raised from request().
61
+ *
62
+ * If not specified, `DEFAULT_REQUEST_TIMEOUT_MSEC` will be used as the timeout.
63
+ */
64
+ timeout ?: number ;
53
65
} ;
54
66
55
67
/**
@@ -379,7 +391,13 @@ export abstract class Protocol<
379
391
} ;
380
392
}
381
393
394
+ let timeoutId : ReturnType < typeof setTimeout > | undefined = undefined ;
395
+
382
396
this . _responseHandlers . set ( messageId , ( response ) => {
397
+ if ( timeoutId !== undefined ) {
398
+ clearTimeout ( timeoutId ) ;
399
+ }
400
+
383
401
if ( options ?. signal ?. aborted ) {
384
402
return ;
385
403
}
@@ -396,8 +414,7 @@ export abstract class Protocol<
396
414
}
397
415
} ) ;
398
416
399
- options ?. signal ?. addEventListener ( "abort" , ( ) => {
400
- const reason = options ?. signal ?. reason ;
417
+ const cancel = ( reason : unknown ) => {
401
418
this . _responseHandlers . delete ( messageId ) ;
402
419
this . _progressHandlers . delete ( messageId ) ;
403
420
@@ -411,9 +428,34 @@ export abstract class Protocol<
411
428
} ) ;
412
429
413
430
reject ( reason ) ;
431
+ } ;
432
+
433
+ options ?. signal ?. addEventListener ( "abort" , ( ) => {
434
+ if ( timeoutId !== undefined ) {
435
+ clearTimeout ( timeoutId ) ;
436
+ }
437
+
438
+ cancel ( options ?. signal ?. reason ) ;
414
439
} ) ;
415
440
416
- this . _transport . send ( jsonrpcRequest ) . catch ( reject ) ;
441
+ const timeout = options ?. timeout ?? DEFAULT_REQUEST_TIMEOUT_MSEC ;
442
+ timeoutId = setTimeout (
443
+ ( ) =>
444
+ cancel (
445
+ new McpError ( ErrorCode . RequestTimeout , "Request timed out" , {
446
+ timeout,
447
+ } ) ,
448
+ ) ,
449
+ timeout ,
450
+ ) ;
451
+
452
+ this . _transport . send ( jsonrpcRequest ) . catch ( ( error ) => {
453
+ if ( timeoutId !== undefined ) {
454
+ clearTimeout ( timeoutId ) ;
455
+ }
456
+
457
+ reject ( error ) ;
458
+ } ) ;
417
459
} ) ;
418
460
}
419
461
0 commit comments