docs(054): MCP security gateway hardening — umbrella spec (5 tracks)#521
docs(054): MCP security gateway hardening — umbrella spec (5 tracks)#521Dumbris wants to merge 2 commits into
Conversation
…g release.yml job release.yml already has an 'mcp-registry' job that publishes server.json on every tag via keyless GitHub OIDC (continue-on-error) — it has shipped 44 versions to registry.modelcontextprotocol.io. The publish-mcp-registry.yml added in #517 was a redundant duplicate that would have thrown 'cannot publish duplicate version' on every release. Removes it and corrects docs/mcp-registry-publishing.md to reference the existing automation instead of claiming publishing was manual.
Related #N/A Umbrella spec decomposing the 'reference OSS MCP security gateway' roadmap into 5 independently-shippable tracks (output-schema validation, output sanitisation enforcement, per-tool/per-arg capability ACLs, TOFU pinning hardening, EU AI Act Article 12-aligned tamper-evident audit logging), each grounded in a gap analysis against existing features (Specs 026/028/032/035, activity log).
Deploying mcpproxy-docs with
|
| Latest commit: |
2134d99
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://a0cdf4cd.mcpproxy-docs.pages.dev |
| Branch Preview URL: | https://054-mcp-security-gateway.mcpproxy-docs.pages.dev |
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
📦 Build ArtifactsWorkflow Run: View Run Available Artifacts
How to DownloadOption 1: GitHub Web UI (easiest)
Option 2: GitHub CLI gh run download 26351797912 --repo smart-mcp-proxy/mcpproxy-go
|
Related #521 Carve Track A of the Spec 054 security-gateway umbrella into its own feature: validate a tool's structuredContent against its declared outputSchema at the proxy boundary before it reaches the agent. ## Changes - spec.md: FR-A1..A12, 3 prioritized user stories, edge cases, success criteria - plan.md: pure internal/outputvalidation pkg + forwardContentResult hook design - research.md: santhosh-tekuri/jsonschema/v6, capture point, modes, cache decisions - data-model.md, contracts/validator.md, quickstart.md - tasks.md: 24 TDD-first tasks organized by user story
…Track A) Related #521 Validate a tool's structured response against its declared outputSchema at the proxy boundary before it reaches the agent, so a buggy or compromised upstream cannot inject malformed/oversized/unexpected data into the agent's context. Track A of the Spec 054 security-gateway umbrella. - internal/outputvalidation: new pure package — Validator with a per-tool compiled-schema sync.Map cache (santhosh-tekuri/jsonschema/v6), byte-size and nesting-depth guards run before validation, uncompilable schemas degrade to a no-op. Never mutates the payload. - internal/config: OutputValidationConfig (mode off/warn/strict, default warn; max_bytes; max_depth; missing_structured_content) + ToolMetadata.OutputSchemaJSON. - internal/upstream/core/client.go: capture tool.RawOutputSchema/OutputSchema at discovery into ToolMetadata.OutputSchemaJSON (FR-A1). - internal/runtime/{stateview,supervisor}: propagate OutputSchemaJSON onto the in-memory ToolInfo snapshot for cheap call-time lookup. - internal/server: applyOutputValidation wired into both handleCallToolVariant forward sites; pure evaluateOutputValidation decision core; strict blocks with an error result, warn forwards + records a policy_decision audit entry (reuses emitActivityPolicyDecision). No build-tag-specific behaviour. - promote santhosh-tekuri/jsonschema/v6 to a direct dependency. - docs/features/output-schema-validation.md; e2e stub MCP server. Design note: validation runs in mcp.go on forwardContentResult's output (StructuredContent is unaffected by truncation) rather than inside forwardContentResult, keeping that function pure. - Unit: internal/outputvalidation (19 tests, validator + guards, -race); internal/config (8 tests); internal/server output_validation (11 tests covering every decision branch incl. ContextForge #4042 trap, guard breach). - E2E (curl + CLI, fresh data-dir, stub MCP server declaring an outputSchema): strict blocks a violating structuredContent with "at '/id': got string, want integer" + a blocked policy_decision; conforming passes; text-only (no structured) passes under strict+allow; warn mode forwards the violation unchanged + a warning policy_decision. Both editions build.
Related #521 make swagger-verify regenerates oas/ from struct annotations; the new config.OutputValidationConfig model and the output_validation field on the Config schema are now documented.
…Track A) (#525) * docs(056): output-schema-validation spec, plan, tasks (Spec 054 Track A) Related #521 Carve Track A of the Spec 054 security-gateway umbrella into its own feature: validate a tool's structuredContent against its declared outputSchema at the proxy boundary before it reaches the agent. ## Changes - spec.md: FR-A1..A12, 3 prioritized user stories, edge cases, success criteria - plan.md: pure internal/outputvalidation pkg + forwardContentResult hook design - research.md: santhosh-tekuri/jsonschema/v6, capture point, modes, cache decisions - data-model.md, contracts/validator.md, quickstart.md - tasks.md: 24 TDD-first tasks organized by user story * feat(056): output-schema validation for proxied tool calls (Spec 054 Track A) Related #521 Validate a tool's structured response against its declared outputSchema at the proxy boundary before it reaches the agent, so a buggy or compromised upstream cannot inject malformed/oversized/unexpected data into the agent's context. Track A of the Spec 054 security-gateway umbrella. - internal/outputvalidation: new pure package — Validator with a per-tool compiled-schema sync.Map cache (santhosh-tekuri/jsonschema/v6), byte-size and nesting-depth guards run before validation, uncompilable schemas degrade to a no-op. Never mutates the payload. - internal/config: OutputValidationConfig (mode off/warn/strict, default warn; max_bytes; max_depth; missing_structured_content) + ToolMetadata.OutputSchemaJSON. - internal/upstream/core/client.go: capture tool.RawOutputSchema/OutputSchema at discovery into ToolMetadata.OutputSchemaJSON (FR-A1). - internal/runtime/{stateview,supervisor}: propagate OutputSchemaJSON onto the in-memory ToolInfo snapshot for cheap call-time lookup. - internal/server: applyOutputValidation wired into both handleCallToolVariant forward sites; pure evaluateOutputValidation decision core; strict blocks with an error result, warn forwards + records a policy_decision audit entry (reuses emitActivityPolicyDecision). No build-tag-specific behaviour. - promote santhosh-tekuri/jsonschema/v6 to a direct dependency. - docs/features/output-schema-validation.md; e2e stub MCP server. Design note: validation runs in mcp.go on forwardContentResult's output (StructuredContent is unaffected by truncation) rather than inside forwardContentResult, keeping that function pure. - Unit: internal/outputvalidation (19 tests, validator + guards, -race); internal/config (8 tests); internal/server output_validation (11 tests covering every decision branch incl. ContextForge #4042 trap, guard breach). - E2E (curl + CLI, fresh data-dir, stub MCP server declaring an outputSchema): strict blocks a violating structuredContent with "at '/id': got string, want integer" + a blocked policy_decision; conforming passes; text-only (no structured) passes under strict+allow; warn mode forwards the violation unchanged + a warning policy_decision. Both editions build. * docs(056): regenerate OpenAPI spec for output_validation config Related #521 make swagger-verify regenerates oas/ from struct annotations; the new config.OutputValidationConfig model and the output_validation field on the Config schema are now documented.
Make mcpproxy's existing-but-discarded content-trust classification (Spec 035) and secret detector (Spec 026) actually contain untrusted tool output, instead of only logging. All behaviour is fully opt-in; default config forwards every response byte-for-byte. - spotlight: wrap untrusted (open-world) tool text in source-identifying «untrusted:server/tool» delimiters, escaping the sentinel so content cannot forge the wrapper (FR-B1/B2). Applied post-truncation, not cached. - redact: mask detected secrets as [REDACTED:<category>] reusing the Spec 026 detector (FR-B3). - strip: neutralise ANSI / C0-C1 / zero-width / bidi sequences on untrusted text, per-class toggles (FR-B4). - block: replace the payload with a remediation error on a critical detection (FR-B7). Redact/strip/block run on the raw result BEFORE forwardContentResult truncates and caches it, so read_cache never stores an unredacted secret and a blocked response is never cached. Non-text blocks are untouched (FR-B5). Mutating actions emit a policy_decision activity record. New OutputSanitisationConfig mirrors OutputValidationConfig (Track A). Verified end-to-end: curl/MCP roundtrip (spotlight/redact/strip/block + read_cache), API E2E (65/65), and the Web UI activity view. Relates to Spec 054 Track B (#521).
…nt (#535) Make mcpproxy's existing-but-discarded content-trust classification (Spec 035) and secret detector (Spec 026) actually contain untrusted tool output, instead of only logging. All behaviour is fully opt-in; default config forwards every response byte-for-byte. - spotlight: wrap untrusted (open-world) tool text in source-identifying «untrusted:server/tool» delimiters, escaping the sentinel so content cannot forge the wrapper (FR-B1/B2). Applied post-truncation, not cached. - redact: mask detected secrets as [REDACTED:<category>] reusing the Spec 026 detector (FR-B3). - strip: neutralise ANSI / C0-C1 / zero-width / bidi sequences on untrusted text, per-class toggles (FR-B4). - block: replace the payload with a remediation error on a critical detection (FR-B7). Redact/strip/block run on the raw result BEFORE forwardContentResult truncates and caches it, so read_cache never stores an unredacted secret and a blocked response is never cached. Non-text blocks are untouched (FR-B5). Mutating actions emit a policy_decision activity record. New OutputSanitisationConfig mirrors OutputValidationConfig (Track A). Verified end-to-end: curl/MCP roundtrip (spotlight/redact/strip/block + read_cache), API E2E (65/65), and the Web UI activity view. Relates to Spec 054 Track B (#521).
|
Critic (Codex) review — Dumbris's PR #521 |
|
Critic (Codex) review — Dumbris's PR #521 Strengths: The Findings:
Checks: Provenance check: ok |
Umbrella spec to turn mcpproxy into the reference open-source MCP security gateway, decomposed into 5 independently-shippable tracks. Grounded in a subagent gap-analysis against existing features (not greenfield) — the Context section maps each track to the Spec it extends, with file pointers.
content_forward.gohookKey reframe: mcpproxy is already ~70% of a reference security gateway — most tracks close gaps on shipped features. Recommended sequencing A→E by leverage × effort; each track gets its own
/speckit.planwhen implementation starts.Non-goals: no legal compliance certification (alignment/support only), no MCP protocol changes, no mandatory content mutation (sanitisation opt-in), personal edition unaffected by default.
Spec-only; no code. Quality checklist passes (no NEEDS CLARIFICATION). Plan to be run later.