66
77import functools
88import json
9- from typing import Any , Callable , Dict , Union
9+ from typing import Any , Callable
10+
11+
12+ class MCPToolError (RuntimeError ):
13+ """Exception raised when an MCP entry point fails."""
14+
15+ def __init__ (self , message : str ):
16+ super ().__init__ (message )
1017
1118
1219def handle_mcp_errors (return_type : str = 'str' ) -> Callable :
1320 """
1421 Decorator to handle exceptions in MCP entry points consistently.
1522
16- This decorator catches all exceptions and formats them according to the expected
17- return type, providing consistent error responses across all MCP entry points.
23+ This decorator catches all exceptions and rethrows them as MCPToolError after
24+ formatting a consistent error message. FastMCP converts the raised exception
25+ into a structured error response for the client.
1826
1927 Args:
20- return_type: The expected return type format
21- - 'str': Returns error as string format "Error: {message}"
22- - 'dict': Returns error as dict format {"error": "Operation failed: {message}"}
23- - 'json': Returns error as JSON string with dict format
28+ return_type: Label used to format the error message for logging/consistency.
29+ - 'str'/'list'/others: Prefixes message with "Error: ..."
30+ - 'dict'/'json': Prefixes message with "Operation failed: ..."
2431
2532 Returns:
2633 Decorator function that wraps MCP entry points with error handling
@@ -39,18 +46,15 @@ def search_code_advanced(pattern: str, ctx: Context, **kwargs) -> Dict[str, Any]
3946 """
4047 def decorator (func : Callable ) -> Callable :
4148 @functools .wraps (func )
42- def wrapper (* args , ** kwargs ) -> Union [ str , Dict [ str , Any ]] :
49+ def wrapper (* args , ** kwargs ) -> Any :
4350 try :
4451 return func (* args , ** kwargs )
45- except Exception as e :
46- error_message = str (e )
47-
48- if return_type == 'dict' :
49- return {"error" : f"Operation failed: { error_message } " }
50- elif return_type == 'json' :
51- return json .dumps ({"error" : f"Operation failed: { error_message } " })
52- else : # return_type == 'str' (default)
53- return f"Error: { error_message } "
52+ except MCPToolError :
53+ raise
54+ except Exception as exc :
55+ error_message = str (exc )
56+ formatted = _format_error_message (error_message , return_type )
57+ raise MCPToolError (formatted ) from exc
5458
5559 return wrapper
5660 return decorator
@@ -88,7 +92,7 @@ def handle_mcp_tool_errors(return_type: str = 'str') -> Callable:
8892 which may return either strings or dictionaries.
8993
9094 Args:
91- return_type: The expected return type ( 'str' or 'dict')
95+ return_type: Label describing the successful payload shape (e.g. 'str', 'dict', 'list').
9296
9397 Returns:
9498 Decorator function for MCP tools
@@ -101,3 +105,19 @@ def find_files(pattern: str, ctx: Context) -> Dict[str, Any]:
101105 return FileDiscoveryService(ctx).find_files(pattern)
102106 """
103107 return handle_mcp_errors (return_type = return_type )
108+
109+
110+ def _format_error_message (error_message : str , return_type : str ) -> str :
111+ """
112+ Convert an exception message into a consistent string for MCP errors.
113+
114+ Args:
115+ error_message: The raw exception message.
116+ return_type: The declared return type for the decorated entry point.
117+
118+ Returns:
119+ A string representation suitable for raising as MCPToolError.
120+ """
121+ if return_type in {'dict' , 'json' }:
122+ return f"Operation failed: { error_message } "
123+ return f"Error: { error_message } "
0 commit comments