@@ -5509,6 +5509,106 @@ describe('Error handling for missing resolvers', () => {
55095509 expect ( callOrder ) . toEqual ( [ 1 , 2 , 3 ] ) ;
55105510 } ) ;
55115511 } ) ;
5512+
5513+ describe ( 'unsafe integer request ID validation' , ( ) => {
5514+ let protocol : Protocol < BaseContext > ;
5515+ let transport : MockTransport ;
5516+
5517+ beforeEach ( ( ) => {
5518+ transport = new MockTransport ( ) ;
5519+ protocol = new ( class extends Protocol < BaseContext > {
5520+ protected assertCapabilityForMethod ( ) : void { }
5521+ protected assertNotificationCapability ( ) : void { }
5522+ protected assertRequestHandlerCapability ( ) : void { }
5523+ protected assertTaskCapability ( ) : void { }
5524+ protected buildContext ( ctx : BaseContext ) : BaseContext {
5525+ return ctx ;
5526+ }
5527+ protected assertTaskHandlerCapability ( ) : void { }
5528+ } ) ( ) ;
5529+ } ) ;
5530+
5531+ it ( 'should respond with InvalidRequest error when request ID exceeds MAX_SAFE_INTEGER' , async ( ) => {
5532+ await protocol . connect ( transport ) ;
5533+ const sendSpy = vi . spyOn ( transport , 'send' ) ;
5534+
5535+ // Send a request with an ID exceeding Number.MAX_SAFE_INTEGER
5536+ // Note: 9007199254740992 === Number.MAX_SAFE_INTEGER + 1, but due to
5537+ // floating-point precision loss, JavaScript cannot represent it exactly.
5538+ const unsafeId = Number . MAX_SAFE_INTEGER + 1 ;
5539+ transport . onmessage ?.( {
5540+ jsonrpc : '2.0' ,
5541+ id : unsafeId ,
5542+ method : 'tools/list' ,
5543+ params : { }
5544+ } ) ;
5545+
5546+ // Wait for async processing
5547+ await new Promise ( resolve => setTimeout ( resolve , 50 ) ) ;
5548+
5549+ // Should have sent an error response
5550+ expect ( sendSpy ) . toHaveBeenCalledTimes ( 1 ) ;
5551+ const sentMessage = sendSpy . mock . calls [ 0 ] [ 0 ] as JSONRPCErrorResponse ;
5552+ expect ( sentMessage . jsonrpc ) . toBe ( '2.0' ) ;
5553+ expect ( sentMessage . id ) . toBe ( unsafeId ) ;
5554+ expect ( sentMessage . error . code ) . toBe ( ProtocolErrorCode . InvalidRequest ) ;
5555+ expect ( sentMessage . error . message ) . toBe ( 'Invalid request: ID must be a string or a safe integer' ) ;
5556+ } ) ;
5557+
5558+ it ( 'should process requests normally when ID is at MAX_SAFE_INTEGER' , async ( ) => {
5559+ await protocol . connect ( transport ) ;
5560+ const sendSpy = vi . spyOn ( transport , 'send' ) ;
5561+
5562+ protocol . setRequestHandler ( 'tools/list' , async ( ) => {
5563+ return { tools : [ ] } ;
5564+ } ) ;
5565+
5566+ // Send a request with ID exactly at Number.MAX_SAFE_INTEGER
5567+ transport . onmessage ?.( {
5568+ jsonrpc : '2.0' ,
5569+ id : Number . MAX_SAFE_INTEGER ,
5570+ method : 'tools/list' ,
5571+ params : { }
5572+ } ) ;
5573+
5574+ // Wait for async processing
5575+ await new Promise ( resolve => setTimeout ( resolve , 50 ) ) ;
5576+
5577+ // Should have sent a successful response, not an error
5578+ expect ( sendSpy ) . toHaveBeenCalledTimes ( 1 ) ;
5579+ const sentMessage = sendSpy . mock . calls [ 0 ] [ 0 ] as JSONRPCResultResponse ;
5580+ expect ( sentMessage . jsonrpc ) . toBe ( '2.0' ) ;
5581+ expect ( sentMessage . id ) . toBe ( Number . MAX_SAFE_INTEGER ) ;
5582+ expect ( sentMessage . result ) . toBeDefined ( ) ;
5583+ } ) ;
5584+
5585+ it ( 'should process requests normally when ID is a string' , async ( ) => {
5586+ await protocol . connect ( transport ) ;
5587+ const sendSpy = vi . spyOn ( transport , 'send' ) ;
5588+
5589+ protocol . setRequestHandler ( 'tools/list' , async ( ) => {
5590+ return { tools : [ ] } ;
5591+ } ) ;
5592+
5593+ // String IDs should always be accepted regardless of content
5594+ transport . onmessage ?.( {
5595+ jsonrpc : '2.0' ,
5596+ id : '9007199254740992' ,
5597+ method : 'tools/list' ,
5598+ params : { }
5599+ } ) ;
5600+
5601+ // Wait for async processing
5602+ await new Promise ( resolve => setTimeout ( resolve , 50 ) ) ;
5603+
5604+ // Should have sent a successful response
5605+ expect ( sendSpy ) . toHaveBeenCalledTimes ( 1 ) ;
5606+ const sentMessage = sendSpy . mock . calls [ 0 ] [ 0 ] as JSONRPCResultResponse ;
5607+ expect ( sentMessage . jsonrpc ) . toBe ( '2.0' ) ;
5608+ expect ( sentMessage . id ) . toBe ( '9007199254740992' ) ;
5609+ expect ( sentMessage . result ) . toBeDefined ( ) ;
5610+ } ) ;
5611+ } ) ;
55125612} ) ;
55135613
55145614describe ( 'Protocol without task configuration' , ( ) => {
0 commit comments