Skip to content

[Gateway] Validate MCP headers and deterministic private catalogs - #385

Merged
mohanagy merged 2 commits into
developmentfrom
feat/365-header-cache
Aug 11, 2026
Merged

[Gateway] Validate MCP headers and deterministic private catalogs#385
mohanagy merged 2 commits into
developmentfrom
feat/365-header-cache

Conversation

@mohanagy

@mohanagy mohanagy commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Closes #365

What changed

  • Keep the MCP SDK v2 validation boundary for required Mcp-Method and operation-specific Mcp-Name mirrors, with regression coverage for missing, duplicated, mismatched, malformed encoded, and valid encoded values before upstream execution.
  • Decline unsupported Mcp-Param-* forwarding safely: modern HTTP strips x-mcp-header schema declarations, rejects received parameter headers with a fixed non-reflective HTTP 400 JSON-RPC response, and never sends the header name or value to routing, policy, audit, diagnostics, or an upstream.
  • Declare every modern cacheable result private and immediately stale with ttlMs: 0, while leaving legacy result shapes unchanged.
  • Canonically order resources, resource templates, and prompts, and replace per-instance random template routes with stable SHA-256 identifiers derived only from already-redacted catalog-visible values.
  • Document the modern HTTP header, cache, compatibility, and security boundary.

Why

Miftah uses the SDK's low-level Server, so the SDK cannot validate schema-declared parameter headers for proxied tools. Rejecting that optional extension is safer than allowing an intermediary to authorize one argument view while Miftah executes another. A positive TTL is also not truthful until catalog caches can be keyed by authenticated principal, profile, policy, upstream capability, and configuration revision. Private zero-TTL results provide immediate invalidation and no cross-principal sharing.

Compatibility

  • Modern Streamable HTTP keeps request-scoped serving and gains the strict header boundary.
  • Legacy initialized HTTP retains its session path and does not receive modern cache fields.
  • Modern and legacy STDIO retain their existing argument transport; modern STDIO receives the standard cache metadata, while legacy STDIO does not.

Validation

Summary by CodeRabbit

  • New Features

    • Added stricter validation for modern request headers, rejecting missing, malformed, duplicate, or mismatched values.
    • Added rejection for unsupported Mcp-Param-* headers with clear HTTP 400 errors.
    • Modern catalogs now remove parameter-header annotations when applicable.
    • Added private, immediately stale caching for modern discovery and resource responses.
    • Resource, template, and prompt listings now use deterministic ordering and stable routing identifiers.
  • Documentation

    • Updated configuration, API, security, and changelog documentation to describe the new validation, caching, and catalog behavior.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d435dcb4-0b37-4368-b213-bc8ae5a3b47e

📥 Commits

Reviewing files that changed from the base of the PR and between 4c55284 and 81f700b.

📒 Files selected for processing (1)
  • docs/config.md

📝 Walkthrough

Walkthrough

Modern Streamable HTTP requests validate routing headers and reject unsupported parameter headers. Modern catalogs redact parameter annotations, use private zero-TTL cache metadata, and return deterministic entries and template routes. Legacy and STDIO behavior remain unchanged.

Changes

Modern MCP gateway contracts

Layer / File(s) Summary
Modern request validation and runtime wiring
src/http/miftah-http-server.ts, src/runtime/create-miftah-runtime.ts
Modern requests reject Mcp-Param-* headers with HTTP 400 and error code -32020. Request-scoped servers enable annotation stripping.
Catalog redaction and cache metadata
src/mcp/server/miftah-server.ts
tools/list can recursively remove x-mcp-header annotations. Modern discovery and resource responses declare private ttlMs: 0 cache hints.
Deterministic catalog routing
src/mcp/server/resource-prompt-registry.ts, src/mcp/server/miftah-server.ts
Resource, resource-template, and prompt listings use stable ordering. Template routes use deterministic SHA-256-based identifiers.
Compatibility tests and protocol documentation
tests/mcp-v2-serving.test.ts, tests/resource-prompt-registry.test.ts, tests/helpers/fake-remote-upstream.ts, docs/*, CHANGELOG.md
Tests cover header validation, cache metadata, parameter-header isolation, encoded names, and catalog ordering. Documentation records the modern contracts and transport compatibility.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ModernClient
  participant miftahHttpServer
  participant createMiftahRuntime
  participant MiftahServer
  participant RemoteUpstream
  ModernClient->>miftahHttpServer: Send MCP request with routing headers
  miftahHttpServer->>miftahHttpServer: Validate headers and reject Mcp-Param-* headers
  miftahHttpServer->>createMiftahRuntime: Pass valid request metadata
  createMiftahRuntime->>MiftahServer: Create modern request-scoped server
  MiftahServer->>RemoteUpstream: Execute validated MCP operation
  RemoteUpstream-->>MiftahServer: Return operation result
  MiftahServer-->>ModernClient: Return result with private zero-TTL metadata
Loading

Possibly related PRs

  • mohanagy/miftah#381 — Both changes modify modern Streamable HTTP handling and MiftahServer protocol behavior.
  • mohanagy/miftah#48 — Both changes extend resource and prompt catalog aggregation and routing.
  • mohanagy/miftah#70 — Both changes modify MiftahServer, ResourcePromptRegistry, and MCP HTTP catalog behavior.

Suggested labels: documentation, area:mcp

Poem

I’m a rabbit guarding headers tight,
Sorting catalogs left to right.
Zero-TTL caches softly sleep,
Hidden parameters cannot creep.
Stable routes hop into view—
Modern MCP is fresh and true!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the gateway header validation and deterministic private catalog changes.
Description check ✅ Passed The description covers the change, security rationale, compatibility, and validation commands, although it uses different headings from the template.
Linked Issues check ✅ Passed The changes address validated headers, rejected parameter forwarding, private zero-TTL caching, deterministic catalogs, compatibility, documentation, and contract tests for issue #365.
Out of Scope Changes check ✅ Passed The code, tests, documentation, changelog, and validation updates are directly related to issue #365 objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/365-header-cache

Comment @coderabbitai help to get the list of available commands.

@mohanagy
mohanagy marked this pull request as ready for review August 11, 2026 17:03
@coderabbitai coderabbitai Bot added area:mcp MCP protocol server and proxy behavior documentation Improvements or additions to documentation labels Aug 11, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/config.md`:
- Line 131: Update the cache behavior description in docs/config.md to state
that resource-template route identifiers are derived deterministically from the
upstream name, exposed name, and redacted catalog-visible URI template, rather
than only the upstream and original template. Preserve the existing
no-sensitive-input guarantee and surrounding cache semantics.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4e1ba110-ab03-4268-b10f-976f5cf0188f

📥 Commits

Reviewing files that changed from the base of the PR and between d3d61d9 and 4c55284.

📒 Files selected for processing (11)
  • CHANGELOG.md
  • docs/config.md
  • docs/library-api.md
  • docs/security.md
  • src/http/miftah-http-server.ts
  • src/mcp/server/miftah-server.ts
  • src/mcp/server/resource-prompt-registry.ts
  • src/runtime/create-miftah-runtime.ts
  • tests/helpers/fake-remote-upstream.ts
  • tests/mcp-v2-serving.test.ts
  • tests/resource-prompt-registry.test.ts

Comment thread docs/config.md Outdated
@mohanagy
mohanagy merged commit 6efa9c7 into development Aug 11, 2026
12 checks passed
@mohanagy
mohanagy deleted the feat/365-header-cache branch August 11, 2026 17:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:mcp MCP protocol server and proxy behavior documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Gateway] Add validated MCP header routing and cacheable catalog semantics

1 participant