Skip to content

Input validation errors returned as -32602 instead of isError (SEP-1303) #840

@blackwell-systems

Description

@blackwell-systems

Description

SEP-1303 ("Input Validation Errors as Tool Execution Errors", status: Final) reclassified tool argument validation failures from Protocol Errors to Tool Execution Errors. The previous spec listed "Invalid arguments" under Protocol Errors (-32602); SEP-1303 moves them under Tool Execution Errors (isError: true).

rmcp's #[tool] macro runs serde deserialization before the tool handler. When deserialization fails (missing required field, wrong type, null for non-optional), the SDK returns a JSON-RPC -32602 error. The tool handler never runs, so the server author has no way to intercept or customize the response.

This means models never see the validation error message in their context window. They receive a protocol-level error that MCP clients typically treat as non-recoverable, preventing self-correction.

Observed behavior

Tested with mcp-assert fuzz against an rmcp-based server (eresende/pitlane-mcp, 8 tools):

93 crashes across 8 tools, 240 total runs

Every failure returns:

{"jsonrpc":"2.0","id":1,"error":{"code":-32602,"message":"invalid params: failed to deserialize parameters: missing field `project`"}}

Expected per SEP-1303:

{"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"missing required field: project"}],"isError":true}}

Failure modes affected:

  • Missing required field
  • Wrong type (int for string, string for bool)
  • Null value for required param
  • Empty object

Impact

Every rmcp-based server inherits this behavior. From SEP-1303's motivation:

Models can learn from tool input validation error messages and retry a tools/call with corrected parameters accordingly, but only if they receive the error feedback in their context window. Protocol Errors are caught at the application level by the MCP Client. Only Tool Execution Errors are forwarded back to the model.

References

Reproduce

pip install mcp-assert
mcp-assert fuzz --server "pitlane-mcp" --runs 30

I'm happy to submit a PR for this if the approach is agreed on. The fix would likely involve catching serde deserialization errors in the tool dispatch path and wrapping them in a CallToolResult with isError: true instead of propagating them as JSON-RPC errors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions