Two questions decide whether a connected agent estate is governed or merely inventoried. What exactly did you approve — a server, a tool, or an action? And what happens on the day the thing you approved offers something it did not offer when you looked at it? Most approval processes answer the first badly and the second not at all.
The sentence this page rests on. Approval that covers only the state on the review date is not approval, it is a dated observation. A tool set is a moving object by design — the protocol carries a capability declaration and a notification specifically for the case where it changes.
Plain-English explainer · Model Context Protocol specification, revision 2026-07-28 · ISO/IEC 42001:2023 · Last reviewed August 2026
No, every tool does not need its own approval — but every tool does need a class, and read-only search must never share a blanket approval with destructive administrative actions. The unit that approval attaches to is not the server and not the individual tool. It is the combination of server, action class, principal and environment. Classification happens per tool, approval happens per class, and the approval is only real if it says what happens when the tool set changes underneath it. That last clause is where most enterprise processes fail. A Model Context Protocol server declares a tools capability that may include listChanged, and emits notifications/tools/list_changed when what it offers moves. The protocol carries that message because the set is expected to move. An approval that captured a snapshot on a Tuesday in March has, by the following quarter, silently expanded to cover whatever the server chose to add. What follows is how to classify tools you did not write, how to detect change in each of the forms it takes, what an approval record has to contain to survive an examination, and where delegation quietly breaks when corporate single sign-on is placed in front of the whole arrangement. It assumes you have already decided which deployments cross into agent territory and have reviewed the servers themselves.
Key Takeaways
- Individual per-tool approval does not scale and produces approval fatigue, which is a control failure in its own right. Classify every tool. Approve every class. Classification is the only per-tool step.
- Read and search are not the same class. Read fetches a named object. Search enumerates a corpus. A search tool converts access to a record into access to an index, and its blast radius is the corpus rather than the row.
- A server that adds tools after approval has expanded your blast radius without anyone deciding anything. The protocol anticipates this: servers declaring the listChanged capability should emit notifications/tools/list_changed, and the specification’s own security guidance describes a client ending up with tools it was not aware were enabled.
- Tool annotations — readOnlyHint, destructiveHint, idempotentHint, openWorldHint — are hints, not guarantees, and clients are required to treat them as untrusted unless the server is trusted. Set the class from the input schema and the executing credential instead.
- Detection needs four mechanisms working together, because each one misses something the others catch: manifest diffing, version or digest pinning, change notifications, and periodic re-review on a cadence set by the class ceiling.
- Corporate SSO authenticates the human. It does not authorise the agent, and it says nothing about whether the delegated authority is narrower than the authority held — which is the question a buyer’s security team will actually ask.
What are you actually approving
There are three candidate units, and choosing between them is the whole design decision. Per server is what most organisations do, because it matches how the thing is installed. It is too coarse: a single server routinely exposes tools spanning four action classes, and one approval cannot mean four different things. Per tool is what security teams reach for next. It is too fine: a mature server can carry sixty tools, an estate carries thousands, and a queue of thousands of approval tickets ends the same way every time, with a reviewer clicking through a batch on a Friday.
Per action class is the unit that holds. What differs materially between two tools is not their name or their vendor but what they can do to the world and how hard that is to undo. Group by that, and one decision covers many tools without covering things it should not. The distinction worth writing on the policy page in exactly these words: classification is per tool, approval is per class. Classification is an inspection, usually five minutes and often templated across a whole server. Approval is a judgement, taken once per class per environment, and inherited by everything that lands in it afterwards.
The corollary is the thing to enforce hardest. Two tools may not share an approval across a class boundary, no matter how convenient it is that they arrived on the same server. A read-only search tool and a destructive administrative tool have nothing in common except a connection, and a blanket approval that spans them is not a lenient control, it is an absent one. In practice that is precisely the shape of most first drafts we review: a ticket that approves “the GitHub MCP server” and, in doing so, approves reading a file, opening a pull request, deleting a branch and changing repository permissions with the same signature.
Eight action classes, and what each one owes
The ladder is ordered by how hard the action is to undo and how far its effect reaches beyond the system that performed it. Two boundaries do most of the work: the one between read and search, which almost every process misses, and the one between write and send, which is where an internal mistake becomes an external one.
| Action class | What defines it | Reversibility | Default mediation | What the approval must record |
|---|---|---|---|---|
| Read | Retrieves a specific, named object the calling principal already has a right to see. The tool is handed an identifier and returns that one thing. | Nothing to reverse — but disclosure is a one-way door. The risk is not the state change, it is the copy that now exists in a model context window and possibly in a transcript. | Standing approval inside a declared data scope. No per-call confirmation. | The data classifications reachable, and where the retrieved content is retained. |
| Search | Enumerates. The caller supplies a predicate rather than an identifier, and the tool returns whatever matches across a corpus. | Nothing to reverse, and this is exactly why it is misfiled. Search converts access to a record into access to an index. Its blast radius is the corpus, not the row. | Standing approval, but scoped to a named corpus and rate-bounded. Never inherited from a read approval. | The corpus boundary, whether results are filtered by the caller’s own entitlements at query time, and the query log. |
| Write | Creates or updates a bounded object inside a system you own — a ticket, a record, a document, a branch. | Recoverable where the target system versions its own history. Unrecoverable where it does not, which is a property of the target rather than of the tool. | Standing inside a declared object scope, confirmation outside it. Bulk writes are a different class in practice — see the edge cases. | Object types and environments in scope, and whether prior state is retrievable. |
| Send | Emits something to a party outside your trust boundary: email, chat message, webhook, ticket comment visible to a customer, public post. | Irreversible at delivery. This is also the primary exfiltration channel when a model has been fed hostile content, which is why it is separated from write. | Human confirmation with the rendered payload and the actual recipient list shown — not a summary of them. | Recipient domains permitted, payload retention, and the confirmation artefact per send. |
| Delete | Removes or overwrites. Includes truncating, purging, force-pushing, and revoking — anything whose success is measured by something no longer being there. | Determined entirely by the target system’s retention and soft-delete configuration, never by the tool description. | Confirmation, and restricted to soft-delete endpoints where the platform offers them. | The retention window behind each destructive endpoint, evidenced from the platform rather than asserted. |
| Deploy | Changes what runs: a release, an infrastructure apply, a configuration push, a feature-flag flip in production. | Reversible only to the extent a rollback path exists and has been exercised. An untested rollback is not a control. | Route through the change-management gate that already exists. Do not build a parallel approval path for agents. | Which environments, which gate the call passes through, and the change record it produces. |
| Transact | Moves money or creates a binding commitment — payments, refunds, orders, contract acceptance, trades. | Costly or impossible, and reversal usually involves a third party on their timetable rather than yours. | Out-of-band human approval with per-transaction and per-period limits enforced by the downstream system, not by the agent. | Limits, the approving human, and reconciliation to the financial system of record. |
| Administer | Changes who can do what: granting roles, rotating keys, editing policy, altering retention, disabling logging, adding another integration. | Technically reversible, practically the worst class, because a successful administrative call can remove the evidence that it happened. | Excluded by default. Where genuinely required, dual control plus a detective control owned by someone who cannot make the change. | The specific administrative endpoints permitted, and an independent alert on privilege change that lands with a second person. |
Three properties travel with the ladder rather than with any single row. Blast radius, which is what one call can touch at maximum rather than typically. Attribution, which is whether a call can be traced to a person or a run without inference. And detectability, which is whether the action leaves a record somewhere the actor cannot edit. Administer is the worst class on all three at once, which is why it is excluded by default rather than merely confirmed — a successful administrative call is the one that can remove the evidence of itself.
Reading a tool you did not write
A tool definition offers four things about itself: a name, a description, an input schema and an optional set of annotations. They are not equally trustworthy, and knowing the order is most of the skill.
The name is marketing. It is chosen for the model’s benefit, it is unique only within one server, and it can be identical to a tool on a different server doing something entirely different. The description is instruction. It is text that will be placed in front of a model, which makes it part of the attack surface as well as part of the documentation. It is also the field most likely to be optimistic. The annotations are hints. The specification says so in the schema itself — the properties are not guaranteed to describe tool behaviour faithfully — and it goes further, requiring clients to treat annotations as untrusted unless they come from a trusted server. The defaults matter when you are relying on their absence: readOnlyHint defaults to false, destructiveHint to true and openWorldHint to true, so an unannotated tool is to be treated as potentially destructive and reaching an open world. That is the correct default, and it is the opposite of how most registers record an unannotated tool.
The input schema is evidence. It is machine-readable, it is what the server will actually accept, and it is the field that answers the questions that set the class. Does an argument identify one object or describe a set? Is there a recipient, a destination, a webhook URL — anything that carries data across the trust boundary? Is there a confirm or force flag, which is usually a tell that the underlying operation is destructive whatever the description says? Is there a free-text field that becomes a path, a query or a command downstream? A schema with an unbounded selector is classified on what the selector can reach.
Above all four sits the fact none of them expose: a tool can never be safer than the credential it executes under. A server described as read-only, holding a token with write scopes, is a write-class risk with a read-class description. The ceiling is set by the entitlement, not by the interface. This is why the executing credential and its scope set are fields in the approval record rather than a footnote, and why the honest classification question is not “what does this tool do?” but “what could this credential do if the tool were not the thing calling it?”
Approval must cover ongoing change
A traditional integration review works because the thing reviewed is stable between releases. A connected tool server is not stable in that way, and its instability is a feature rather than a defect. The protocol declares it openly: a server that supports tools declares the capability, and where it sets listChanged it is telling clients that the set will move and that it will say so when it does. The specification’s security guidance is blunter still, describing a sequence in which a client ends up holding tools it was not aware were enabled.
Capability change is not one event. It is at least six, and they are detected by different means, which is why a single mechanism always leaves a gap. A tool is added — the obvious case, and the only one most processes look for. An existing tool’s schema widens, which is more dangerous because the tool name is unchanged and a name-based register sees nothing. Adding a recipient array to a tool that previously updated one record has moved it from write to send without renaming anything. A description changes, which alters the instructions placed in front of the model even when behaviour is identical — the pattern the community calls a rug pull, where a tool is benign at review and rewritten afterwards. The backend changes behind an identical manifest, which no interface diff can ever catch and only a pin can. The required scopes change, surfacing as a step-up challenge that looks like a consent prompt and is actually a request for more authority. And the endpoint or authorisation server changes, which is a different server wearing the same name.
There is a seventh case that reads as a defect and is not. The current revision states that a server’s tool set must not vary per connection or as a side effect of other requests, but explicitly may vary by the authorisation presented on the request — returning, for example, only the tools the caller’s granted scopes permit. So two of your people can legitimately see two different tool lists from the same server. The governance consequence is precise: the object you approve is the union across principals, not the view that appeared on the reviewer’s screen. A review conducted by a read-only account will see a read-only server and record a read-only approval that a privileged user immediately exceeds.
Framed in control terms, none of this is new. The trust services criteria already carry the requirement at CC3.4, which asks the entity to identify and assess changes that could significantly impact the system of internal control, and change to what an agent can do is squarely that. CC8.1 governs authorising, testing, approving and implementing changes. CC6.3 asks that access be authorised, modified or removed based on roles and responsibilities with consideration of least privilege and segregation of duties. CC9.2 covers the risks associated with vendors and business partners, which is where a third-party server lives. Under ISO/IEC 42001:2023 the same obligation appears as planned and controlled change within the management system, with the impact of the AI system reassessed when its context moves. What is new is only the rate: this class of system changes between reviews rather than at them.
The change-trigger matrix
Four mechanisms, each covering what the others miss. Manifest diffing catches interface change. Pinning catches behaviour change behind an unchanged interface. Notifications reduce the time to detection where a server declares the capability. Periodic re-review catches the server that is quietly doing none of the above. The default response to every unexpected change is the same: quarantine the delta, keep the approved set running, and let a person decide without an outage forcing their hand.
| Trigger event | How it is detected | Governance response | Who decides | Evidence produced |
|---|---|---|---|---|
| A tool appears in tools/list that was not there before | Scheduled manifest diff against the last approved snapshot, plus the notifications/tools/list_changed message where the server declared the listChanged capability. | Quarantine the new tool. The server stays available at its previously approved classes. The new tool is unavailable until classified. | Registered owner of the server entry | Before and after manifest hashes, the diff, the timestamp, and the quarantine decision. |
| An existing tool’s input schema widens | Structural diff of inputSchema — a new property, a required field dropped, an enum loosened, a scalar becoming an array. | Re-review at class level. Widening can move a tool between classes: adding a recipients array turns a write into a send. | Class owner for the tool’s current class | The schema diff, the re-classification decision, and the date it took effect. |
| A tool’s description or title changes | Text diff of description, title and annotations against the approved snapshot. | Treat as a change to the model’s instruction surface. Inspect for injected directives, and re-review if described behaviour crosses a class boundary. | Security review | The text diff and the reviewer’s note on whether behaviour or only wording changed. |
| An annotation flips — readOnlyHint or destructiveHint | Annotation diff on the same schedule as the manifest diff. | A signal to re-verify by schema and credential, never an authorisation in itself. The specification requires clients to treat annotations as untrusted unless the server is trusted. | Class owner | The annotation diff plus the independent verification that set the class. |
| The server version or image digest changes, manifest identical | Comparison against the pinned version or digest. This is the case manifest diffing cannot see: behaviour behind an unchanged interface. | Handle as a supply-chain event. Verify provenance, re-review at the server’s class ceiling, and re-pin. | Platform owner plus the class owner where the ceiling is above read | Old and new pins, the provenance check, and the re-approval record. |
| A call starts failing with insufficient_scope | Client logs showing HTTP 403 with a WWW-Authenticate challenge naming scopes the current token does not hold. | A scope step-up is an authorisation change wearing a user-experience costume. Route it to the class owner. Never let the client silently re-consent. | Identity owner and class owner jointly | The challenge, the scope set before and after, and the approval for the increment. |
| Two principals see different tool lists | Periodic comparison of tools/list across a sample of principals and service identities. | Expected behaviour, not a defect — the current revision permits the set to vary by the authorisation presented. Approve the union across principals, not the view one reviewer happened to see. | Registered owner of the server entry | The per-principal manifests and the union set the approval actually covers. |
| Transport, endpoint or authorisation server changes | Configuration diff, plus a diff of the protected resource metadata document. | Full re-approval. For trust purposes this is a different server, even where the name and the tool list are unchanged. | Security review and platform owner | The configuration history and the new approval record with a new effective date. |
| Nothing has changed for the review interval | The calendar. Staleness is a trigger in its own right. | Periodic re-review proportionate to class ceiling: annually at read and search, semi-annually at write and send, quarterly where delete, deploy, transact or administer is enabled. | Class owner | The dated re-review, what was inspected, and what changed as a result. |
Two implementation notes make the difference between a matrix on a page and a control that operates. First, diff a normalised manifest — sort the tool array, strip volatile fields, hash the result — because otherwise ordering noise produces false positives until someone switches the job off. The specification helps here: servers should return tools in a deterministic order precisely so clients can cache reliably. Second, pin to something immutable. A container digest, or a published version in a registry that forbids republishing under the same string — the official MCP registry, for instance, requires a unique version per publication and does not permit a published version’s metadata to be changed. A pin to a moving tag is not a pin, and it fails silently, which is the worst way for a control to fail.
What a tool approval record has to contain
An approval record is not a ticket saying yes. It is the document a reviewer, an assessor or your successor reads in eighteen months to answer one question: was this call, on this date, within something a named person actually decided? Nine fields carry that weight. The third column is the version we most often find in place.
| Field | Why it is load-bearing | The weak version |
|---|---|---|
| Server identity and pin | The name is not the identity. The identity is the name plus the endpoint or command line plus the pinned version or image digest, because two of those three can change without the first one moving. | A row that says “Jira MCP” with no endpoint, no version and no pin — which cannot tell you next quarter whether you are running what you approved. |
| Tool name, namespaced | Tool names are unique only within a server. A host aggregating several servers can meet two tools called search, and the specification tells clients to disambiguate — so your record has to carry the server prefix too. | An approval for “search” with no server qualifier, which silently covers whichever server registered the name first. |
| Assigned action class and ceiling | The class is the unit approval attaches to, and the ceiling is the highest class the server may ever reach without a fresh decision. The ceiling is what makes a later capability change a governed event rather than a surprise. | A class assigned from the tool description, with no ceiling recorded, so a new administrative tool inherits the server’s original low-risk rating. |
| Executing credential and scope set | A tool can never be safer than the token it holds. Recording the scope set is what lets you say what the tool could do rather than what it is meant to do — and it is the field that makes a later step-up challenge legible. | A service account with an omnibus scope, recorded as “API access”. That is a description of a category, not of an entitlement. |
| Principal and delegation basis | Whether the call runs as the human, as a distinct agent identity, or as a shared service account. Attribution, revocation and every access review downstream depend on this one field. | A shared token used by several people and one scheduler, with no way to attribute a call to a person or a run. |
| Mediation rule | Standing approval, confirmation with the payload rendered, dual control, or excluded. This is the field that stops a read-only search approval from covering a destructive administrative call by accident. | An approval that says the tool is “allowed”, leaving the host’s default confirmation behaviour to decide how much of it is allowed. |
| Data classes and environments reachable | Governs whether the approval has to be re-taken when the same tool is pointed at production, or at a system holding regulated personal data, rather than at the sandbox where it was reviewed. | An approval taken in a demo tenant and inherited into production without a second decision. |
| Change regime and expiry | The clause that converts a snapshot into an approval: which events trigger re-review, at what depth, who decides, and the date the approval lapses if nobody looks at it again. | An approval with no expiry, which is indistinguishable a year later from an approval nobody has thought about. |
| Approver, date and basis | Who decided, when, and what they actually inspected — the manifest snapshot, the schema, the scope set. Basis is the field auditors ask for and the one most often missing. | A ticket that says “approved” with a name and a date and no statement of what was in front of the approver. |
The record belongs in the same register as the rest of the estate rather than in a separate spreadsheet, because the questions asked of it are the same questions asked of every other AI system entry: who owns it, what data it touches, what it can do, and when it was last looked at. A tool register that lives apart from the AI system inventory diverges within two quarters, in our experience without exception.
When SSO fronts MCP instead of authorising it
A pattern arrives in almost every enterprise rollout: put the servers behind the corporate identity provider, and treat the resulting session as the approval. It is attractive because it is real security — it removes personal tokens, it gives you revocation, it puts conditional access in the path. It is also answering a different question from the one being asked. Authentication establishes who the human is. It does not establish that this specific action was intended, that the agent may take it on the human’s behalf, or that the authority delegated is narrower than the authority held. Those are three separate decisions, and a session cookie makes none of them.
The protocol’s authorisation model is unusually helpful here, because it draws the boundaries in exactly the places governance needs them. It builds on OAuth 2.1, requires MCP servers to implement protected resource metadata under RFC 9728, and requires clients to implement resource indicators under RFC 8707 so that a token is issued for a named resource. Servers must validate that access tokens were issued specifically for them as the intended audience, must only accept tokens valid for their own resources, and must not accept or transit any others. The accompanying security guidance names token passthrough as an anti-pattern outright. Read those requirements as governance rather than plumbing and they say something simple: a token is a grant to one resource for one purpose, not a general credential the agent carries around the estate.
The same guidance addresses the confused-deputy problem directly, requiring proxy servers to maintain per-client consent and to check it before forwarding to a third-party authorisation server, so that an existing consent cookie cannot be used to skip a consent screen for a client the user never approved. And the scope model gives you a mechanism that maps onto the action-class ladder almost exactly: servers should publish a minimal scope set, challenge for more when a privileged operation is first attempted, and clients should request only what they need. A privileged operation producing an insufficient_scope challenge is the technical form of the governance event “this agent is asking to move up a class”. Treat it as such. The failure mode is a client configured to request the union of every scope at first connection, which converts an entire ladder into a single blanket grant on day one.
Two operational rules follow, and they are worth stating in the policy because both get argued. Delegated authority must be a strict subset of held authority — an agent acting for an administrator should not inherit administrative reach merely because its principal has it. That is what the class ceiling is for. And “the user could have done it manually” is not an approval basis. It is true of almost every action an agent takes, it proves nothing about intent, and at scale the difference between a human who could have deleted a thousand records and a process that did is the entire control. Where an agent runs on a schedule with no human in the session at all, it needs its own identity and its own grant, because there is no human session to borrow.
When a low-risk server acquires a high-risk tool
This is the case the whole page exists for, and it fails on ownership rather than on technology. A documentation server was approved eight months ago by a platform engineer as an obvious yes: three search tools, no writes, nobody argued. Its next release adds a publish tool that pushes content to a customer-facing site. The diff fires. And then it lands on a queue belonging to a team who assessed a search server, have no view on customer-facing publication, and can see that the original approval said the server was low risk.
Three mechanisms close the seam, and the first is the important one. The class ceiling governs, not the server’s original rating. A tool classified above the ceiling recorded for that server cannot be auto-approved by anyone, including the person who approved the server, because the ceiling is a statement about the limit of what that approval was ever able to cover. It is a deliberate ratchet: raising a ceiling is a fresh decision with a fresh approver, and the approver is chosen by the new class rather than by the old server entry.
Second, route by class, not by asset. The send class routes to whoever owns external communications, deploy routes to the change board that already exists, transact routes to finance, and administer routes to whoever owns the identity estate. That is the routing table that stops a platform engineer being asked to make a publishing decision, and it is a five-line addition to a policy that usually names only one approver.
Third, allowlist rather than deny-list. A deny-list is a list of the tools you happened to think of, and it is structurally unable to cover a tool that did not exist when the list was written — which is the exact event under discussion. An allowlist inverts the default: an unrecognised tool is unavailable until classified, so the failure mode is a support request rather than an unreviewed capability. The cost is a queue and the occasional Monday-morning complaint. The benefit is that the queue is the control operating, visibly, with a date on it.
One change, carried end to end
An illustrative sequence, with the dates that make it testable. Note where the exposure actually closes — seven hours in, at quarantine, not seven days later at the decision. The decision is for the record. The quarantine is the control.
| Approved | 9 March 2026 | A vendor-hosted MCP server for the issue tracker is approved for a support team. Fourteen tools, all read or search. Class ceiling recorded as Search. Pin recorded at the published version. Executing credential is a per-user token carrying two read scopes. Review interval annual, because the ceiling is Search. |
| Change detected | 12 June 2026, 02:14 | The nightly manifest diff returns a mismatch against the approved snapshot: seventeen tools, three of them new. Two are search variants, and one is a bulk transition tool that can move every issue matching a filter and, per its schema, close them. The host had received a list-changed notification eleven hours earlier. Nobody was watching that channel, which is why the diff is the control and the notification is the convenience. |
| Quarantine | 12 June, 09:05 | The three new tools are added to the host deny list. The fourteen approved tools stay available, so the support team is not blocked. This is the whole point of a class ceiling: the change is contained without an outage, and nobody is under pressure to wave it through. |
| Classification | 15 June | The two search variants are classified Search and inherit the standing approval. The bulk transition tool is classified Write, then raised to Delete on the bulk rule, because its filter argument is unbounded and closing an issue is not reversible in the tracker’s workflow. That is above the recorded ceiling of Search, so it cannot be inherited. |
| Decision | 19 June | The support lead declines the bulk tool for the support team and requests it for a single named operations account with a confirmation prompt and a fifty-issue limit enforced by the tracker rather than by the agent. Approval is recorded against that principal only. The server ceiling for the support team stays at Search. |
| What the record shows afterwards | 30 June, period end | One detected change, one quarantine, one classification, one scoped approval, one declined request, and an unbroken pin history. Seven days from detection to decision, with the exposure closed in seven hours. The counterfactual is the version of this page nobody writes: the tool arrives, inherits the server’s approval, and the first anyone hears of it is a bulk closure nobody ordered. |
What an assessor actually requests
Whether the examination is a SOC 2 under AT-C 205 or an ISO/IEC 42001 certification audit, the first request is not a screenshot of your policy. It is a population, because a sample drawn from an incomplete list proves nothing about the list it came from. There are three populations here and teams usually have only the first.
| The request | What satisfies it | What gets rejected |
|---|---|---|
| Define the population of approved tools | A system-generated export of the tool register at period start and at period end, with the query, the filter and the record count visible, reconciled against the tool manifests captured from each connected server on those dates. | A hand-maintained spreadsheet with no extract date. A register that lists servers but not tools, which cannot answer a question asked at tool level. |
| Prove the register is complete | Reconciliation of the register to an independent source — the host or gateway configuration inventory, the identity provider’s list of granted applications and service principals, and network egress records for remote servers. | A register that omits locally configured servers on engineer laptops, or one that cannot account for a service principal seen in the identity provider. |
| Show the population of capability-change events | The manifest-diff history for the period, one entry per detected change with before and after hashes, plus the pin history for every server. Where change notifications are used, the client-side log of received notifications alongside the polled diffs. | Reliance on notifications alone. Emitting them is a SHOULD conditioned on the server declaring the capability, and under the current revision they reach only clients that opened a subscription stream asking for them — so silence is indistinguishable from stability. |
| Show the control operated on selected changes | For each selection: the diff, the quarantine or classification decision, the approver, the date, and the resulting register entry — with the decision date after the detection date and before the tool became callable. | A classification recorded after the tool had already been used. A decision date that precedes the detection date, which usually means the record was assembled later. |
| Show mediation held for the higher classes | Host or gateway policy configuration captured at two or more in-period dates, the change history proving it was not relaxed between them, and call logs for send, delete, deploy, transact and administer showing a confirmation event paired to each call. | A single screenshot of today’s settings. A call log with no principal, or one that records the tool name but not the arguments class. |
| Reconcile calls to approvals | The period’s tool-call log joined to the register, demonstrating that every tool actually invoked had a current approval at the time of the call, and that no call fell outside its approved class. | A log that cannot be joined to the register because calls are keyed by an internal identifier the register does not carry. |
On sampling, the arithmetic is the same as anywhere else and it bites in a specific place. Capability-change events are an event-driven population you have to bound before anything is drawn: a six-month period across a dozen servers might produce eight change events, which is small enough that the firm tests all of them, and a single change handled after the fact is then a known deviation rather than an estimate. Approval records are tested against the register population. Mediation is tested as a configuration control — captured at two or more in-period dates, with the change history proving it was not relaxed in between — which is the same treatment any automated enforcement receives.
One point specific to SOC 2. If connected agents are inside the system boundary, the description criteria at DC 200 expect the description to cover the system as it was during the period, including significant changes made to it. A tool set that expanded in month four is a change to the system, and a description written in month one that never mentions it is inaccurate rather than merely brief. Decide early whether the agent stack is inside the boundary, and where a third party operates the server, whether it is a vendor managed under CC9.2 or a subservice organization with the carve-out or inclusive treatment that follows.
The edge cases that generate the questions
The ladder and the matrix cover the ordinary eighty per cent. These are the cases where two competent people disagree, and where settling the answer before it is urgent is worth several days.
The bulk variant of an approved tool
A tool that updates one record and a tool that updates ten thousand are the same class on paper and different risks in practice. Volume is a dimension of consequence, not a detail of implementation. The workable rule is that a batch or bulk tool sits one class higher than its single-object equivalent, and that any tool accepting an unbounded selector — a filter, a query, an “all matching” flag — is classified on what the selector can reach rather than on what it usually reaches.
The composite tool
Some tools do several things depending on an argument: an action parameter with values like get, update and archive, or a generic endpoint that proxies an arbitrary API path. There is no single class for such a tool, and picking the average is the worst available answer. Classify at the ceiling of what the schema permits, or ask the server owner to split it. A tool that takes an arbitrary path and an arbitrary method is not a tool at all for approval purposes. It is an unrestricted client.
The tool whose danger is in its output
A read tool that returns content sourced from outside your organisation — a web page, an inbound email, an issue comment filed by a stranger — is read-only in the sense the annotation means and hostile in the sense that matters. It cannot change state itself. What it can do is place instructions into the context that the next tool call obeys. Prompt injection sits at the top of the current OWASP list for LLM applications for this reason. The control is not to reclassify the read tool but to require that no unmediated write, send, delete or administer tool is enabled in the same session as an untrusted-content reader.
A locally installed server on an engineer’s machine
Locally configured servers run with the user’s own privileges, are usually invisible to a gateway inventory, and are the most common reason a tool register is incomplete. The specification’s security guidance asks clients to show the exact command before a one-click local install, precisely because the command is the payload. Governance that only inspects the managed gateway is governing the part of the estate that was already the least exposed.
The approval was taken in a sandbox tenant
Reviewers test against a demo project because it is safe, and then the same server is pointed at production. Nothing in the manifest changes, so no diff fires, and every downstream record still says approved. Environment belongs in the approval record as a first-class field, and a change of environment is a change of approval — the same discipline any organisation already applies to a database credential.
The server operator changes hands
An open-source server acquires a new maintainer, or a vendor is acquired. The endpoint is the same, the manifest is the same, the pin may even be the same until the next release. This is a third-party risk event rather than a technical one, and it is detected by watching the supplier rather than the wire. Where the server sits above the read class, it belongs in the vendor register with a named reviewer, not only in the tool register.
Two servers offering the same tool name
Aggregating hosts can meet two servers each exposing a tool called search or delete. The specification notes that tool names are unique only within a server and that aggregators should disambiguate, and it is explicit that the server name is not a reliable disambiguator either. A register keyed on the bare tool name will eventually approve one server and permit another. Key on the pair, and have the host prefix names before they reach the model.
The third of those — the read tool that returns hostile content — is the one that most often changes how a team designs sessions rather than tools. It is covered in its own right under prompt injection once tools are connected, and the ability to stop a run mid-flight belongs with kill switches and circuit breakers.
What gets pushed back on and the answer
These seven arrive in roughly this order, half of them from your own engineering team and half from a customer’s security reviewer. The difference between a good answer and a defensive one is, as ever, specificity.
“Approving every tool individually is unworkable. We have hundreds.”
Agreed, and that is not what is being proposed. Every tool is classified. Approval attaches to the class. Classification is a five-minute inspection of the schema and the credential, most of which can be templated across a server, and it is the only per-tool step. Approval is then a decision taken once per action class per environment, and everything landing in that class inherits it. The failure mode you are describing — a queue of hundreds of individual approval tickets — produces approval fatigue, which is itself a control failure because people stop reading before they click.
“The server is read-only. Why does it need a change regime?”
Because read-only is a statement about today. The property that makes MCP useful is that a server can extend what it offers, and the protocol carries a notification for exactly that event. The specification’s own security guidance describes a scenario where a client ends up with tools it was not aware were enabled. So the question is not whether the server is read-only but what happens on the day it is not, and whether anyone would know. A read-only server with a recorded class ceiling, a pinned version and a monthly diff costs almost nothing and answers that question in advance.
“Our SSO covers this. Users authenticate with corporate identity.”
Single sign-on establishes who the human is. It does not establish that the human intended this action, that the agent may take it on their behalf, or that the authority delegated is narrower than the authority held. Those are three separate decisions and SSO answers none of them. In protocol terms the relevant requirements sit elsewhere: tokens must be audience-bound to the server they are presented to, servers must not accept tokens issued for something else, and scope challenges exist so that a privileged operation triggers a fresh, specific grant rather than riding an existing session.
“The tool is annotated read-only. That is our classification.”
The annotations are useful and they are hints. The specification says so in the schema itself — they are not guaranteed to describe behaviour faithfully — and it requires clients to treat them as untrusted unless the server is trusted. The defaults are worth knowing when you rely on their absence: an unannotated tool is treated as potentially destructive and open-world. Use the annotation as a signal, then set the class from the input schema and from what the executing credential can actually reach, because those two are the things an attacker also has to work with.
“We pin the version. That covers capability change.”
Pinning is the strongest single control here and it covers one of two directions. It stops the server changing under you without a deliberate act. It does not stop the tool list changing while the pin holds — a remote server can vary its offering server-side, and the current revision explicitly permits the set to differ according to the authorisation presented. Pinning also fails quietly when the pin is a moving tag rather than an immutable reference. Pin to a digest or an immutable published version, and keep the diff running anyway. The two controls answer different questions.
“Nobody will maintain a tool register.”
True where the register is a document kept alongside how access actually works. It stays current where it is load-bearing: the register entry is what causes the server to be enabled in the host or gateway configuration, so an unregistered server is an unreachable one. Where full enforcement is not yet possible, a monthly reconciliation between the register and the host configuration is the minimum, and the reconciliation exception list is the thing to review — not the register itself.
“This is over-engineering for a productivity feature.”
It would be, at the read and search classes, and that is why those classes carry standing approval and no queue. The structure exists for the other six. A tool that can send, delete, deploy, transact or administer is a privileged integration with a natural-language front end, and would have gone through change and access review under any name other than the current one. The test we apply is whether the same action, performed by a script with the same credential, would have needed a change record. If it would, the tool needs one too.
A note on how this page is written, because it matters for what you do next. Host and server behaviour in this space changes quickly — which client honours which annotation, what a given product does with a change notification, which plan tier carries which controls. The protocol requirements cited here are drawn from the specification as published at the time of writing. Product behaviour is not asserted at all. Verify both against current vendor documentation for the hosts you actually run, whether that is Claude Code, Cursor, GitHub Copilot, a Copilot Studio agent or an in-house client, and record the date you verified it in the approval record.
Frequently Asked Questions
Does every MCP tool need individual approval?
Why separate read from search if both are read-only?
What is the capability-change problem in MCP?
Can we rely on tool annotations to classify risk?
How do we detect that an MCP server has changed its tools?
What should a tool approval record contain?
Is corporate SSO enough to authorise agent tool use?
What happens when a low-risk server adds a high-risk tool?
Do we need to approve tools per environment as well as per class?
How does any of this map to SOC 2 or ISO 42001?
Related Reading
MCP Server Security and Governance
An MCP server is closer to a privileged integration than a browser extension. What review it deserves.
Read morePrompt Injection Once Tools Are Connected
Injection stops being a content problem and becomes an action problem. The controls that reduce blast radius.
Read moreAI Agent Identity and Delegated Authority
Human authority and authority-to-delegate are different things. Why agents need their own identity.
Read moreThe Ten Questions That Govern Any AI Agent
Scope, ownership, data, capability, identity, oversight, failure detection, evidence, reassessment and how to stop it.
Read moreISO 42001 Knowledge Hub
AIMS controls, EU AI Act mapping, risk assessment and guides.
Read moreISO 42001 (AI Management)
The world's first AI management system standard, for AI builders.
Read more