Skip to content

Add tool parameter validation to MCP binding#1877

Draft
jfallows wants to merge 13 commits into
developfrom
claude/magical-hopper-ox3k4c
Draft

Add tool parameter validation to MCP binding#1877
jfallows wants to merge 13 commits into
developfrom
claude/magical-hopper-ox3k4c

Conversation

@jfallows

Copy link
Copy Markdown
Contributor

Description

This PR adds JSON schema validation for tool call parameters in the MCP binding. When tools are configured with a model and catalog, their input parameters are now validated against the schema before being forwarded to the application.

Changes

Core Validation Logic:

  • Modified McpServerFactory to pass binding configuration to McpServer instances
  • Added parameter buffering and validation in McpRequestStream via new bufferArgs() and validateArgs() methods
  • Tool schemas are now registered with the catalog when tools are listed, and unregistered when the tools list changes
  • Invalid parameters trigger a JSON-RPC error response (code -32602, "Invalid params") with HTTP 400 status

Configuration & Integration:

  • Extended McpBindingConfig to support optional tools model configuration with catalog references
  • Added validatesTools(), registerToolSchema(), resolveToolValidator(), and unregisterToolSchema() methods to manage tool validation
  • Updated McpOptionsConfig and related adapters to support the new tools model configuration
  • Added dependency on model-json runtime module

Catalog Improvements:

  • Enhanced InlineCatalogHandler with runtime registration/unregistration via register() and unregister() methods
  • Implemented reference counting to properly manage shared schemas across multiple subjects
  • Added unit tests for the catalog handler's registration and lifecycle management

Test Coverage:

  • Added integration tests for valid and invalid tool call parameters
  • Added test specifications for both network and application streams
  • New configuration file server.validation.yaml demonstrates tools validation setup

Test Plan

Existing and new integration tests verify:

  • Valid tool parameters are accepted and forwarded to the application
  • Invalid tool parameters are rejected with appropriate JSON-RPC error responses
  • Tool schemas are properly registered and unregistered during the session lifecycle
  • Catalog reference counting works correctly for shared schemas

https://claude.ai/code/session_015SCFtykHvSyqMSqe5VCBYo

claude added 13 commits June 12, 2026 21:52
…ptions.tools

Make InlineCatalogHandler mutable at runtime (content-addressed CRC32C,
refcounted) so the mcp server can register tool inputSchemas captured from
tools/list responses. Add McpOptionsConfig.tools ModelConfig surfaced through
OptionsConfig.models for catalog id resolution.

Refs #1876

https://claude.ai/code/session_015SCFtykHvSyqMSqe5VCBYo
Add 'tool' to the model-json validator strategy enum, add the
options.tools validator ref to the mcp binding schema, and add
server.validation.yaml IT config wiring an inline catalog with
strategy: tool (#1876).

https://claude.ai/code/session_015SCFtykHvSyqMSqe5VCBYo
Resolve the inline tools catalog on McpBindingConfig and add
registerToolSchema/unregisterToolSchema/resolveToolValidator with a
worker-level Int2ObjectHashMap<ValidatorHandler> cache keyed by
content-addressed schema id. Add model-json dependency (#1876).

https://claude.ai/code/session_015SCFtykHvSyqMSqe5VCBYo
…call args

McpServerFactory now captures each advertised inputSchema from the
tools/list reply (per session, content-addressed into the inline
catalog) and validates tools/call arguments against the tool's schema.
On invalid arguments the server returns JSON-RPC -32602 and never
forwards the payload upstream (app begin is deferred until validation
passes); unknown tools pass through. Schemas are evicted on
notifications/tools/list_changed (#1876).

https://claude.ai/code/session_015SCFtykHvSyqMSqe5VCBYo
…alog

Add network/application .rpt scenarios and McpServerIT methods for
tools/call argument validation (valid pass-through, invalid -> -32602).
Fix InlineCatalogHandler to accept a null/absent options block so an
inline catalog can be populated purely at runtime (was NPEing on
config.subjects); add regression unit test. Make doEncodeResponseError
emit well-formed JSON. Add catalog-inline test dependency for the IT.

ITs not yet executed to green: the container's k3po control backend
fails to start after a restart (reproduced on unrelated binding-http
ITs), so engine+k3po integration tests cannot run in this environment;
engine config load and unit tests verified.

https://claude.ai/code/session_015SCFtykHvSyqMSqe5VCBYo
…t request end

Validate tools/call arguments when the request body completes (onNetEnd),
not mid-decode, so the rejected request stream is already registered and
cleanly removed, and the error reply is encoded at the half-duplex reply
point. Fix doEncodeResponseError to mark the reply closing and defer the
END until any buffered body flushes (previously doNetEnd discarded the
buffered JSON-RPC error before the client could read it). Guard
flushAppWindow against a deferred request stream whose app side was never
begun. McpServerIT shouldAcceptToolsCallWithValidInput and
shouldRejectToolsCallWithInvalidInput both pass via failsafe verify.

https://claude.ai/code/session_015SCFtykHvSyqMSqe5VCBYo
…alidation

Add the network server and application client peer scripts and the
paired NetworkIT/ApplicationIT methods for tools.call.valid.input and
tools.call.invalid.input, per specs/AGENTS.md (every scenario needs both
a binding IT and a peer-to-peer NetworkIT/ApplicationIT method). All four
peer tests pass.

https://claude.ai/code/session_015SCFtykHvSyqMSqe5VCBYo
A tools/call for a tool with no captured schema (here, called before any
tools/list) is forwarded unvalidated under server.validation.yaml,
exercising the best-effort path. Adds network + application peer scripts
and McpServerIT/NetworkIT/ApplicationIT methods. All pass.

https://claude.ai/code/session_015SCFtykHvSyqMSqe5VCBYo
Re-listing with a changed inputSchema recaptures the tool schema; a
subsequent tools/call is validated against the new schema (args valid
under v2 but not v1 are accepted). Adds network + application peer
scripts and McpServerIT/NetworkIT/ApplicationIT methods. All pass.

https://claude.ai/code/session_015SCFtykHvSyqMSqe5VCBYo
…n end

Schema catalog references were only released on tools/list_changed, so
tools dropped from a subsequent tools/list and schemas held by a session
that ended without a list_changed were never unregistered (refcount
leak, bounded only by distinct schema content). Treat each tools/list as
the authoritative full set: evict the session's prior schemas before
recapturing, and evict on both session teardown paths (inactivity and
app close). Add tools.list.drop scenario (network+application peers +
McpServerIT/NetworkIT/ApplicationIT) asserting a tool dropped from a
re-list is no longer validated (call passes through instead of -32602).

https://claude.ai/code/session_015SCFtykHvSyqMSqe5VCBYo
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.

2 participants