@@ -674,4 +674,118 @@ describe("StreamableHTTPServerTransport", () => {
674
674
expect ( onErrorMock ) . toHaveBeenCalled ( ) ;
675
675
} ) ;
676
676
} ) ;
677
+
678
+ describe ( "Handling Pre-Parsed Body" , ( ) => {
679
+ it ( "should accept pre-parsed request body" , async ( ) => {
680
+ const message : JSONRPCMessage = {
681
+ jsonrpc : "2.0" ,
682
+ method : "initialize" ,
683
+ params : {
684
+ clientInfo : { name : "test-client" , version : "1.0" } ,
685
+ protocolVersion : "2025-03-26"
686
+ } ,
687
+ id : "pre-parsed-test" ,
688
+ } ;
689
+
690
+ // Create a request without actual body content
691
+ const req = createMockRequest ( {
692
+ method : "POST" ,
693
+ headers : {
694
+ "content-type" : "application/json" ,
695
+ "accept" : "application/json" ,
696
+ } ,
697
+ // No body provided here - it will be passed as parsedBody
698
+ } ) ;
699
+
700
+ const onMessageMock = jest . fn ( ) ;
701
+ transport . onmessage = onMessageMock ;
702
+
703
+ // Pass the pre-parsed body directly
704
+ await transport . handleRequest ( req , mockResponse , message ) ;
705
+
706
+ // Verify the message was processed correctly
707
+ expect ( onMessageMock ) . toHaveBeenCalledWith ( message ) ;
708
+ expect ( mockResponse . writeHead ) . toHaveBeenCalledWith (
709
+ 200 ,
710
+ expect . objectContaining ( {
711
+ "Content-Type" : "application/json" ,
712
+ } )
713
+ ) ;
714
+ } ) ;
715
+
716
+ it ( "should handle pre-parsed batch messages" , async ( ) => {
717
+ const batchMessages : JSONRPCMessage [ ] = [
718
+ {
719
+ jsonrpc : "2.0" ,
720
+ method : "method1" ,
721
+ params : { data : "test1" } ,
722
+ id : "batch1"
723
+ } ,
724
+ {
725
+ jsonrpc : "2.0" ,
726
+ method : "method2" ,
727
+ params : { data : "test2" } ,
728
+ id : "batch2"
729
+ } ,
730
+ ] ;
731
+
732
+ // Create a request without actual body content
733
+ const req = createMockRequest ( {
734
+ method : "POST" ,
735
+ headers : {
736
+ "content-type" : "application/json" ,
737
+ "accept" : "text/event-stream" ,
738
+ "mcp-session-id" : transport . sessionId ,
739
+ } ,
740
+ // No body provided here - it will be passed as parsedBody
741
+ } ) ;
742
+
743
+ const onMessageMock = jest . fn ( ) ;
744
+ transport . onmessage = onMessageMock ;
745
+
746
+ // Pass the pre-parsed body directly
747
+ await transport . handleRequest ( req , mockResponse , batchMessages ) ;
748
+
749
+ // Should be called for each message in the batch
750
+ expect ( onMessageMock ) . toHaveBeenCalledTimes ( 2 ) ;
751
+ expect ( onMessageMock ) . toHaveBeenCalledWith ( batchMessages [ 0 ] ) ;
752
+ expect ( onMessageMock ) . toHaveBeenCalledWith ( batchMessages [ 1 ] ) ;
753
+ } ) ;
754
+
755
+ it ( "should prefer pre-parsed body over request body" , async ( ) => {
756
+ const requestBodyMessage : JSONRPCMessage = {
757
+ jsonrpc : "2.0" ,
758
+ method : "fromRequestBody" ,
759
+ params : { } ,
760
+ id : "request-body" ,
761
+ } ;
762
+
763
+ const parsedBodyMessage : JSONRPCMessage = {
764
+ jsonrpc : "2.0" ,
765
+ method : "fromParsedBody" ,
766
+ params : { } ,
767
+ id : "parsed-body" ,
768
+ } ;
769
+
770
+ // Create a request with actual body content
771
+ const req = createMockRequest ( {
772
+ method : "POST" ,
773
+ headers : {
774
+ "content-type" : "application/json" ,
775
+ "accept" : "application/json" ,
776
+ } ,
777
+ body : JSON . stringify ( requestBodyMessage ) ,
778
+ } ) ;
779
+
780
+ const onMessageMock = jest . fn ( ) ;
781
+ transport . onmessage = onMessageMock ;
782
+
783
+ // Pass the pre-parsed body directly
784
+ await transport . handleRequest ( req , mockResponse , parsedBodyMessage ) ;
785
+
786
+ // Should use the parsed body instead of the request body
787
+ expect ( onMessageMock ) . toHaveBeenCalledWith ( parsedBodyMessage ) ;
788
+ expect ( onMessageMock ) . not . toHaveBeenCalledWith ( requestBodyMessage ) ;
789
+ } ) ;
790
+ } ) ;
677
791
} ) ;
0 commit comments