Designing an MCP Permission Gateway for Claude Code
The short answer: put MCP policy behind a gateway
An MCP permission gateway gives Claude Code one approved MCP endpoint, then enforces policy before the agent discovers tools and again before it invokes them. In practice, that means the gateway can hide unauthorized tools, resources, and prompts from the model, check each tools/call or resources/read against identity-aware rules, broker scoped downstream credentials, and write audit logs for every decision.
This matters because Claude Code's native MCP permission rules are mostly server and tool-name oriented. Anthropic documents patterns such as mcp__puppeteer and mcp__puppeteer__*. That is useful hygiene, but many teams need policies closer to the resource and argument layer: allow this developer to read GitHub issues in one organization, deny production Kubernetes mutations, allow staging SQL reads only for non-sensitive tables, or block browser automation against unapproved domains.
The gateway pattern does not replace Claude Code permissions, managed settings, or hooks. It gives them a stronger center. Use managed Claude Code settings to constrain which MCP endpoints are allowed. Point developers at the approved gateway. Let the gateway handle resource-level, argument-level, identity-aware enforcement that local settings do not express well.
What breaks when permission decisions are scattered
The failure mode starts quietly. A team adds MCP servers for GitHub, Jira, Postgres, Kubernetes, a browser, and internal services. Developers want Claude Code to work through real tasks, not stop every few minutes for another approval. The prompts become noise. Some users start looking for broader allow rules. Others reach for bypass modes because the work needs to keep moving.
That pressure is visible in the brief's field signals. A Reddit thread asked how to stop Claude Code from asking for permission every time, and responses pointed toward bypass or dangerous modes. GitHub issues #6130 and #6856 reported MCP initialization and detection surprises with --dangerously-skip-permissions, which is a good reminder that bypass modes can create operational friction as well as security risk.
Scattered controls also create blind spots. One developer has a local MCP config. Another has a different set of permissions. CI may run without interactive prompts. A managed allowlist may approve a server, but that same server may expose safe reads, sensitive reads, and destructive writes. If the only control is "GitHub MCP server allowed," then policy has stopped at the door.
Claude Code's own docs draw an important boundary: permission rules are enforced by Claude Code, not by the model. Prompts and project instructions can influence what Claude tries to do, but they do not grant or revoke access. That is the right mental model. Treat the model as a planner and the permission layer as the control plane.
Related reading: Claude Code permissions.
What Claude Code already gives you
Start with the native controls. Anthropic documents permission precedence as deny, then ask, then allow. Deny rules cannot be overridden by allow rules. That gives platform teams a clear baseline for high-risk tools and commands.
Managed settings have the highest precedence, and allowManagedPermissionRulesOnly can make managed settings the only source of permission rules. Organization admins can also restrict MCP servers with managed-mcp.json, managedMcpServers, allowedMcpServers, and deniedMcpServers. This is the first layer for fleet governance: decide which MCP servers Claude Code may connect to at all.
Claude Code also supports PreToolUse hooks. These hooks can inspect the tool name and input before execution, then return allow, deny, ask, or defer. Anthropic documents that hooks run before permission prompts for every tool except EndConversation. If your organization is not ready to proxy all MCP traffic, a hook that calls a central policy decision point can bridge part of the gap.
There is an important limit. The brief notes that Claude Code settings skip mcp__ permission rules with parentheses, which limits local settings as a general argument-level MCP policy system. Native controls are valuable, but they are not a full policy language for heterogeneous MCP traffic.
Where an MCP permission gateway fits
An MCP gateway sits between Claude Code and upstream MCP servers. Claude Code connects to one approved remote endpoint. The gateway fronts the actual GitHub, Jira, database, Kubernetes, browser, and internal MCP servers.
The first job is discovery filtering. When Claude Code asks for tools/list, resources/list, or prompts/list, the gateway returns only what the current user, repo, environment, and session should see. This is not only a security control. It also reduces the chance that the model plans around tools it is not allowed to use.
The second job is invocation enforcement. A gateway should re-check every tools/call and resources/read, even if that tool or resource appeared in discovery. Policy can change. Context can be stale. Prompt injection can attempt direct invocation. The gateway must treat each call as a fresh authorization decision.
The third job is credential brokerage. The MCP authorization spec builds on OAuth 2.1, protected resource metadata, resource indicators, and token audience validation. It also says MCP authorization is optional overall, while HTTP-based implementations should conform to the authorization spec. For STDIO transport, credentials should come from the environment instead. A gateway is where SSO/OIDC identity can be turned into scoped downstream credentials for the exact user, repo, environment, and risk tier.
The fourth job is audit. A useful audit event records the subject, Claude Code session, MCP server, operation, arguments summary or hash, decision, upstream result metadata, latency, and cost or session linkage. Without this central record, incident review depends on local machine state and partial logs.
Related reading: MCP security.
MCP permission gateway policy design
A good gateway policy starts with identity. The subject is broader than "Claude Code." It includes a developer or automation identity, a team, a repo, a branch, a workspace, and a session. A policy that cannot tell staging from production will eventually be too broad or too annoying.
Next, model the MCP request itself. At minimum, inspect the JSON-RPC method, upstream server, tool name, resource URI, prompt name, and arguments. For databases, that may mean classifying SQL reads and writes. For GitHub, it may mean repo, branch, path, issue, pull request, and workflow controls. For Kubernetes, it may mean namespace, resource type, and verb.
Then separate discovery policy from invocation policy. Discovery answers the question "what should the model know exists?" Invocation answers "is this exact call allowed right now?" You need both. Discovery filtering alone can fail with stale context. Invocation-only policy can still expose dangerous tool descriptions and create poor plans.
Finally, define failure behavior. For sensitive systems, fail closed when policy cannot be evaluated. For lower-risk developer experience flows, you may return ask or defer where Claude Code can still route to a human approval path. The key is to make this explicit by risk tier, not accidental by outage.
The security details that matter
The MCP security guidance named in the brief highlights risks that map directly to gateways: confused deputy, token passthrough, SSRF, session hijacking, local MCP server compromise, and OAuth URL validation failures. A gateway can reduce these risks only if it is designed as an enforcement point, not as a simple traffic forwarder.
Token handling deserves special attention. MCP authorization security guidance says token passthrough is forbidden: MCP servers must not accept or transit tokens that were not issued for themselves. The security best practices phrase this plainly: "Token passthrough is an anti-pattern." A gateway should exchange or mint audience-correct tokens rather than forwarding a broad user token everywhere.
Local STDIO servers are the awkward edge. They are convenient for developers, but harder to govern centrally. The options in the brief are practical: block them, wrap them, containerize them, or replace them with remote gateway endpoints. Which path you choose depends on how much local autonomy your engineering teams need and how sensitive the connected systems are.
Tool annotations can help user experience, especially hints such as read-only or destructive. They should not be trusted as policy by themselves. Treat annotations as input, not authority.
Use hooks as a bridge, not the whole design
PreToolUse hooks are valuable when you need centralized decisions before a full MCP reverse proxy is ready. A hook can send the proposed tool name and input to a policy service, then return allow, deny, ask, or defer. That gives you a path to start collecting decisions and blocking obvious high-risk actions.
Hooks still live at the Claude Code client boundary. They do not naturally solve upstream credential exchange, discovery filtering across many MCP servers, or central normalization of resource and prompt access. Use them for baseline control, migration, and fast risk reduction. Put long-term MCP access controls in a gateway when the goal is consistent governance across teams and agents.
What the current gateway landscape suggests
The brief points to several projects and vendors that are moving in this direction. agentgateway describes MCP authorization for tools, prompts, and resources with CEL policies. Octelium describes per-request JSON-RPC policies over method, tool, and arguments, and says every tool call is authorized on its own. Docker AI Governance describes policies over server registration, tool calls, resources, prompts, and audit events.
These are useful signals, not automatic proof of production fit. The brief's confidence is mixed because the architecture is well supported by official Claude Code and MCP docs, while some gateway claims still need production validation. Treat any gateway evaluation as an engineering exercise: run Claude Code against it, test streamable HTTP behavior, check failure modes, measure latency, and confirm audit quality.
Research also supports the architectural direction, with caveats. Rohith Uppala's 2026 arXiv paper, "Prompts Don't Protect: Architectural Enforcement via MCP Proxy for LLM Tool Access Control," reported that an ABAC proxy enforcing policy at discovery and invocation reduced unauthorized invocation to 0% in its benchmark and added under 50ms median latency. That is a useful data point, not a guarantee for your systems.
A separate 2026 stress test of Claude Code auto mode reported high false-negative rates under ambiguous DevOps scenarios, especially where effects happened indirectly through file edits instead of obvious shell commands. That finding reinforces the practical point: classifier or prompt-based permission gates are not enough for production-grade MCP authorization.
A practical rollout plan
First, establish the Claude Code baseline. Use managed settings for fleet-wide deny, ask, and allow rules. Restrict MCP servers with managed MCP controls. Consider allowManagedPermissionRulesOnly where local exceptions would undermine the policy.
Second, approve one remote MCP gateway endpoint for normal development work. Make it the path to GitHub, Jira, Postgres, Kubernetes, browser automation, and internal MCP servers. Keep local STDIO exceptions narrow, documented, and reviewed.
Third, implement discovery filtering and invocation re-checks together. Do not settle for one without the other. The model should not see tools it cannot use, and every call should still be authorized at execution time.
Fourth, broker credentials per user and session. Prefer user-delegated OAuth where audit and least privilege matter. Be careful with service accounts because they reduce friction but create shared blast radius.
Fifth, build audit before broad rollout. Record the decision, not only the request. Security teams need to know what was denied, what was allowed, which identity was used, which upstream server was called, and what policy version made the decision.
Sixth, test the boring failure cases. What happens when the policy service is down? What happens when a tool schema changes? What happens when Claude Code has stale tool context? What happens in CI or long-running sessions without an interactive user?
Evaluation checklist
- Can the gateway enforce policy at both discovery and invocation?
- Can it inspect JSON-RPC method, tool, resource URI, prompt, and arguments?
- Can it attach user, repo, environment, branch, session, and risk context to decisions?
- Does it prevent token passthrough and issue audience-correct downstream credentials?
- Does it produce central audit logs with decision, arguments summary or hash, latency, and upstream metadata?
- Does it fail closed for high-risk systems when policy cannot be evaluated?
- Does it work with Claude Code managed settings, managed MCP restrictions, and
PreToolUsehooks? - Does it handle local STDIO MCP servers through blocking, wrapping, containerization, or replacement?
- Does it have a clear process for tool drift, schema changes, and emergency kill switches?
Bottom line
For platform and security teams, the clean pattern is: Claude Code permissions set the client baseline, managed MCP controls decide which endpoints are allowed, hooks can bridge early policy decisions, and an MCP permission gateway becomes the central enforcement point for real MCP access controls.
The practical story is simple. When permission decisions are scattered, developers get prompt fatigue, admins get partial visibility, and approved servers become too broad. When MCP traffic runs through a gateway, the team can filter what the agent sees, authorize what it does, scope the credentials it uses, and audit the outcome.