Skip to content

Commit 7e88410

Browse files
committed
fix(utils): standardize MCP error propagation
1 parent 18642d8 commit 7e88410

File tree

2 files changed

+46
-20
lines changed

2 files changed

+46
-20
lines changed

src/code_index_mcp/utils/__init__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@
88
- response_formatter: Response formatting utilities
99
"""
1010

11-
from .error_handler import handle_mcp_errors, handle_mcp_resource_errors, handle_mcp_tool_errors
11+
from .error_handler import (
12+
handle_mcp_errors,
13+
handle_mcp_resource_errors,
14+
handle_mcp_tool_errors,
15+
MCPToolError,
16+
)
1217
from .context_helper import ContextHelper
1318
from .validation import ValidationHelper
1419
from .response_formatter import ResponseFormatter
@@ -18,8 +23,9 @@
1823
'handle_mcp_errors',
1924
'handle_mcp_resource_errors',
2025
'handle_mcp_tool_errors',
26+
'MCPToolError',
2127
'ContextHelper',
2228
'ValidationHelper',
2329
'ResponseFormatter',
2430
'FileFilter'
25-
]
31+
]

src/code_index_mcp/utils/error_handler.py

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,28 @@
66

77
import functools
88
import 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

1219
def 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

Comments
 (0)