Governing the MCP tools your agents are allowed to call
AI agents are governed by what they can invoke. How to observe MCP servers and tools at the proxy, build an allowlist from evidence, and then enforce it.
An AI agent’s risk profile comes from what it can reach, not from which model it runs. The same model is a text generator with nothing attached to it, and something you need a change-control process for once it holds a shell tool, a database connection and an outbound HTTP client.
An agent’s registry entry carries a name, an owner and a risk rating. It records what someone intended the agent to do on the day they filled the form in. It will not tell you that the agent has been calling a Jira MCP server’s create_issue tool four hundred times a month, or that a Postgres server with write credentials was wired in during a sprint in March. Those calls are visible only at runtime, and they are the ones that turn into incidents.
The Model Context Protocol made this concrete. MCP standardised how agents connect to external tools, so the thing you need to govern now has a name, a shape and a wire format you can observe.
Start from what you can see, not what you were told
The instinct is to govern by declaration. Ask each team to document which MCP servers their agent uses, review the list, approve it. The list is accurate on the day it is written. An engineer adds a server the following sprint, and nothing in that process forces anyone to revisit the document.
The alternative is to observe. If your agents’ model calls route through a proxy, every tool invocation is visible in the request and response stream. Per call you get:
- Which agent or AI system made it
- The provider and model
- The kind of call, meaning an MCP tool use, a provider-hosted server tool, or a plain client-side tool
- The server name the tool belongs to
- The tool name itself
- Who was behind it, by user email and department
- A request ID tying it back to the full session
From that stream you can build a profile per agent. Which servers it touches, which tools on each, how many times, first seen and last seen. Nobody had to declare anything, and the profile cannot drift from reality, because it is reality.
Expect the first profile to be uncomfortable reading. Agents reach servers their owners did not know were wired up, because an MCP client config was inherited from a template or a framework enabled something by default.
Three kinds of tool call
Not every tool call is the same shape, and conflating them produces a confusing inventory.
MCP tool use. The agent invoked a tool exposed by an MCP server. This carries the widest blast radius, because MCP servers are frequently third-party code holding credentials of their own.
Server tool use. A tool hosted by the model provider itself, such as provider-side web search or code execution. The risk profile differs: you are trusting the provider rather than a server you deployed, but the data still leaves your boundary.
Client tool use. A function the application defines and executes itself. The code is yours, which makes this the best-understood category. It is also where an agent reaches your internal systems.
Govern these identically and you will either over-restrict the safe category or under-restrict the dangerous one. Record the kind alongside the call.
Build the allowlist from the observed profile
Once you have a profile, the allowlist writes itself. Approve what you have observed and understand, deny what you have not.
The key design decision is what happens when no allowlist is configured. The pragmatic answer is to allow by default and record the verdict on every call. A governance tool that breaks every agent the moment it is installed does not stay installed. Start in observation, let profiles accumulate, then tighten per agent once the team can see what they would be turning off.
Recording the verdict on every call matters more than it sounds, including when that verdict is “allowed because no allowlist exists”. It means that when you later enable enforcement, you can answer “what would this have blocked last month?” from data rather than guesswork. Teams sign off on enforcement when they can read the list of calls it would have stopped. Without that list you are asking them to approve a change that might break production on a Tuesday, and it gets deferred.
There is a second-order benefit. An allowlist scoped per agent and built from observation is what makes an agent’s autonomy level meaningful. HUMAN_IN_THE_LOOP on a registry record is a claim about how a team says it works, and the scale it sits on runs from MANUAL through SUPERVISED up to FULL_AUTONOMY. An allowlist of four tools, none of which write to production, is a claim you can test against last month’s call log. Record the autonomy level anyway, because it tells a reviewer what the owning team believes it is doing. Expect the allowlist to be the one an auditor asks to see.
What the frameworks already ask for here
This is not a novel control. It is an existing control applied to a new component type.
NIST AI RMF MAP 4 asks you to understand risks and benefits of all components. An MCP server is a component. MANAGE 3 asks you to manage third-party risks, and a third-party MCP server running with your credentials is squarely in scope. It is also the kind of dependency that skips vendor review, since it arrived in a config file rather than through procurement.
ISO/IEC 42001 A.10 covers third-party and customer relationships, including allocating responsibilities and managing suppliers. A.4.4 asks for tooling resources to be documented. An observed tool profile is better documentation than a written inventory, and it is the kind of evidence A.6.2.8 event logs are asking for.
SOC 2 CC6 is logical access control. If an agent can invoke a tool that reads customer data, that is an access path, and it belongs in your access review whether or not a human sits at the other end of it. An access review that enumerates human accounts and service accounts, then omits the agent that can call both, has a hole in it.
The framing that lands with auditors: an agent with tool access is a non-human identity with privileges. You already have controls for those. Apply them.
Practical sequence
If you are starting from nothing:
- Route agent traffic through a proxy you control. Without this, everything below is a declaration exercise. This is the only step with real engineering cost.
- Observe for a few weeks. Build profiles per agent. Do not enforce anything yet.
- Review the profiles with the owning teams. This conversation surfaces the surprises, and it is where you learn which servers are load-bearing and which were accidental.
- Allowlist per agent, in dry-run. Record what would have been denied.
- Read the would-have-denied list. If it is empty, your allowlist is too loose. If it is full of legitimate traffic, your profiles were too short.
- Enforce, agent by agent. Start with the agents that touch the least.
- Alert on the new. A tool appearing that no profile has seen before is the signal worth waking someone for. It means either a legitimate change nobody told you about, or something worse.
Step 7 is the one that keeps paying. Profiling tells you what exists during the weeks you were watching. The alert on an unseen tool name is what catches the Postgres server someone adds in March, on a sprint nobody mentioned to you.
The hard part
Tool governance has a tension that no amount of process resolves. The whole value of agents is that they compose capabilities in ways you did not pre-plan, and an allowlist is a bet that you can enumerate the useful capabilities in advance.
Set it too tight and you have built an expensive way to stop your agents working, and teams will route around you. Too loose and you have built an inventory rather than a control.
The resolution is to stop asking the allowlist to be the safety mechanism. Its job is to fire when an agent calls something it has not called before, and to route that to someone who can decide within the hour whether it is fine. A slightly generous list that produces a reviewed alert on every new tool is worth more than a tight list nobody can amend without a change ticket.
So optimise for how fast that alert reaches a person with enough context to judge it. The tight-list version is the one that gets switched off the first time it blocks a release.
More resources
Human in the loop for AI agents: from a policy line to a proxy that holds the call
Why 'a human reviews high-risk actions' fails as a policy, and how to make it a condition the proxy checks against each tool call's arguments and holds.
ReferenceAI governance glossary: 40 terms worth getting right
Plain definitions for the terms that come up in AI governance work: regulation, risk assessment, agents and MCP, shadow AI, and the telemetry underneath it all.
FrameworksHow to classify a high-risk AI system under the EU AI Act
A step-by-step walkthrough of EU AI Act classification: role, prohibited practices, Annex III, the Article 6(3) derogations, and the obligations each triggers.