Skip to content

feat(policy): add MCP-aware JSON-RPC L7 governance#1938

Merged
krishicks merged 1 commit into
NVIDIA:hicks/push-nvuozlywzuwufrom
ddurst-nvidia:dev/ddurst/mcp-tower-types-variant-3
Jun 25, 2026
Merged

feat(policy): add MCP-aware JSON-RPC L7 governance#1938
krishicks merged 1 commit into
NVIDIA:hicks/push-nvuozlywzuwufrom
ddurst-nvidia:dev/ddurst/mcp-tower-types-variant-3

Conversation

@ddurst-nvidia

@ddurst-nvidia ddurst-nvidia commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Builds on #1865 by keeping its shared JSON-RPC-family L7 enforcement foundation and adding an MCP-specific policy surface on top of it.

PR #1865 introduces generic JSON-RPC method/params enforcement. This variant preserves generic JSON-RPC as a first-class supported protocol for non-MCP services, while adding MCP-specific policy syntax, MCP request validation via tower-mcp-types, MCP tool-name enforcement, and conformance-oriented e2e coverage.

Related Issue

Addresses #1793.

Builds on #1865.

Changes

Relationship to #1865

PR #1865 adds the shared JSON-RPC-family L7 enforcement layer. This branch builds on that layer with an MCP-specific policy surface and MCP message validation via tower-mcp-types, while preserving generic JSON-RPC as a first-class supported protocol for non-MCP services.

How This Addresses #1793

Issue #1793 asks for method-level governance for MCP tool calls because MCP traffic is carried as JSON-RPC over a single allowed connection, making network-only policy all-or-nothing.

This branch addresses that by allowing policy to distinguish MCP requests inside the connection:

  • protocol: mcp selects MCP-aware JSON-RPC inspection.
  • method can match MCP method names such as initialize, tools/list, and tools/call when authors want explicit method rules.
  • tool is a convenience matcher for tools/call params.name.
  • deny_rules can block specific MCP calls even when broader allow rules match.
  • Allow and deny rules are evaluated before forwarding to the MCP server.
  • MCP traffic remains in OpenShell's existing policy/audit path instead of requiring an external governance gateway.

MCP Policy Shape

  • Adds MCP endpoint options under mcp:
    • mcp.max_body_bytes
    • mcp.strict_tool_names
    • mcp.allow_all_known_mcp_methods
  • Adds a dedicated McpOptions protobuf message so MCP policy can evolve without taking over generic L7 endpoint fields.
  • Requires protocol: mcp endpoints to declare a concrete host plus port or ports; protocol: mcp alone is invalid and is not treated as MCP everywhere.
  • Defaults mcp.strict_tool_names to true, enforcing the MCP-recommended tool-name pattern ^[A-Za-z0-9_.-]{1,128}$ before policy evaluation.
  • Allows tool glob matchers only while mcp.strict_tool_names remains enabled.
  • Defaults mcp.allow_all_known_mcp_methods to true, so omitted rules allow the MCP method profile and all tools before applying deny_rules.
  • When mcp.allow_all_known_mcp_methods is false, explicit rules are required, and rules using tool or params.name must set method: tools/call.
  • MCP tool argument matching is intentionally not supported yet; allowed tools currently accept all argument payloads.

JSON-RPC / MCP Enforcement

  • Adds JsonRpcInspectionMode so parsing can distinguish generic JSON-RPC from MCP-specific inspection.
  • Uses tower-mcp-types to validate known MCP request and notification parameter shapes.
  • Preserves unknown MCP extension methods as policy-addressable literal method strings.
  • Keeps generic JSON-RPC parsing protocol-neutral for non-MCP JSON-RPC servers.
  • Keeps enforcement on the existing OPA path by compiling MCP policy syntax back to the current JSON-RPC-family rule model.
  • Preserves literal dotted JSON-RPC param keys on the generic JSON-RPC path.
  • Relays MCP response frames and server-to-client MCP messages for current conformance compatibility; those frames are not currently parsed for policy enforcement.

Conformance Notes

The MCP conformance policy template now uses:

protocol: mcp
mcp:
  max_body_bytes: 131072
rules:
  - allow: {}

Expected-failure carve-outs are empty:

client: []
server: []

Note

The wrapper still carries a temporary workaround for modelcontextprotocol/conformance#345 while pinned to an upstream ref where the bundled TypeScript client fixtures drift from the runner scenarios. The wrapper patches the local checkout before building the client image so elicitation-sep1034-client-defaults and sse-retry exercise the intended MCP paths through OpenShell. Remove this workaround when OPENSHELL_MCP_CONFORMANCE_REF points at an upstream release containing that fix.

Follow-up

Typed MCP argument enforcement would be better handled as a wider L7 policy input change, for example by preserving scalar JSON type metadata alongside the existing flattened matcher keys. That would let a future MCP argument policy express type: integer or type: boolean without weakening the existing JSON-RPC compatibility path.

OpenShell should also eventually own explicit MCP version profiles rather than relying on dependency enums as the policy contract. That would let policy choose between the current 2025-11-25 behavior and future MCP transport or method-profile changes.

Testing

  • mise run pre-commit passes
  • Unit tests added/updated
  • E2E tests added/updated

Local validation run for this branch includes:

  • mise run pre-commit
  • cargo test -p openshell-policy
  • cargo test -p openshell-supervisor-network mcp_tool_deny_rule_blocks_tools_call
  • cargo test -p openshell-supervisor-network l7_mcp
  • cargo test --manifest-path e2e/rust/Cargo.toml --test forward_proxy_jsonrpc_l7 --features e2e-host-gateway --no-run
  • OPENSHELL_DOCKER_SUPERVISOR_BIN=deploy/docker/.build/prebuilt-binaries/amd64/openshell-sandbox mise run e2e:mcp
    • Passed: initialize, tools_call, elicitation-sep1034-client-defaults, sse-retry
    • Failed: none

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • Architecture docs updated (if applicable)

@ddurst-nvidia

Copy link
Copy Markdown
Contributor Author

@krishicks - Mostly for your review.

@ddurst-nvidia ddurst-nvidia force-pushed the dev/ddurst/mcp-tower-types-variant-3 branch from a432508 to 8c9606b Compare June 16, 2026 23:27
@ddurst-nvidia

Copy link
Copy Markdown
Contributor Author

I don't have permissions to add the test:e2e label, but it would be appreciated if someone could add it.

Comment thread docs/reference/policy-schema.mdx Outdated
Comment thread docs/reference/policy-schema.mdx Outdated
Comment thread docs/reference/policy-schema.mdx Outdated
@copy-pr-bot

copy-pr-bot Bot commented Jun 18, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@ddurst-nvidia

Copy link
Copy Markdown
Contributor Author

Cleaned up the conformance fixture workarounds to align with modelcontextprotocol/conformance#346.

@krishicks krishicks force-pushed the hicks/push-nvuozlywzuwu branch 2 times, most recently from 0e4d7af to fb9c396 Compare June 22, 2026 22:36
@johntmyers johntmyers added the test:e2e Requires end-to-end coverage label Jun 22, 2026
@github-actions

Copy link
Copy Markdown

Label test:e2e applied, but pull-request/1938 is at 8c9606b while the PR head is da2a2fd. A maintainer needs to comment /ok to test da2a2fdf72847a17ed8dc7e2e1ab4eac5375aaef to refresh the mirror. Once the mirror catches up, re-run Branch E2E Checks from the Actions tab.

@krishicks krishicks force-pushed the hicks/push-nvuozlywzuwu branch 2 times, most recently from fd2621a to 0f54c83 Compare June 23, 2026 16:08
@ddurst-nvidia ddurst-nvidia force-pushed the dev/ddurst/mcp-tower-types-variant-3 branch from da2a2fd to 1d8d4af Compare June 23, 2026 17:03
@krishicks krishicks force-pushed the hicks/push-nvuozlywzuwu branch 2 times, most recently from e3a525e to 91dac00 Compare June 23, 2026 17:48
@johntmyers johntmyers added this to the OpenShell Beta milestone Jun 23, 2026
@ddurst-nvidia ddurst-nvidia force-pushed the dev/ddurst/mcp-tower-types-variant-3 branch from 1d8d4af to f6d11bc Compare June 23, 2026 19:06
@ddurst-nvidia ddurst-nvidia marked this pull request as draft June 23, 2026 19:08
@copy-pr-bot

copy-pr-bot Bot commented Jun 23, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@ddurst-nvidia ddurst-nvidia force-pushed the dev/ddurst/mcp-tower-types-variant-3 branch 2 times, most recently from eb82ed8 to f1fb164 Compare June 24, 2026 20:34
@ddurst-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test

@ddurst-nvidia ddurst-nvidia force-pushed the dev/ddurst/mcp-tower-types-variant-3 branch from 5469fc6 to e58f9ed Compare June 24, 2026 22:58
@ddurst-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test

@ddurst-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test

3 similar comments
@ddurst-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test

@ddurst-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test

@ddurst-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test

Add MCP-aware JSON-RPC inspection using tower-mcp-types, including strict tool-name enforcement and method/tool policy matching.

Wire MCP options through proto, YAML, provider profiles, OPA/Rego policy evaluation, docs, and the MCP conformance harness.

Signed-off-by: ddurst <267424412+ddurst-nvidia@users.noreply.github.com>
@ddurst-nvidia ddurst-nvidia force-pushed the dev/ddurst/mcp-tower-types-variant-3 branch from 4a26fbb to fa115e4 Compare June 25, 2026 19:37
@ddurst-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test

@ddurst-nvidia ddurst-nvidia marked this pull request as ready for review June 25, 2026 20:16
@krishicks krishicks merged commit a5321b7 into NVIDIA:hicks/push-nvuozlywzuwu Jun 25, 2026
47 checks passed
krishicks pushed a commit that referenced this pull request Jun 26, 2026
Add MCP-aware JSON-RPC inspection using tower-mcp-types, including strict tool-name enforcement and method/tool policy matching.

Wire MCP options through proto, YAML, provider profiles, OPA/Rego policy evaluation, docs, and the MCP conformance harness.

Signed-off-by: ddurst <267424412+ddurst-nvidia@users.noreply.github.com>
fix(e2e): use supervisor image in docker gateway runner

Signed-off-by: Kris Hicks <khicks@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test:e2e Requires end-to-end coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants