Skip to content

Commit 47d4e09

Browse files
committed
test: clarify sanitized tool error coverage
1 parent 3898b88 commit 47d4e09

3 files changed

Lines changed: 16 additions & 11 deletions

File tree

src/mcp/server/mcpserver/tools/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,5 +184,7 @@ async def run(
184184
except ToolError:
185185
raise
186186
except Exception:
187+
# Intentional broad catch at the tool execution boundary: arbitrary
188+
# tool exceptions must not cross the MCP boundary with their value.
187189
logger.exception("Error executing tool %s", self.name)
188190
raise ToolError(f"An unexpected error occurred while executing tool {self.name}") from None

tests/server/mcpserver/test_tool_manager.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ async def async_tool(x: int, ctx: Context) -> str:
383383
assert result == "42"
384384

385385
@pytest.mark.anyio
386-
async def test_context_error_handling(self):
386+
async def test_context_error_handling(self) -> None:
387387
"""Test error handling when context injection fails."""
388388

389389
def tool_with_context(x: int, ctx: Context) -> str:
@@ -392,9 +392,11 @@ def tool_with_context(x: int, ctx: Context) -> str:
392392
manager = ToolManager()
393393
manager.add_tool(tool_with_context)
394394

395-
with pytest.raises(ToolError, match="^An unexpected error occurred while executing tool tool_with_context$"):
395+
with pytest.raises(ToolError) as exc_info:
396396
await manager.call_tool("tool_with_context", {"x": 42}, context=Context())
397397

398+
assert str(exc_info.value) == "An unexpected error occurred while executing tool tool_with_context"
399+
398400

399401
class TestToolAnnotations:
400402
def test_tool_annotations(self):

tests/server/mcpserver/tools/test_base.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,8 @@ async def needs_sampling() -> str:
4343

4444

4545
@pytest.mark.anyio
46-
async def test_non_mcperror_exception_raised_from_a_tool_is_wrapped_as_an_is_error_result():
47-
"""Unexpected tool exceptions become sanitized ``is_error`` results.
48-
49-
The original exception is logged server-side rather than returned to the client.
50-
Pins the other arm of the same branch.
51-
"""
46+
async def test_non_mcperror_exception_raised_from_a_tool_is_wrapped_as_an_is_error_result() -> None:
47+
"""SDK-defined: unexpected tool exceptions become sanitized ``is_error`` results."""
5248
mcp = MCPServer(name="srv")
5349

5450
@mcp.tool()
@@ -63,7 +59,8 @@ async def boom() -> str:
6359

6460

6561
@pytest.mark.anyio
66-
async def test_unexpected_tool_error_is_sanitized_and_logged(caplog: pytest.LogCaptureFixture):
62+
async def test_unexpected_tool_error_is_sanitized_and_logged(caplog: pytest.LogCaptureFixture) -> None:
63+
"""SDK-defined: ``Tool.run`` logs exception details but exposes a stable message."""
6764
secret = "database password"
6865

6966
def boom() -> str:
@@ -81,11 +78,15 @@ def boom() -> str:
8178

8279

8380
@pytest.mark.anyio
84-
async def test_tool_error_is_re_raised_without_wrapping():
81+
async def test_tool_error_is_re_raised_without_wrapping() -> None:
82+
"""SDK-defined: an explicit ``ToolError`` remains actionable and is not wrapped."""
83+
8584
def fail() -> str:
8685
raise ToolError("the requested record is unavailable")
8786

8887
tool = Tool.from_function(fail)
8988

90-
with pytest.raises(ToolError, match="^the requested record is unavailable$"):
89+
with pytest.raises(ToolError) as exc_info:
9190
await tool.run({}, Context())
91+
92+
assert str(exc_info.value) == "the requested record is unavailable"

0 commit comments

Comments
 (0)