Blog

Your MCP Gateway Can't See Most of What Your Agent Does

· Jonathan Fishner
Your MCP Gateway Can't See Most of What Your Agent Does

Watch a coding agent work for ten minutes. It opens a pull request with gh, hits an API with curl, and when neither does the job it writes a Python script and runs that. Three trips to external services, and not one of them is an MCP tool call.

If your agent security is an MCP gateway, you just watched ten minutes of ungoverned traffic, and your dashboard stayed green. The real problem is not the gap but the confidence: the gateway is up, the policies are configured, the box is checked. The gateway isn't broken. It is standing at the wrong layer, and it has no way to tell you what it isn't seeing.

How you got here

Nobody deploys an autonomous agent. They adopt an assistant. On day one, they approve every action. By week two, approving file reads is tedious, so those get auto-accepted. By month one, it's “just let it run the tests.”

By month three, it's --dangerously-skip-permissions in a tmux session over the weekend, because the agent is good and babysitting it has become the bottleneck.

At no point did anyone make a decision called “give an autonomous agent production credentials.” The autonomy arrived one convenience toggle at a time, while the environment never changed from day one: real keys in env vars, a full shell, open egress. The security control that actually existed was human attention, and it was quietly traded away for velocity, because trading it away is the entire point of these tools. Every coding agent ships with an autonomy dial, and every user turns it up. The question is whether your security holds at the setting you'll actually use, not the setting in the demo.

How agents actually reach services

An agent with shell access has at least four ways to hit an external API.

MCP tool calls. These are structured and easy to govern if you proxy the protocol. This is the slice MCP gateways cover.

CLI commands. gh, aws, stripe, vercel, kubectl. Agents are startlingly good at these. Peter Steinberger, creator of OpenClaw, put it bluntly: “Agents are really, really good at calling CLIs (actually much better than calling MCPs).” Andrej Karpathy made the same point: CLIs are exciting precisely because they're a “legacy” technology that agents can natively use. There's a whole genre of posts now arguing that the CLI is the new MCP.

curl. When no tool or CLI exists for the job, the agent shells out and improvises a single hand-assembled HTTP call.

Code it writes itself. This is usually a Python script with requests or a Node script with fetch. For coding agents it is the default mode of work.

# one agent session, three minutes apart:
gh pr merge 482 --squash                 # CLI
curl -X POST api.stripe.com/v1/refunds   # improvised shell call
python retry_failed_webhooks.py          # code it just wrote

Here is the part that makes this structural rather than incidental: to the agent framework, those last three are all one tool: bash. From the tool layer's perspective, each of them is just “ran a shell command.” The tool layer cannot tell you which credential was used, which host was reached, or what the payload contained, because at that layer those details do not exist as distinct events. The only place those three actions look like what they actually are is on the wire, as authenticated requests to GitHub, Stripe, and wherever the script points.

An MCP gateway can't be extended to cover this. There is nothing at its layer to extend into.

Coverage disappears exactly when risk peaks

So the gateway intercepts one protocol. The gh command doesn't pass through it. Neither does the curl call, or anything the Python script does. Those requests go straight to the service, authenticated with whatever credentials the process could reach: environment variables, config files in the home directory, CI secrets. None of those calls get a policy check, a rate limit, an approval flow, or an audit line. The attack surface hasn't shrunk. The unguarded part of it has moved out of view.

But the timing is worse than the coverage. Agents route around failure by design. That is their value proposition. A tool is missing, an MCP server is down, a rate limit trips, and the agent finds another way: it shells out and improvises. The governed path failing is precisely the trigger for the ungoverned path. Your enforcement coverage is inversely correlated with how much you need it.

An MCP gateway sees the agent's best behavior and misses its improvisation. Improvisation is where incidents live.

Enforce on the wire, not on the interface

If enforcement sits at the network layer, the calling mechanism stops mattering. Every outbound HTTPS request from the agent's environment, whatever produced it, passes the same choke point, and the same three things happen to it.

