Skip to content

feat: return actionable MCP tool errors instead of bare 4xx/5xx responses #603 - #644

Open
kryachkow wants to merge 6 commits into
developmentfrom
603-mcp-app-return-actionable-mcp-tool-errors-instead-of-bare-4xx5xx-responses
Open

kryachkow wants to merge 6 commits into
developmentfrom
603-mcp-app-return-actionable-mcp-tool-errors-instead-of-bare-4xx5xx-responses

Conversation

@kryachkow

Copy link
Copy Markdown
Contributor

Applicable issues

Description of changes

MCP tool calls previously surfaced whatever exception was raised during execution — bare 4xx/5xx responses, stack traces, upstream bodies, hostnames and trace identifiers — giving the caller neither a clear reason nor a next step, while leaking internal detail.

This PR introduces a small, fixed error taxonomy for MCP tool calls. Each execution error is classified into one of a handful of classes (invalid input, missing authorization, insufficient scope, rate limited, upstream unavailable, result too large, internal error), and each class maps to a single actionable, internals-free message that states what happened, who can fix it, and the concrete next step.

  • statgpt/app/mcp/errors.py (new): the taxonomy itself — exception classification, one message template per class, and the ToolError builders. Full exception detail is logged server-side at a severity matching its class; only the scrubbed template (plus a named invalid field, or a safe-by-design upstream reason) reaches the caller.
  • provider.py: wires the taxonomy into the MCP tool adapter, wrapping both the tool invocation and the response-assembly step so a failure in either cannot leak as a bare error.
  • app.py: enables mask_error_details on the FastMCP app as defense-in-depth, so any error escaping the taxonomy path is still not surfaced verbatim.
  • sdmx_query_app_tool.py and widget_resource.py: scrub the underlying endpoint from upstream connection/fetch errors, keeping it in the server log only.

Rate-limited responses carry a Retry-After hint (from either the upstream headers or DIAL's RateLimitException extra fields) into the caller-visible message.

Checklist

By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.

…nses #603

Translate the heterogeneous exceptions raised while executing a StatGPT
tool into a fixed taxonomy of MCP error classes, each with a single
actionable, internals-free message. Internal detail (stack traces,
upstream bodies, hostnames, trace identifiers) is logged server-side
only and never reaches the caller.

- add statgpt/app/mcp/errors.py: the error taxonomy, exception
  classification, and ToolError builders
- wire the taxonomy into the MCP tool adapter, wrapping both invocation
  and response assembly so neither can leak a bare error
- enable mask_error_details on the FastMCP app as defense-in-depth
- scrub the underlying endpoint from SDMX query and widget-fetch upstream
  errors, keeping it in the server log only
…turn-actionable-mcp-tool-errors-instead-of-bare-4xx5xx-responses

# Conflicts:
#	statgpt/app/mcp/provider.py
#	tests/unit/app/chains/test_sdmx_query_app.py
#	tests/unit/app/mcp/test_provider.py
…turn-actionable-mcp-tool-errors-instead-of-bare-4xx5xx-responses

# Conflicts:
#	statgpt/app/mcp/tools/base.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP app: Return actionable MCP tool errors instead of bare 4xx/5xx responses

1 participant