@@ -420,27 +420,29 @@ async def _handle_post_request(
420420 request_stream_reader = self ._request_streams [request_id ][1 ]
421421
422422 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 :
426425 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+ }
427435 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+ ),
439441 HTTPStatus .OK ,
440442 )
441443 asyncio .create_task (
442444 self ._send_response_to_webhooks (
443- request_id , session_message , request_stream_reader
445+ request_id , session_message , webhooks , request_stream_reader
444446 )
445447 )
446448 else :
@@ -574,14 +576,13 @@ async def sse_writer():
574576 await writer .send (Exception (err ))
575577 return
576578
577-
578579 async def _send_response_to_webhooks (
579580 self ,
580581 request_id : str ,
581582 session_message : SessionMessage ,
583+ webhooks : list [Webhook ],
582584 request_stream_reader : MemoryObjectReceiveStream [EventMessage ],
583585 ):
584- webhooks : list [Webhook ] = [Webhook (** webhook ) for webhook in session_message .message .root .webhooks ]
585586 writer = self ._read_stream_writer
586587 if writer is None :
587588 raise ValueError (
@@ -611,9 +612,7 @@ async def _send_response_to_webhooks(
611612 break
612613 # For notifications and request, keep waiting
613614 else :
614- logger .debug (
615- f"received: { event_message .message .root .method } "
616- )
615+ logger .debug (f"received: { event_message .message .root .method } " )
617616
618617 await self ._send_message_to_webhooks (webhooks , response_message )
619618 else :
@@ -635,7 +634,6 @@ async def _send_response_to_webhooks(
635634 finally :
636635 await self ._clean_up_memory_streams (request_id )
637636
638-
639637 async def _send_message_to_webhooks (
640638 self ,
641639 webhooks : list [Webhook ],
@@ -646,7 +644,9 @@ async def _send_message_to_webhooks(
646644 # Add authorization headers
647645 if webhook .authentication and webhook .authentication .credentials :
648646 if webhook .authentication .strategy == "bearer" :
649- headers ["Authorization" ] = f"Bearer { webhook .authentication .credentials } "
647+ headers ["Authorization" ] = (
648+ f"Bearer { webhook .authentication .credentials } "
649+ )
650650 elif webhook .authentication .strategy == "apiKey" :
651651 headers ["X-API-Key" ] = webhook .authentication .credentials
652652 elif webhook .authentication .strategy == "basic" :
@@ -656,32 +656,45 @@ async def _send_message_to_webhooks(
656656 if "username" in creds_dict and "password" in creds_dict :
657657 # Create basic auth header from username and password
658658 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 ()
661666 headers ["Authorization" ] = f"Basic { credentials } "
662- except :
667+ except Exception :
663668 # 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+ ):
666676 try :
667677 custom_headers = json .loads (webhook .authentication .credentials )
668678 headers .update (custom_headers )
669- except :
670- pass
679+ except Exception as e :
680+ logger . exception ( f"Error setting custom headers: { e } " )
671681
672682 async with create_mcp_http_client (headers = headers ) as client :
673683 try :
674684 if isinstance (message , JSONRPCMessage | JSONRPCError ):
675685 await client .post (
676686 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+ ),
678690 )
679691 else :
680692 await client .post (webhook .url , json = message )
681693
682694 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+ )
685698
686699 async def _handle_get_request (self , request : Request , send : Send ) -> None :
687700 """
@@ -803,17 +816,18 @@ async def _handle_delete_request(self, request: Request, send: Send) -> None:
803816 )
804817 await response (request .scope , request .receive , send )
805818
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 (
810822 isinstance (message .root , JSONRPCRequest )
811823 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
817831
818832 async def _terminate_session (self ) -> None :
819833 """Terminate the current session, closing all streams.
0 commit comments