# MCP gateway: one governed entry point for agent tools

URL: https://infro.io/blog/mcp-gateway-govern-agent-tools
Author: INFRO Editorial (https://infro.io/blog/editorial)
Publisher: INFRO
Published: 2026-10-13
Last modified: 2026-10-13
Last reviewed: 2026-10-13 (next review due 2026-11-12)
Topic: Agents and multimodal systems
Format: Guide

> An MCP gateway sits between your agents and the MCP servers they use: servers and their credentials are registered once, each agent key sees only the tools it was granted, tool definitions are reviewed and pinned so a silent change is refused, and every call is recorded against the run that made it. It narrows what a compromised server or a steered agent can do; it does not stop prompt injection. INFRO's MCP gateway does this at mcp.infro.io/gateway/mcp with the gateway key agents already use for model calls, on the Business plan and above.

Key takeaways:
- An MCP server is a dependency with credentials: the published incidents are a fake npm package that BCC'd every email, a CVSS 9.6 client flaw, poisoned tool descriptions and an agent steered into leaking private repositories.
- The MCP specification makes the host responsible for consent, access control and logging; it cannot enforce them at the protocol level.
- A gateway centralises four controls: credentials agents never hold, deny-by-default grants per agent, pinned tool definitions that refuse silent changes, and one audit record per call.
- No filter reliably separates instructions from data in a tool result; limit what one agent can combine, and keep a person on changes that matter.
- INFRO's MCP gateway serves approved tools at mcp.infro.io/gateway/mcp to a gateway key with a grant, adds the server's sealed credential per call, and puts tool calls on the same trace as model calls.

A model that answers badly produces a bad paragraph. An agent with tools reads your repositories, sends your email and changes your systems, using credentials someone pasted into a configuration file. Each Model Context Protocol server it connects to is code you did not write, holding a credential you issued, describing itself in text the model treats as guidance. That is a supply chain, and it has started to fail like one.

This guide covers what has gone wrong in public, what the MCP specification asks of the people who deploy it, the controls a gateway in front of your tool servers can centralise, and where those controls stop. The last third describes INFRO's MCP gateway as it is documented and built.

## Tool access is the new supply chain

Four public incidents from 2025 show the range.

[Diagram: Four public MCP incidents, from the primary write-ups opened on 2026-10-13.]

- **Poisoned descriptions.** In April 2025 Invariant Labs showed a tool whose visible purpose was adding two numbers, and whose full description told the model to read the user's MCP configuration and SSH private key and pass them through an unused parameter, without mentioning it. In their test with Cursor the agent complied, and the confirmation dialog did not show the full input. The same write-up described two variants: a *rug pull*, where a server changes a tool's description after the user approved it, and *shadowing*, where one server's description changes how the agent uses another server's trusted tool, such as redirecting every email sent through it[1].
- **A steered agent with broad access.** In May 2025 Invariant Labs showed an agent connected to the official GitHub MCP server reading a malicious issue in a public repository, then copying data from the user's private repositories into a public pull request. The server code was not at fault; the agent had access to every repository and followed instructions it found in content. Their mitigation was granular permissions, such as limiting a session to one repository[2].
- **A vulnerable client.** In July 2025 JFrog disclosed CVE-2025-6514 in `mcp-remote`, a proxy used to connect desktop hosts to remote servers. A malicious server could return a crafted authorization endpoint during OAuth discovery that the client passed to the operating system as a command. It was rated CVSS 9.6, affected versions 0.0.5 to 0.1.15 and was fixed in 0.1.16[3].
- **An impersonating package.** In September 2025 Postmark warned that an npm package named `postmark-mcp`, which it had never published, had added a hidden BCC of every outgoing email to an outside address in version 1.0.16, after 15 earlier versions that built trust. Its advice: remove the package, check email logs and rotate any credentials sent by email[4].

None of these needed a novel exploit against the model. They needed a credential in the wrong place, a definition nobody re-read, or an agent allowed to combine more than its task required.

## What the specification asks of you

The MCP specification is direct about where responsibility sits. It describes tools as arbitrary code execution, says annotations describing a tool's behaviour should be treated as untrusted unless they come from a trusted server, and says hosts must get explicit user consent before invoking a tool. It also says the protocol "cannot enforce these security principles at the protocol level"; implementors are expected to build consent, authorization and access controls into their applications[5].

The tools page adds a checklist. Servers must validate inputs, apply access controls, rate-limit invocations and sanitise outputs. Clients should confirm sensitive operations, show tool inputs before calling, validate results before passing them to the model, set timeouts and log tool usage for audit. Clients that aggregate tools from several servers should disambiguate names, for example by prefixing a server identifier[6].

For remote servers, the authorization specification builds on OAuth 2.1. A server must only accept tokens issued for itself, and must not accept or pass through any other token[7]. The security guidance calls token passthrough an anti-pattern because it bypasses the server's own controls and leaves no usable audit trail, and it recommends a minimal initial scope set with step-up for privileged operations rather than broad tokens granted up front[8].

OWASP's MCP Top 10, currently in beta, names the same risks as a list: token mismanagement and secret exposure, privilege escalation via scope creep, tool poisoning, supply-chain tampering, command injection, prompt injection via contextual payloads, weak authentication, lack of audit and telemetry, shadow MCP servers, and context over-sharing[9].

## What an MCP gateway does

When every developer's editor and every agent connects to servers directly, each of those controls has to be rebuilt in each host, and the credentials live wherever the hosts run. An MCP gateway is a proxy that speaks MCP on both sides: agents connect to one endpoint, and the gateway connects to the upstream servers. That position lets it own five things.

1. **One endpoint, servers registered once.** An administrator registers each upstream server with its URL and credential. Agents configure a single entry instead of one per server, and a server added or removed centrally changes every agent at once.
2. **Credentials agents never hold.** The upstream secret stays in the gateway and is attached per call. The agent authenticates to the gateway with its own credential, which the upstream never sees. A laptop or a CI log no longer contains a GitHub token with write access to every repository.
3. **Deny-by-default grants.** Each agent identity sees only the servers, and the tools within them, it was granted. The research agent gets read tools on the wiki; the release agent gets the deploy tool and nothing that reads the inbox.
4. **Pinned definitions.** The gateway records each tool's definition when a person approves it and serves that copy. A server that later changes a description or schema is a rug pull until a person looks at it, so the changed tool is refused rather than passed through.
5. **One record per call.** Which agent, which tool, what outcome, how long, tied to the run that made it. That is the audit trail the specification asks hosts to keep and OWASP lists as missing.

[Diagram: OWASP MCP Top 10 risks a gateway addresses, and where each control has to live. Risk names from the OWASP project page, read 2026-10-13.]

A gateway also gives you one place for limits: argument and result sizes, time limits, and a rate limit per upstream that protects the server from a looping agent.

## Where a gateway stops

A gateway decides whether a call may proceed and checks what passes through. It does not make the content safe. A tool result is text the model reads, and if an issue body or an email contains instructions, the model may follow them. Pattern detectors and definition scans reduce some risks; none reliably tells instructions apart from data.

Simon Willison's framing is the most useful test: an agent that has access to private data, exposure to untrusted content and the ability to communicate externally can be made to leak the first through the third[10]. The GitHub incident had all three in one session[2].

[Diagram: The three capabilities that, combined on one agent identity, let untrusted text exfiltrate private data.]

So the design rules sit outside the gateway as well as in it:

- Give each agent identity only the servers and tool classes its task needs, and avoid granting all three capabilities to one identity.
- Register upstream servers with the narrowest credential they accept, read-only where the provider offers one.
- Keep a person in the loop for writes that matter, as the specification recommends[6].
- Treat a server's annotations as claims, not facts, unless you trust the server[5].
- Keep client software current; a gateway does not patch a vulnerable MCP client on someone's machine[3].

## INFRO's MCP gateway: endpoint, grants and pinned tools

INFRO's MCP gateway puts INFRO between your agents and the MCP servers you already use, such as GitHub, Linear, Supabase, Stripe, Datadog or internal tools. INFRO never executes a tool and never hosts an MCP server or an agent: the servers are yours, reached with your credentials, and the services behind them bill you under your own accounts. Tool calls are not priced and do not count against the plan's request allowance.

Agents connect to `https://mcp.infro.io/gateway/mcp` with `Authorization: Bearer <gateway key>`, the same INFRO gateway key they use for model calls on `/v1`. That endpoint lists every approved tool the key's grants allow, named `<slug>_<upstream name>` (for example `github_list_issues`), so one entry in the agent's configuration covers every server. `https://mcp.infro.io/gateway/<slug>/mcp` serves one server's tools under their own names, for an existing integration that should only change its URL and header. Both speak Streamable HTTP; the gateway serves MCP revision 2026-07-28 and the earlier `initialize` revisions.

```python
async with MCPServerStreamableHttp(
    name="infro",
    params={
        "url": "https://mcp.infro.io/gateway/mcp",
        "headers": {
            "Authorization": f"Bearer {os.environ['INFRO_API_KEY']}",
            "X-INFRO-Trace-Id": trace_id,
        },
    },
) as infro:
    agent = Agent(name="Triage", instructions="...", mcp_servers=[infro])
```

The [connect guide](https://infro.io/docs/mcp-gateway/connect) has the same recipe for the Claude Agent SDK, LangChain, the Vercel AI SDK, Google ADK, Mastra, CrewAI, Claude Code, Cursor and VS Code.

[Diagram: One tool call through INFRO's MCP gateway, as documented on the MCP gateway pages.]

**Servers.** Owners and admins register a server with a slug, a name, its public HTTPS URL and either no authentication or up to eight credential headers. Header values are sealed and never shown again; the console and the management API show only header names. Registration succeeds only if the server answers `tools/list` with that credential. A server can be limited to some projects and environments.

**The catalog.** INFRO re-reads each server's tools on registration, on **Sync**, and every 15 minutes (or at the server's own `ttlMs` when it asks for longer, at most every six hours). Approving a tool stores a SHA-256 hash of its canonical definition and the definition itself, and agents are served that stored copy. When a sync finds a different hash, the tool becomes `changed`, disappears from `tools/list`, and calls are refused with `tool_definition_changed` until an admin reviews the difference and approves it again. Approval names the hash the reviewer saw, so a definition that changes between review and approval is refused.

[Diagram: Every tool in the gateway catalog is in one of five states; only `approved` tools are served.]

Each new or changed definition is also scanned for shapes associated with poisoning and shadowing: invisible Unicode, instruction-like phrases aimed at the model, mentions of another server's tools, URLs in descriptions, very long descriptions, write tools that accept any extra property. The scan informs the reviewer; it never approves or blocks on its own.

**Classes and grants.** An admin classes each approved tool `read` or `write`. A server's own `readOnlyHint` only suggests the default, because the specification treats annotations as untrusted. Access is denied by default: a key with no grant sees no tools. A grant gives one key one server in mode `read`, `all` or `selected` (named tools only), and survives key rotation. Admins label each server as reading private data, reading untrusted content, or able to send data out; when one key's grants would combine all three, the console warns before saving, and the management API refuses the grant with `mcp_trifecta_unconfirmed` unless the request sets `confirm_trifecta: true`. The grant is not forbidden: the decision stays with you, and it is audited.

## Credentials, guardrails and the record of each call

The agent holds only its INFRO gateway key. INFRO adds the server's sealed headers to each call; the server never sees the INFRO key, the agent's `Authorization` header or any `X-INFRO-*` header. Server URLs must be public HTTPS, private and link-local addresses are refused at registration and on every call, and redirects are never followed.

Before a call reaches the server, INFRO checks the grant and the tool's state, validates the arguments against the approved `inputSchema`, and applies your organization's guardrail policies to the arguments. After it returns, it checks the result size and `outputSchema` and applies the guardrails' output stage. The pattern detectors apply (`email`, `phone`, `card`, `iban`, `ssn`, `ip`, `secret`, `deny_terms`); a `secret` rule with `block` on the input stage refuses a call whose arguments carry a credential, a common sign of an agent being steered into sending one out. INFRO's own documentation is plain that guardrails and scans reduce risk and do not stop prompt injection.

Every call, refusals included, writes one record: time, server, tool, outcome, error code, latency, argument and result sizes, a SHA-256 of the arguments, guardrail counts and the key, project, environment and attribution. Contents are not kept unless an owner or admin turns on capture, which follows the organization's prompt-logging settings. Send the same `X-INFRO-Trace-Id` on model requests and on the MCP connection, and `GET /v1/traces/{trace_id}` returns both, with tool calls under `tool_calls`. Approvals, blocks and class changes go to the organization's audit log, and two alert events, `mcp.tool_changed` and `mcp.server_failing`, route to the same email, Slack and webhook channels as other alerts.

Kill switches are read on every call without a cache: disable a server, **Stop all tool traffic** (`POST /mcp_servers/disable_all`), block a tool, delete a grant, or disable the key (`403 key_disabled`). None of them is plan-gated.

## Limits, errors and plans

| Limit | Value |
| --- | --- |
| Arguments per call | 256 KB, else `invalid_tool_arguments` |
| Result per call | Per server, 1 KB to 5 MB; default 1 MB, else `tool_result_too_large` |
| Time limit | Per server, 1 to 300 seconds; default 60, else `upstream_timeout` |
| Calls per key | The key's existing rate limit, shared with its model calls |
| Calls per server | Per server, 60 to 50,000 a minute; default 300, else `429 mcp_server_rate_limited` |
| Credential | Up to 8 headers, each value up to 8 KB |

Table: INFRO MCP gateway limits, from its documentation.

A refusal after authentication is a tool result with `isError: true`, so the model can read it: `structuredContent.error` carries a `type`, a `code` such as `tool_not_allowed`, `tool_not_approved` or `guardrail_blocked`, and a message saying what to do next. Refusals before any MCP message are HTTP errors in INFRO's usual envelope, such as `403 plan_feature` or `404 mcp_server_not_found`, which answers the same way for an unknown, disabled or ungranted server so a key cannot map what exists. The [errors page](https://infro.io/docs/mcp-gateway/errors) lists which codes to retry.

Some things are not supported yet: upstream servers that require OAuth sign-in (such as Sentry and Notion), servers on private networks or behind IP allowlists, a person approving each write call as it happens, MCP resources and prompts, and provider-hosted connectors that would carry the gateway key to a model provider. Today an admin decides per tool and per grant, ahead of time.

The MCP gateway is included in the Business plan ($599 a month) and Enterprise agreements; on other plans its endpoints answer `403 plan_feature`. The plan gates only what enables access (registering a server, approving a tool, granting a key). The same configuration is available through the management API's `mcp_servers`, `mcp_server_tools` and `mcp_key_grants` resources. The [security model](https://infro.io/docs/mcp-gateway/security) page describes what INFRO stores and processes; read it, and your own policies, before routing tool traffic through any gateway.

## Sources

1. MCP Security Notification: Tool Poisoning Attacks — Invariant Labs. https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks (accessed 2026-10-13)
2. GitHub MCP Exploited: Accessing private repositories via MCP — Invariant Labs. https://invariantlabs.ai/blog/mcp-github-vulnerability (accessed 2026-10-13)
3. Critical RCE Vulnerability in mcp-remote: CVE-2025-6514 — JFrog. https://jfrog.com/blog/2025-6514-critical-mcp-remote-rce-vulnerability/ (accessed 2026-10-13)
4. Security Alert: Malicious 'postmark-mcp' npm Package Impersonating Postmark — Postmark. https://postmarkapp.com/blog/information-regarding-malicious-postmark-mcp-package (accessed 2026-10-13)
5. Model Context Protocol specification (2026-07-28) — Model Context Protocol. https://modelcontextprotocol.io/specification/latest (accessed 2026-10-13)
6. Tools — Model Context Protocol specification — Model Context Protocol. https://modelcontextprotocol.io/specification/2026-07-28/server/tools (accessed 2026-10-13)
7. Authorization — Model Context Protocol specification — Model Context Protocol. https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization (accessed 2026-10-13)
8. Security Best Practices — Model Context Protocol. https://modelcontextprotocol.io/docs/2026-07-28/tutorials/security/security_best_practices (accessed 2026-10-13)
9. OWASP MCP Top 10 — OWASP Foundation. https://owasp.org/www-project-mcp-top-10/ (accessed 2026-10-13)
10. The lethal trifecta for AI agents: private data, untrusted content, and external communication — Simon Willison. https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/ (accessed 2026-10-13)
