@@ -290,26 +290,51 @@ def _set_span_output_data(span, result, result_data_key, handler_type):
290290# Handler data preparation and wrapping
291291
292292
293- def _prepare_handler_data (handler_type , original_args ):
294- # type: (str, tuple[Any, ...]) -> tuple[str, dict[str, Any], str, str, str, Optional[str]]
293+ def _prepare_handler_data (handler_type , original_args , original_kwargs = None ):
294+ # type: (str, tuple[Any, ...], Optional[dict[str, Any]] ) -> tuple[str, dict[str, Any], str, str, str, Optional[str]]
295295 """
296296 Prepare common handler data for both async and sync wrappers.
297297
298298 Returns:
299299 Tuple of (handler_name, arguments, span_data_key, span_name, mcp_method_name, result_data_key)
300300 """
301+ original_kwargs = original_kwargs or {}
302+
301303 # Extract handler-specific data based on handler type
302304 if handler_type == "tool" :
303- handler_name = original_args [0 ] # tool_name
304- arguments = original_args [1 ] if len (original_args ) > 1 else {}
305+ if original_args :
306+ handler_name = original_args [0 ]
307+ elif original_kwargs .get ("tool_name" ):
308+ handler_name = original_kwargs ["tool_name" ]
309+
310+ arguments = {}
311+ if len (original_args ) > 1 :
312+ arguments = original_args [1 ]
313+ elif original_kwargs .get ("arguments" ):
314+ arguments = original_kwargs ["arguments" ]
315+
305316 elif handler_type == "prompt" :
306- handler_name = original_args [0 ] # name
307- arguments = original_args [1 ] if len (original_args ) > 1 else {}
317+ if original_args :
318+ handler_name = original_args [0 ]
319+ elif original_kwargs .get ("tool_name" ):
320+ handler_name = original_kwargs ["tool_name" ]
321+
322+ arguments = {}
323+ if len (original_args ) > 1 :
324+ arguments = original_args [1 ]
325+ elif original_kwargs .get ("arguments" ):
326+ arguments = original_kwargs ["arguments" ]
327+
308328 # Include name in arguments dict for span data
309329 arguments = {"name" : handler_name , ** (arguments or {})}
330+
310331 else : # resource
311- uri = original_args [0 ]
312- handler_name = str (uri ) if uri else "unknown"
332+ handler_name = "unknown"
333+ if original_args :
334+ handler_name = str (original_args [0 ])
335+ elif original_kwargs .get ("uri" ):
336+ handler_name = str (original_kwargs ["uri" ])
337+
313338 arguments = {}
314339
315340 # Get span configuration
@@ -327,8 +352,10 @@ def _prepare_handler_data(handler_type, original_args):
327352 )
328353
329354
330- async def _async_handler_wrapper (handler_type , func , original_args ):
331- # type: (str, Callable[..., Any], tuple[Any, ...]) -> Any
355+ async def _async_handler_wrapper (
356+ handler_type , func , original_args , original_kwargs = None
357+ ):
358+ # type: (str, Callable[..., Any], tuple[Any, ...], Optional[dict[Any, Any]]) -> Any
332359 """
333360 Async wrapper for MCP handlers.
334361
@@ -337,14 +364,17 @@ async def _async_handler_wrapper(handler_type, func, original_args):
337364 func: The async handler function to wrap
338365 original_args: Original arguments passed to the handler
339366 """
367+ if original_kwargs is None :
368+ original_kwargs = {}
369+
340370 (
341371 handler_name ,
342372 arguments ,
343373 span_data_key ,
344374 span_name ,
345375 mcp_method_name ,
346376 result_data_key ,
347- ) = _prepare_handler_data (handler_type , original_args )
377+ ) = _prepare_handler_data (handler_type , original_args , original_kwargs )
348378
349379 # Start span and execute
350380 with get_start_span_function ()(
@@ -380,7 +410,7 @@ async def _async_handler_wrapper(handler_type, func, original_args):
380410
381411 try :
382412 # Execute the async handler
383- result = await func (* original_args )
413+ result = await func (* original_args , ** original_kwargs )
384414 except Exception as e :
385415 # Set error flag for tools
386416 if handler_type == "tool" :
@@ -588,84 +618,28 @@ def _patch_fastmcp():
588618 original_get_prompt_mcp = FastMCP ._get_prompt_mcp
589619
590620 @wraps (original_get_prompt_mcp )
591- async def patched_get_prompt_mcp (self , name , arguments = None ):
592- # type: (Any, str, Optional[dict[str, Any]] ) -> Any
593- return await _async_fastmcp_handler_wrapper (
621+ async def patched_get_prompt_mcp (self , * args , ** kwargs ):
622+ # type: (Any, Any) -> Any
623+ return await _async_handler_wrapper (
594624 "prompt" ,
595- lambda n , a : original_get_prompt_mcp (self , n , a ),
596- (name , arguments ),
625+ original_get_prompt_mcp ,
626+ args ,
627+ kwargs ,
597628 )
598629
599630 FastMCP ._get_prompt_mcp = patched_get_prompt_mcp
600631
601- # Patch _read_resource_mcp
602632 if hasattr (FastMCP , "_read_resource_mcp" ):
603633 original_read_resource_mcp = FastMCP ._read_resource_mcp
604634
605635 @wraps (original_read_resource_mcp )
606- async def patched_read_resource_mcp (self , uri ):
636+ async def patched_read_resource_mcp (self , * args , ** kwargs ):
607637 # type: (Any, Any) -> Any
608- return await _async_fastmcp_handler_wrapper (
638+ return await _async_handler_wrapper (
609639 "resource" ,
610- lambda u : original_read_resource_mcp (self , u ),
611- (uri ,),
640+ original_read_resource_mcp ,
641+ args ,
642+ kwargs ,
612643 )
613644
614645 FastMCP ._read_resource_mcp = patched_read_resource_mcp
615-
616-
617- async def _async_fastmcp_handler_wrapper (handler_type , func , original_args ):
618- # type: (str, Callable[..., Any], tuple[Any, ...]) -> Any
619- """
620- Async wrapper for standalone FastMCP handlers.
621-
622- Similar to _async_handler_wrapper but the original function is already
623- a coroutine function that we call directly.
624- """
625- (
626- handler_name ,
627- arguments ,
628- span_data_key ,
629- span_name ,
630- mcp_method_name ,
631- result_data_key ,
632- ) = _prepare_handler_data (handler_type , original_args )
633-
634- with get_start_span_function ()(
635- op = OP .MCP_SERVER ,
636- name = span_name ,
637- origin = MCPIntegration .origin ,
638- ) as span :
639- request_id , session_id , mcp_transport = _get_request_context_data ()
640-
641- _set_span_input_data (
642- span ,
643- handler_name ,
644- span_data_key ,
645- mcp_method_name ,
646- arguments ,
647- request_id ,
648- session_id ,
649- mcp_transport ,
650- )
651-
652- if handler_type == "resource" :
653- uri = original_args [0 ]
654- protocol = None
655- if hasattr (uri , "scheme" ):
656- protocol = uri .scheme
657- elif handler_name and "://" in handler_name :
658- protocol = handler_name .split ("://" )[0 ]
659- if protocol :
660- span .set_data (SPANDATA .MCP_RESOURCE_PROTOCOL , protocol )
661-
662- try :
663- result = await func (* original_args )
664- except Exception as e :
665- if handler_type == "tool" :
666- span .set_data (SPANDATA .MCP_TOOL_RESULT_IS_ERROR , True )
667- sentry_sdk .capture_exception (e )
668- raise
669-
670- _set_span_output_data (span , result , result_data_key , handler_type )
671- return result
0 commit comments