Summary
Validate tool input schemas themselves — not just arguments against them — when catalogs are ingested from external sources, and bound schema complexity (depth, size) before running jsonschema validation. Cache compiled validators per tool.
Why this matters
The gateway validates LLM-supplied arguments against schemas that arrive from upstream servers, but a malformed or pathologically nested schema currently flows through unchecked until validation time. Checking schema well-formedness at ingest gives catalog authors early, actionable errors; complexity bounds keep validation costs predictable on untrusted inputs; validator caching removes repeated compilation from the hot execute path.
Current evidence
src/contextweaver/adapters/mcp.py (~lines 131–136): inputSchema / outputSchema from upstream tools/list are stored verbatim on the SelectableItem with no checks.
src/contextweaver/adapters/proxy_runtime.py lines 572–583: _validate_args calls jsonschema.validate(instance=args, schema=schema) per execution — schema is assumed well-formed, no check_schema, no depth/size guard, and a fresh validation each call.
docs/gateway_spec.md §4.4 mandates argument validation but does not address schema trust or complexity.
Proposed implementation
- At catalog ingest (and
hydrate_with_schema in routing/hydration.py), run jsonschema.validators.validator_for(schema).check_schema(schema); surface failures as a structured normalization/catalog error rather than at execution time.
- Add conservative complexity bounds (configurable): max serialized size (e.g. 64 KB), max nesting depth (e.g. 32), max property count. Reject or flag schemas beyond bounds with a clear error.
- Cache compiled validators keyed by canonical
tool_id + hash8 (the existing schema-shape hash in routing/tool_id.py is a natural cache key); invalidate on catalog refresh.
- Map ingest-time schema failures to a distinct
GatewayError code (e.g. SCHEMA_INVALID) and document in the spec.
- Extend
CatalogNormalizer / NormalizationReport (routing/normalizer.py) to report schema-health findings so operators can audit catalogs.
Example prompt, schema, or interface
report = normalizer.normalize(catalog)
# report.schema_findings -> [
# SchemaFinding(tool_id="acme:deploy", kind="not_well_formed", detail="'type': 'strnig'"),
# SchemaFinding(tool_id="acme:query", kind="depth_exceeded", detail="depth 41 > 32"),
# ]
Acceptance criteria
- Malformed schemas are detected at ingest with tool-level diagnostics, not at first execution.
- Schemas exceeding configured complexity bounds are rejected or flagged per configuration.
- Repeated
tool_execute calls for the same tool reuse a cached validator (verifiable via a counter in tests).
make ci passes; spec documents the new behavior and error code.
Test and evaluation plan
- Unit tests: well-formed, malformed, oversized, and deeply nested schema fixtures.
- Performance check: validator caching measurably reduces repeated-validation time in the gateway benchmark (
benchmarks/gateway_benchmark.py).
- Regression: existing real-catalog snapshots (
tests/test_architectures_mcp_context_gateway_real.py) still load cleanly.
Migration notes
Catalogs containing malformed schemas that previously loaded silently will now produce diagnostics; default to flag-and-continue with strict mode opt-in to avoid breaking existing deployments.
Risks and tradeoffs
Bounds that are too tight could reject legitimate large schemas (some enterprise APIs are huge) — limits must be configurable and defaults generous. Caching adds invalidation complexity tied to catalog refresh (coordinate with #424).
Suggested labels
security, reliability, area/gateway
Summary
Validate tool input schemas themselves — not just arguments against them — when catalogs are ingested from external sources, and bound schema complexity (depth, size) before running
jsonschemavalidation. Cache compiled validators per tool.Why this matters
The gateway validates LLM-supplied arguments against schemas that arrive from upstream servers, but a malformed or pathologically nested schema currently flows through unchecked until validation time. Checking schema well-formedness at ingest gives catalog authors early, actionable errors; complexity bounds keep validation costs predictable on untrusted inputs; validator caching removes repeated compilation from the hot execute path.
Current evidence
src/contextweaver/adapters/mcp.py(~lines 131–136):inputSchema/outputSchemafrom upstreamtools/listare stored verbatim on theSelectableItemwith no checks.src/contextweaver/adapters/proxy_runtime.pylines 572–583:_validate_argscallsjsonschema.validate(instance=args, schema=schema)per execution — schema is assumed well-formed, nocheck_schema, no depth/size guard, and a fresh validation each call.docs/gateway_spec.md§4.4 mandates argument validation but does not address schema trust or complexity.Proposed implementation
hydrate_with_schemainrouting/hydration.py), runjsonschema.validators.validator_for(schema).check_schema(schema); surface failures as a structured normalization/catalog error rather than at execution time.tool_id+hash8(the existing schema-shape hash inrouting/tool_id.pyis a natural cache key); invalidate on catalog refresh.GatewayErrorcode (e.g.SCHEMA_INVALID) and document in the spec.CatalogNormalizer/NormalizationReport(routing/normalizer.py) to report schema-health findings so operators can audit catalogs.Example prompt, schema, or interface
Acceptance criteria
tool_executecalls for the same tool reuse a cached validator (verifiable via a counter in tests).make cipasses; spec documents the new behavior and error code.Test and evaluation plan
benchmarks/gateway_benchmark.py).tests/test_architectures_mcp_context_gateway_real.py) still load cleanly.Migration notes
Catalogs containing malformed schemas that previously loaded silently will now produce diagnostics; default to flag-and-continue with strict mode opt-in to avoid breaking existing deployments.
Risks and tradeoffs
Bounds that are too tight could reject legitimate large schemas (some enterprise APIs are huge) — limits must be configurable and defaults generous. Caching adds invalidation complexity tied to catalog refresh (coordinate with #424).
Suggested labels
security, reliability, area/gateway