- 
                Notifications
    You must be signed in to change notification settings 
- Fork 1.4k
feat: add optional strictInputSchemaValidation parameter to registerTool for Zod validation #846
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: add optional strictInputSchemaValidation parameter to registerTool for Zod validation #846
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @abloomston !
        
          
                README.md
              
                Outdated
          
        
      | strict: true // Reject { username: "test", itemcount: 42 } | ||
| }, handler); | ||
|  | ||
| // Lenient validation for production - handles client variations gracefully | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure about advising leniency in prod tbh, or maybe explain why (e.g. to allow some kind of forward compatibility maybe, although I'm struggling to imagine a valid use case)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ochafik I did this to maintain backwards compatibility for users of this sdk. Let me know which (or another) you'd like me to do:
- Revise this comment, maintaining backwards compatibility
- Do not maintain backwards compatibility, making strict the default
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will revise this comment, maintaining backwards compatibility
        
          
                src/server/mcp.ts
              
                Outdated
          
        
      | inputSchema: ZodRawShape | undefined, | ||
| outputSchema: ZodRawShape | undefined, | ||
| annotations: ToolAnnotations | undefined, | ||
| strict: boolean | undefined, | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd name this more explicitly, e.g. rejectUnexpectedInputs, given this isn't turning registerTool as fully strict (e.g. I'd expect structuredContent to be checked against outputSchema, and potentially content text to be checked against structuredContent)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ochafik would the variable name strictInputSchemaValidation work for you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will proceed with the variable name strictInputSchemaValidation
0845a57    to
    c94ba4b      
    Compare
  
    This test demonstrates the current issue where tools accept unknown parameters (e.g. incorrect capitalization) without validation errors. The test uses 'username' and 'itemcount' instead of the expected 'userName' and 'itemCount' parameters, which should be rejected but currently aren't. This test is expected to fail until strict validation is implemented.
Add strict parameter to registerTool config that defaults to false for backward compatibility. When strict=true, applies .strict() to Zod schema creation for tool input validation to throw errors on unknown parameters instead of silently ignoring them. - Add strict?: boolean to registerTool config interface - Modify _createRegisteredTool to accept and use strict parameter - Apply z.object(inputSchema).strict() when strict=true - Update legacy tool() method to pass strict=false (backward compatibility) - Update test to verify strict validation rejects unknown parameters - All existing tests continue to pass (no breaking changes) This fixes the issue where parameter name typos are silently dropped, leading to confusing behavior where tools execute with missing data.
Add Advanced Usage section explaining the strict parameter for registerTool: - Show examples of strict vs lenient validation - Explain when to use each mode (development vs production) - Document that strict parameter is only available in registerTool() - Note that legacy tool() method uses lenient validation for compatibility This helps developers understand when and how to use strict validation to catch parameter name typos and unexpected data.
1753939    to
    57dacc4      
    Compare
  
    Revised comment to explain that lenient validation (strict=false) maintains backwards compatibility with existing clients rather than advising leniency for production. The updated comment clarifies that extra parameters are accepted to support clients that may send additional fields. Changes linted and tested. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Renamed parameter from `strict` to `strictInputSchemaValidation` for clarity. The longer name makes it more explicit that this validation applies specifically to the input schema and helps distinguish it from other types of strictness. Updated: - src/server/mcp.ts: Parameter in registerTool config and _createRegisteredTool signature - src/server/mcp.test.ts: Test using the renamed parameter - README.md: Documentation examples and notes Changes linted and tested. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Changed test from expecting failure to properly testing that lenient validation (default behavior) accepts unknown parameters for backwards compatibility. Renamed test from "should fail..." to "should accept unknown parameters when strict validation is disabled (default)" to clarify it's testing the expected lenient behavior. This ensures all tests pass while documenting both validation modes: - Lenient (default): accepts unknown parameters - Strict: rejects unknown parameters Changes linted and tested - all 756 tests now pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Applied prettier auto-formatting to README.md and src/server/mcp.ts to fix code style issues. Changes linted and tested. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Renamed example from prod-tool to lenient-tool to better reflect that lenient validation is about backwards compatibility rather than being specifically for production environments. Changes linted and tested. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
| @ochafik I took a pass at changes based on what I expect you to have wanted, please take a look. Thanks! | 
| Hi @ochafik wondering if I can get your 👀 on this PR? Looking to close this task out on my end :) Thanks! | 
…esponses When strictInputSchemaValidation is enabled, validation errors now properly throw (reject the request) instead of being caught and returned as error responses with isError: true. Changes: - Add strictInputSchemaValidation field to RegisteredTool type - Store strictInputSchemaValidation flag when creating tools - Modify error handling to rethrow validation errors when strict mode enabled This ensures tools with strict validation fail fast on invalid input, maintaining backwards compatibility for tools without strict validation where errors are returned as error responses. Changes linted and tested. <em>🤖 Created with Claude Code via Airchat</em>
…col#1044 pattern Change strict validation errors to return CallToolResult with isError: true instead of throwing protocol-level errors, aligning with the pattern established in PR modelcontextprotocol#1044 (commit 7387c44) where all validation errors return error responses rather than throwing. This ensures consistent error handling across all validation scenarios and enables LLMs to see validation errors and attempt self-correction, as specified in the MCP protocol specification. Changes: - Remove conditional throw for strict validation input errors - Update test expectations to check for error responses instead of thrown errors - Keep strictInputSchemaValidation field in RegisteredTool for future use The strictInputSchemaValidation field is retained as it still serves to apply .strict() to the Zod schema, rejecting unknown parameters. The difference is now the rejection returns an error response visible to LLMs rather than a protocol-level error. Changes linted and tested. <em>🤖 Created with Claude Code via Airchat</em>
| Update: Aligned Error Handling with PR #1044I've updated this PR to align with the error handling pattern established in PR #1044 (commit 7387c44), which was merged to main on October 28, 2025. What ChangedBefore: The original implementation had strict validation errors throw protocol-level  After: Strict validation errors now return  Why This ChangePR #1044 established a uniform pattern where all validation errors (tool not found, disabled tools, input validation, output validation) return error responses rather than throwing protocol-level errors. This follows the MCP specification guidance: 
 Impact
 Commits
 The feature still provides the same value (catching parameter typos, preventing unexpected data) while maintaining consistency with the SDK's error handling approach. | 
Add optional
strictInputSchemaValidationparameter toregisterTool()config that enables Zod's strict validation to reject unknown parameters instead of silently ignoring them.Motivation and Context
The MCP TypeScript SDK currently silently ignores unknown parameters in tool calls, which causes issues where parameter name typos are silently dropped, leading to confusing behavior where tools execute with missing data.
How Has This Been Tested?
Breaking Changes
None. The
strictInputSchemaValidationparameter defaults tofalsefor backward compatibility. Existing code will continue to work unchanged.Types of changes
Checklist
Additional context
You should consider this PR in concert with #792 which makes changes that may be related.
Implementation Details:
strictInputSchemaValidation?: booleantoregisterToolconfig interfacestrictInputSchemaValidation: true, appliesz.object(inputSchema).strict()to reject unknown parametersstrictInputSchemaValidation: false(default), maintains current lenient behaviorregisterTool()method - legacytool()method uses lenient validation for compatibilityError Handling:
CallToolResultwithisError: trueUse Cases:
The feature follows existing patterns in the codebase and maintains full backward compatibility while solving a real pain point for developers.
LLM Disclosure
This PR was created with the assistance of Claude Code, Claude Haiku 3.5, Claude Sonnet 4.0, Claude Haiku 4.5, Claude Sonnet 4.5, and Chat-GPT 4.1 nano.