fix: handle ToolError exceptions in MCP clients to reduce production alerts (#8599)

Add ToolError to exception handling alongside McpError in MCP client classes.
ToolError is raised by fastmcp for input validation errors (e.g., missing
required properties like 'filename'). Both error types are expected user-facing
errors from external MCP servers and should be logged at warning/debug level
to avoid triggering production alerts.

Fixes issue with production error: "fastmcp.exceptions.ToolError: Input
validation error: 'filename' is a required property"

🤖 Generated with [Letta Code](https://letta.com)

Co-authored-by: letta-code <248085862+letta-code@users.noreply.github.com>
Co-authored-by: Letta <noreply@letta.com>
Co-authored-by: datadog-official[bot] <datadog-official[bot]@users.noreply.github.com>
Co-authored-by: Kian Jones <11655409+kianjones9@users.noreply.github.com>
This commit is contained in:
github-actions[bot]
2026-01-13 17:11:44 -08:00
committed by Sarah Wooders
parent f67af1b13d
commit a5108c96b4
2 changed files with 13 additions and 6 deletions

View File

@@ -81,10 +81,11 @@ class AsyncBaseMCPClient:
try:
result = await self.session.call_tool(tool_name, tool_args)
except Exception as e:
if e.__class__.__name__ == "McpError":
# MCP errors are typically user-facing issues from external MCP servers
# (e.g., resource not found, invalid arguments, permission errors)
# Log at debug level to avoid triggering production alerts for expected failures
# ToolError is raised by fastmcp for input validation errors (e.g., missing required properties)
# McpError is raised for other MCP-related errors
# Both are expected user-facing issues from external MCP servers
# Log at debug level to avoid triggering production alerts for expected failures
if e.__class__.__name__ in ("McpError", "ToolError"):
logger.debug(f"MCP tool '{tool_name}' execution failed: {str(e)}")
raise

View File

@@ -128,7 +128,10 @@ class AsyncFastMCPSSEClient:
try:
result = await self.client.call_tool(tool_name, tool_args)
except Exception as e:
if e.__class__.__name__ == "McpError":
# ToolError is raised by fastmcp for input validation errors (e.g., missing required properties)
# McpError is raised for other MCP-related errors
# Both are expected user-facing errors from MCP tools, log at warning level
if e.__class__.__name__ in ("McpError", "ToolError"):
logger.warning(f"MCP tool '{tool_name}' execution failed: {str(e)}")
raise
@@ -270,7 +273,10 @@ class AsyncFastMCPStreamableHTTPClient:
try:
result = await self.client.call_tool(tool_name, tool_args)
except Exception as e:
if e.__class__.__name__ == "McpError":
# ToolError is raised by fastmcp for input validation errors (e.g., missing required properties)
# McpError is raised for other MCP-related errors
# Both are expected user-facing errors from MCP tools, log at warning level
if e.__class__.__name__ in ("McpError", "ToolError"):
logger.warning(f"MCP tool '{tool_name}' execution failed: {str(e)}")
raise