Skip to content

SEP-1303: Input validation errors should return Tool Execution Errors, not Protocol Errors #1956

@sejano77

Description

@sejano77

Summary

SDK v1.29.0 still throws McpError(ErrorCode.InvalidParams, ...) when tool input validation fails, which conflicts with SEP-1303 (merged into spec 2025-11-25).

Per the 2025-11-25 changelog:

Clarify that input validation errors should be returned as Tool Execution Errors rather than Protocol Errors to enable model self-correction (SEP-1303).

Current SDK behavior prevents the agent model from seeing the error message and self-correcting.

Current Behavior

packages/sdk/src/server/mcp.ts (compiled: dist/esm/server/mcp.js:174-180):

const parseResult = await safeParseAsync(schemaToParse, args);
if (!parseResult.success) {
    const error = 'error' in parseResult ? parseResult.error : 'Unknown error';
    const errorMessage = getParseErrorMessage(error);
    throw new McpError(
      ErrorCode.InvalidParams,
      `Input validation error: Invalid arguments for tool ${toolName}: ${errorMessage}`
    );
}

Result to the client: JSON-RPC error -32602 InvalidParams (Protocol Error).

Expected Behavior (SEP-1303)

Return a successful CallToolResult with isError: true and the validation message in content:

{
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Input validation error for tool X: <Zod message>"
      }
    ],
    "isError": true
  }
}

This lets the model see the error and retry with corrected arguments — exactly the motivation behind SEP-1303.

Scope

Only input validation should switch. Keep Protocol Errors for:

  • Unknown tool (-32602) — already correct, and SDK 2.0.0-alpha.1 reinforced this for unknown tools
  • Disabled tool — correct
  • Structural JSON-RPC errors — correct

Impact

Any server built on this SDK is non-compliant with spec 2025-11-25 for this specific clause. MCPWebStore (Trusteed) hit this during a 2025-11-25 alignment audit — no workaround exists short of patching the SDK or wrapping every registerTool call with permissive input schemas and manual Zod validation inside the handler.

Suggested Fix

Transform the throw into a structured CallToolResult:

if (!parseResult.success) {
    const errorMessage = getParseErrorMessage(
      'error' in parseResult ? parseResult.error : 'Unknown error'
    );
    return {
        content: [{
            type: 'text',
            text: `Input validation error for tool ${toolName}: ${errorMessage}`
        }],
        isError: true,
    };
}

Same for the symmetric output validation check at line ~201 — though SEP-1303 language targets input validation primarily; output validation may warrant a separate decision.

References

Happy to open a PR if maintainers confirm the direction.

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