@@ -653,6 +653,122 @@ describe('protocol tests', () => {
653653 expect ( sendSpy ) . toHaveBeenCalledTimes ( 2 ) ;
654654 } ) ;
655655 } ) ;
656+
657+ describe ( 'Error data propagation' , ( ) => {
658+ test ( 'should include error data in response when request handler throws error with data' , async ( ) => {
659+ await protocol . connect ( transport ) ;
660+
661+ // Set up request handler that throws error with data
662+ const RequestSchema = z . object ( {
663+ method : z . literal ( 'test/error-with-data' )
664+ } ) ;
665+
666+ protocol . setRequestHandler ( RequestSchema , ( ) => {
667+ const error = new Error ( 'Test error' ) ;
668+ error [ 'code' ] = ErrorCode . InvalidParams ;
669+ error [ 'data' ] = { details : 'Additional context' , errorCode : 42 } ;
670+ throw error ;
671+ } ) ;
672+
673+ // Simulate incoming request
674+ transport . onmessage ?.( {
675+ jsonrpc : '2.0' ,
676+ id : 1 ,
677+ method : 'test/error-with-data'
678+ } ) ;
679+
680+ // Wait for async error handling
681+ await new Promise ( resolve => setImmediate ( resolve ) ) ;
682+
683+ // Verify error response includes data
684+ expect ( sendSpy ) . toHaveBeenCalledWith ( {
685+ jsonrpc : '2.0' ,
686+ id : 1 ,
687+ error : {
688+ code : ErrorCode . InvalidParams ,
689+ message : 'Test error' ,
690+ data : { details : 'Additional context' , errorCode : 42 }
691+ }
692+ } ) ;
693+ } ) ;
694+
695+ test ( 'should not include data field when request handler throws error without data' , async ( ) => {
696+ await protocol . connect ( transport ) ;
697+
698+ // Set up request handler that throws error without data
699+ const RequestSchema = z . object ( {
700+ method : z . literal ( 'test/error-without-data' )
701+ } ) ;
702+
703+ protocol . setRequestHandler ( RequestSchema , ( ) => {
704+ const error = new Error ( 'Test error' ) ;
705+ error [ 'code' ] = ErrorCode . InternalError ;
706+ throw error ;
707+ } ) ;
708+
709+ // Simulate incoming request
710+ transport . onmessage ?.( {
711+ jsonrpc : '2.0' ,
712+ id : 2 ,
713+ method : 'test/error-without-data'
714+ } ) ;
715+
716+ // Wait for async error handling
717+ await new Promise ( resolve => setImmediate ( resolve ) ) ;
718+
719+ // Verify error response does not include data field
720+ expect ( sendSpy ) . toHaveBeenCalledWith ( {
721+ jsonrpc : '2.0' ,
722+ id : 2 ,
723+ error : {
724+ code : ErrorCode . InternalError ,
725+ message : 'Test error'
726+ }
727+ } ) ;
728+ } ) ;
729+
730+ test ( 'should include error data when request handler throws McpError with data' , async ( ) => {
731+ await protocol . connect ( transport ) ;
732+
733+ // Set up request handler that throws McpError with data
734+ const RequestSchema = z . object ( {
735+ method : z . literal ( 'test/mcperror-with-data' )
736+ } ) ;
737+
738+ protocol . setRequestHandler ( RequestSchema , ( ) => {
739+ throw new McpError ( ErrorCode . InvalidParams , 'Invalid parameter' , {
740+ paramName : 'userId' ,
741+ expectedType : 'string' ,
742+ actualType : 'number'
743+ } ) ;
744+ } ) ;
745+
746+ // Simulate incoming request
747+ transport . onmessage ?.( {
748+ jsonrpc : '2.0' ,
749+ id : 3 ,
750+ method : 'test/mcperror-with-data'
751+ } ) ;
752+
753+ // Wait for async error handling
754+ await new Promise ( resolve => setImmediate ( resolve ) ) ;
755+
756+ // Verify error response includes data from McpError
757+ expect ( sendSpy ) . toHaveBeenCalledWith ( {
758+ jsonrpc : '2.0' ,
759+ id : 3 ,
760+ error : {
761+ code : ErrorCode . InvalidParams ,
762+ message : 'Invalid parameter' ,
763+ data : {
764+ paramName : 'userId' ,
765+ expectedType : 'string' ,
766+ actualType : 'number'
767+ }
768+ }
769+ } ) ;
770+ } ) ;
771+ } ) ;
656772} ) ;
657773
658774describe ( 'mergeCapabilities' , ( ) => {
0 commit comments