Credential injection. The request arrives without a key and the gateway injects one, scoped to the agent's project. There was never a key in an env var to steal. (We wrote about what that does and doesn't protect against.)

Policy enforcement. Host, path, and method rules, per-agent rate limits, human approval for sensitive operations. DELETE /repos is blocked whether it came from an MCP tool, gh, curl, or a script.

Audit. One log with every call, not just the tool calls: which agent called which service, with which credential, and when.

curl -fsSL https://onecli.sh/install | sh
export HTTPS_PROXY=http://localhost:10255

# every process in the agent's environment is now governed:
gh pr create --fill
curl -X POST api.stripe.com/v1/refunds
python anything.py

“Can't the agent just bypass the proxy?”

Fair question. The whole argument so far has been that enforcement an agent can route around is worthless. So what stops an agent from unsetting HTTPS_PROXY and going direct?

Nothing stops it. It just doesn't gain anything. The real credentials never exist in the agent's environment. The agent only ever holds placeholders, and real keys are injected at the proxy. An agent that goes around the proxy isn't escaping governance. It is escaping authentication. Its requests arrive at GitHub or Stripe without valid credentials and fail.

That is the architectural difference between the two layers. A protocol gateway is a fence, and the credentials are sitting in env vars on both sides of it. A network-layer gateway is the only place the credentials exist at all. There is nothing outside the fence to steal.

A scope note, because it matters: none of this prevents prompt injection. An agent can still be fooled. That is a model problem, and a proxy cannot fix it. What the network layer bounds is the blast radius of a fooled agent: which services it can reach, which credentials it can use, and what gets logged while it tries.

Side by side

Most products in this category stand at the protocol. We stood at the network layer instead. The feature lists look identical from a distance (policy, approvals, audit logs), so the real difference is what routes through the proxy at all. A proxy can only govern what it sees.

TrafficMCP gatewayOneCLI, network layer
MCP tool calls✓ governed✓ governed
CLI commands (gh, aws, stripe)✕ invisible✓ governed
curl and raw HTTP✕ invisible✓ governed
Code the agent writes✕ invisible✓ governed

And the rows aren't equal in size. For an agent doing real work in a shell, tool calls are one slice of the outbound traffic, and the practitioners quoted above are describing why the other slices keep growing. The comparison isn't four categories versus one. It is a gateway that governs a slice of your traffic versus a gateway that governs the wire all of it shares.

Standing on the wire makes enforcement independent of the calling mechanism: the call is governed whether or not the agent picked the protocol you planned for. You stop maintaining a list of ways your agent might reach the internet, and start governing the one path all of them share.

This is not an argument against MCP

MCP is a good protocol, and agents will keep using it. MCP traffic is HTTP underneath, so it flows through the same proxy and gets the same treatment as everything else. The argument is narrower: enforcement scoped to one protocol only works if agents only speak that protocol. They don't, and the trend lines (CLIs, code execution, computer use) all point further away from it.

That is also why the network layer is the safe bet rather than the contrarian one. It doesn't require you to predict which protocol wins. Whatever agents speak next year, it will run over HTTPS, and it will pass through the same wire.

The MCP ecosystem itself points the same way. It recently shipped enterprise-managed OAuth, real identity work built with Okta and Anthropic, and the first thing commenters asked for was the same treatment for CLI tools like gcloud and npm. The commenters are ahead of the tooling here. Auth isolation scoped to one protocol immediately raises the question of every other channel.

Count your own traffic

We're biased. We sell the network-layer version of this. So don't take our word for it. Ask your logs.

OneCLI is open source (Apache 2.0). One command gets you the gateway, vault, and dashboard:

curl -fsSL https://onecli.sh/install | sh

Point your agent's environment at the proxy and watch the request log for a day. Within a day you'll know your own MCP-to-everything-else ratio, and whether the gateway you have is standing where your traffic actually is. github.com/onecli/onecli