@@ -420,27 +420,29 @@ async def _handle_post_request(
420
420
request_stream_reader = self ._request_streams [request_id ][1 ]
421
421
422
422
session_message = SessionMessage (message )
423
- if self ._is_call_tool_request_with_webhooks (
424
- session_message .message
425
- ):
423
+ webhooks = self ._get_webhooks (session_message .message )
424
+ if webhooks is not None :
426
425
if self .is_webhooks_supported :
426
+ result = {
427
+ "content" : [
428
+ {
429
+ "type" : "text" ,
430
+ "text" : "Response will be forwarded to the webhook." ,
431
+ }
432
+ ],
433
+ "isError" : False ,
434
+ }
427
435
response = self ._create_json_response (
428
- JSONRPCMessage (root = JSONRPCResponse (
429
- jsonrpc = "2.0" ,
430
- id = message .root .id ,
431
- result = {
432
- 'content' : [{
433
- 'type' : 'text' ,
434
- 'text' : 'Response will be forwarded to the webhook.'
435
- }],
436
- 'isError' : False
437
- },
438
- )),
436
+ JSONRPCMessage (
437
+ root = JSONRPCResponse (
438
+ jsonrpc = "2.0" , id = message .root .id , result = result
439
+ )
440
+ ),
439
441
HTTPStatus .OK ,
440
442
)
441
443
asyncio .create_task (
442
444
self ._send_response_to_webhooks (
443
- request_id , session_message , request_stream_reader
445
+ request_id , session_message , webhooks , request_stream_reader
444
446
)
445
447
)
446
448
else :
@@ -574,14 +576,13 @@ async def sse_writer():
574
576
await writer .send (Exception (err ))
575
577
return
576
578
577
-
578
579
async def _send_response_to_webhooks (
579
580
self ,
580
581
request_id : str ,
581
582
session_message : SessionMessage ,
583
+ webhooks : list [Webhook ],
582
584
request_stream_reader : MemoryObjectReceiveStream [EventMessage ],
583
585
):
584
- webhooks : list [Webhook ] = [Webhook (** webhook ) for webhook in session_message .message .root .webhooks ]
585
586
writer = self ._read_stream_writer
586
587
if writer is None :
587
588
raise ValueError (
@@ -611,9 +612,7 @@ async def _send_response_to_webhooks(
611
612
break
612
613
# For notifications and request, keep waiting
613
614
else :
614
- logger .debug (
615
- f"received: { event_message .message .root .method } "
616
- )
615
+ logger .debug (f"received: { event_message .message .root .method } " )
617
616
618
617
await self ._send_message_to_webhooks (webhooks , response_message )
619
618
else :
@@ -635,7 +634,6 @@ async def _send_response_to_webhooks(
635
634
finally :
636
635
await self ._clean_up_memory_streams (request_id )
637
636
638
-
639
637
async def _send_message_to_webhooks (
640
638
self ,
641
639
webhooks : list [Webhook ],
@@ -646,7 +644,9 @@ async def _send_message_to_webhooks(
646
644
# Add authorization headers
647
645
if webhook .authentication and webhook .authentication .credentials :
648
646
if webhook .authentication .strategy == "bearer" :
649
- headers ["Authorization" ] = f"Bearer { webhook .authentication .credentials } "
647
+ headers ["Authorization" ] = (
648
+ f"Bearer { webhook .authentication .credentials } "
649
+ )
650
650
elif webhook .authentication .strategy == "apiKey" :
651
651
headers ["X-API-Key" ] = webhook .authentication .credentials
652
652
elif webhook .authentication .strategy == "basic" :
@@ -656,32 +656,45 @@ async def _send_message_to_webhooks(
656
656
if "username" in creds_dict and "password" in creds_dict :
657
657
# Create basic auth header from username and password
658
658
import base64
659
- auth_string = f"{ creds_dict ['username' ]} :{ creds_dict ['password' ]} "
660
- credentials = base64 .b64encode (auth_string .encode ()).decode ()
659
+
660
+ auth_string = (
661
+ f"{ creds_dict ['username' ]} :{ creds_dict ['password' ]} "
662
+ )
663
+ credentials = base64 .b64encode (
664
+ auth_string .encode ()
665
+ ).decode ()
661
666
headers ["Authorization" ] = f"Basic { credentials } "
662
- except :
667
+ except Exception :
663
668
# Not JSON, use as-is
664
- headers ["Authorization" ] = f"Basic { webhook .authentication .credentials } "
665
- elif webhook .authentication .strategy == "customHeader" and webhook .authentication .credentials :
669
+ headers ["Authorization" ] = (
670
+ f"Basic { webhook .authentication .credentials } "
671
+ )
672
+ elif (
673
+ webhook .authentication .strategy == "customHeader"
674
+ and webhook .authentication .credentials
675
+ ):
666
676
try :
667
677
custom_headers = json .loads (webhook .authentication .credentials )
668
678
headers .update (custom_headers )
669
- except :
670
- pass
679
+ except Exception as e :
680
+ logger . exception ( f"Error setting custom headers: { e } " )
671
681
672
682
async with create_mcp_http_client (headers = headers ) as client :
673
683
try :
674
684
if isinstance (message , JSONRPCMessage | JSONRPCError ):
675
685
await client .post (
676
686
webhook .url ,
677
- json = message .model_dump_json (by_alias = True , exclude_none = True ),
687
+ json = message .model_dump_json (
688
+ by_alias = True , exclude_none = True
689
+ ),
678
690
)
679
691
else :
680
692
await client .post (webhook .url , json = message )
681
693
682
694
except Exception as e :
683
- logger .exception (f"Error sending response to webhook { webhook .url } : { e } " )
684
-
695
+ logger .exception (
696
+ f"Error sending response to webhook { webhook .url } : { e } "
697
+ )
685
698
686
699
async def _handle_get_request (self , request : Request , send : Send ) -> None :
687
700
"""
@@ -803,17 +816,18 @@ async def _handle_delete_request(self, request: Request, send: Send) -> None:
803
816
)
804
817
await response (request .scope , request .receive , send )
805
818
806
-
807
- def _is_call_tool_request_with_webhooks (self , message : JSONRPCMessage ) -> bool :
808
- """Check if the request is a call tool request with webhooks."""
809
- return (
819
+ def _get_webhooks (self , message : JSONRPCMessage ) -> list [Webhook ] | None :
820
+ """Return webhooks if the request is a call tool request with webhooks."""
821
+ if (
810
822
isinstance (message .root , JSONRPCRequest )
811
823
and message .root .method == "tools/call"
812
- and hasattr (message .root , "webhooks" )
813
- and message .root .webhooks is not None
814
- and len (message .root .webhooks ) > 0
815
- )
816
-
824
+ and message .root .params is not None
825
+ and "webhooks" in message .root .params
826
+ and message .root .params ["webhooks" ] is not None
827
+ and len (message .root .params ["webhooks" ]) > 0
828
+ ):
829
+ return [Webhook (** webhook ) for webhook in message .root .params ["webhooks" ]]
830
+ return None
817
831
818
832
async def _terminate_session (self ) -> None :
819
833
"""Terminate the current session, closing all streams.
0 commit comments