# MCP v2 Improves Agent Access Control and Still Cannot Say Who Decided

_MCP revision 2026-07-28 improves two of the three identities behind every agent action: the agent making the call and the account whose permissions it uses. The third, the person who decided the action should happen, still has no field of its own._

By Gil Röder, CPO & Co-Founder  
Published: 2026-08-10  
Source: https://www.cakewalk.security/blog/mcp-spec-agent-access-control-accountability

---

## TL;DR

- The Model Context Protocol, or MCP, is the standard that lets an AI agent access the apps a company already runs. The revision published on July 28, 2026 makes it cheap for a server to check on every request whether the call is allowed.
- Every agent action involves three identities: the agent making the call, the account whose permissions it uses and the person who decided it should happen. Revision 2026-07-28 makes the agent explicit and the account was already there as an OAuth token, while the person has no field at all.
- MCP accounts for the person in exactly one place: an approval that pauses a task mid-flight. There the server must verify who is answering and must not take the client's word for it.

**Bottom line:** MCP keeps getting better at checking whether a call is allowed while it still defines no field for the person who decided it.

The people who maintain the [Model Context Protocol](https://www.cakewalk.security/glossary/model-context-protocol) ([MCP](/glossary/model-context-protocol)), the standard that lets an AI agent access the apps a company already runs, documented an attack against it. It sits in the specification next to its fix, a requirement that the same person start and finish an approval, and both have been there since late 2025.[1][2] The newest revision, published July 28, 2026, is the reason to look at both again, because it improves what the protocol can check and leaves what it cannot record unchanged. MCP keeps getting better at saying whether a call is allowed. It still cannot say which person decided the call should happen.

The attack has two characters: Alice wants access she should not have, and Bob is about to hand it to her.

Alice and Bob work at the same company. Between their agents and the company CRM sits an MCP server. When Alice asks her agent to work in that CRM, nothing happens until a person signs in and approves the access. The protocol forbids collecting a sign-in through the agent, so the MCP server sends back a web link where the approval can happen, and Alice's agent puts that link on her screen.[1]

Alice sends the link to Bob, who opens it, signs in and approves. Nothing looks wrong to him, because the page belongs to the real vendor and the account being connected is his own. But the flow he completed is the flow Alice started, so the access lands with her. From then on, Alice's agent works inside the CRM holding Bob's permissions. The CRM's records show Bob's account at work. The MCP server's records show Alice's approved flow behaving as intended. Neither record is wrong, and neither tells anyone what happened. The specification's name for the result is account takeover.[1]

### How the Approval Handoff Takes Over an Account

_Because the flow Bob finishes is the flow Alice started, the access lands with her agent, and both records still read as normal._

_Figure: The approval handoff attack. Alice's agent requests CRM access, Alice forwards the approval link to Bob, Bob signs in and approves with his own account and the access lands with Alice's agent holding Bob's permissions. The CRM logs Bob's account and the MCP server logs Alice's approved flow, so neither record is wrong and neither says what happened._

The rule that defeats the attack is one sentence long. The server must make sure that the person who started an approval is the person who finished it.[1] The mitigation shipped in the same revision that introduced the flow, which says something good about the people doing the writing.

Outside that rule, MCP never requires anyone to establish which person is acting. Every agent action involves three identities: The first is the agent making the call, the piece of software the protocol calls the client. The second is the account whose permissions the call uses. Last comes the person who caused the action, by asking for it, approving it or clicking a button. Revision 2026-07-28, which practitioners call MCP v2, makes the first identity explicit on every request. Identity two, the account, already traveled on every request as an [OAuth access token](https://www.cakewalk.security/glossary/oauth). Identity three has no field at all. Everything the revision improves lands on the first two identities, and everything an auditor asks about lands on the third.

### What Travels With Every Tool Call

_The agent and the account both ride along on the request. The person who caused it has no field to travel in._

_Figure: The three identities in one MCP tool call. The agent is named by the client name that revision 2026-07-28 added. The account is carried by the OAuth token that already traveled. The person has no field at all._

## Checking a Call Got Cheaper

Until this revision, an MCP client and server opened every conversation with a handshake. The agent's client introduced itself and its capabilities, the two sides agreed on a protocol version, and the server could hand back a transport session identifier that later requests repeated. That context lived on the transport connection between the two, so anything in the middle, such as an [MCP gateway](https://www.cakewalk.security/glossary/mcp-gateway), had to remember it, keep the memory alive across restarts and hope it never drifted out of date.[3]

Authorization was never inside that handshake. The credential already traveled with every request. What lived on the transport connection was the context around the credential, and any implementation that checked a caller once and then reused the answer for the rest of the conversation was leaning on that context.

Revision 2026-07-28 removes the handshake and the transport session entirely. Every request now carries its own protocol version and the client's declared capabilities, and each is expected to name the client sending it, so a request explains itself.[3] The shorthand for the change is stateless, and the word fits the transport only. A server that holds a credential still stores it against a person, which the specification says outright. [1]

The revision then makes each request readable from the outside. The facts needed to route a request move into HTTP headers: the protocol version, the method being called and the name of the MCP tool, resource or prompt it targets. A call to a tool named `execute_sql` announces itself as exactly that before anything opens the request body. The specification states the purpose plainly, saying the headers exist so load balancers, gateways and observability tooling can route and inspect requests without parsing the body.[4] The maintainers offer an example of the payoff: a remote MCP server that once needed sticky routing and a body-parsing gateway can now sit behind a plain round-robin load balancer.[5]

Read the headers closely, though, before deciding the identity problem is solved. The headers make it cheap to see which method is running and which tool it targets. They do not say who wanted it. The client name identifies the agent's software rather than a person. The token identifies an account, and often only after an authorization server unpacks it. Nothing standardized in the request says a specific human wanted this call to happen.

One part of the job got more expensive. The shortcut from earlier, checking a caller once and reusing the answer for the whole conversation, depended on the transport session, and the transport session is gone. Nothing ties one request to a check done before it, so a server must evaluate every request on its own, and an agent produces far more requests than a person clicking through an app ever did. The Agentic AI Foundation, the Linux Foundation fund that hosts MCP, is blunt about this in its migration guidance: "The answer has to be produced on every request, or it is not being produced at all."[6][9] The revision made the facts of a call cheap to read. Deciding whether the call is allowed, every time, remains real work, and it now falls on every MCP server a company runs.

## Only the Approval Flow Carries the Person

The protocol does account for the person in exactly one place. That place is a mechanism called elicitation, which a server uses to pause mid-task and ask a person for something, most often an approval. The Alice and Bob rule lives there. While one of these approvals runs, the server must verify which person is answering, and it must not take the client's word for it, because a client can forge that claim.[1]

Those requirements cover approvals and nothing else. An ordinary tool call, the request that does an agent's actual work, carries the first two identities, the agent and the account, and has no place for the third.

That absence would matter less if a person never acted inside an agent's work directly. MCP Apps, an extension to the protocol, exists to make exactly that happen. It lets a server hand back a working interface instead of text, a dashboard rendered inside the conversation, and a person uses it the way they use any interface, by clicking. The click becomes a tool call that the app asks the host, the chat product rendering it, to send on its behalf.

Compare two ways the same deletion can happen. The agent decides on its own that a customer record must go, and the server receives a tool call. Or a person reads the dashboard, decides the record must go and clicks delete, and the server receives a tool call. The two messages are identical, because the extension specification defines no field, no metadata key and no annotation that says a person clicked.[7] The host did see the click, but it has no agreed spot in the message to write that down, and a note written outside the agreed spots is a note other vendors' software never reads. So the difference between "a person chose this" and "the model chose this" exists for a moment inside the host, and travels no further. The log then tells a small lie, because a person decided and the record names the agent.

### Why a Person's Click Arrives as an Agent's Action

_Because the extension defines no field for the click, both paths reach the server as the same message._

_Figure: Two routes to the same deletion: the model deciding on its own and a person clicking Delete inside an MCP App. Both reach the server as identical delete_record calls, so the audit record names the agent either way._

## The Approval Check Belongs With the Credential

Approval flows carry a trap of their own, and a product can fall into it by accident. When the approval happens on a web page, the way Alice and Bob's did, the real approval happens on the page, after the person signs in there. The client reports the word `accept` much earlier, at the moment the person merely agrees to open the page, and it never directly learns what the person did once the page opened, which the specification spells out.[1] So a product that treats `accept` as approval granted will execute sensitive actions because a person opened a browser tab, while the person may have closed it, failed the sign-in or clicked deny. Only the server can know the real outcome, and it has to wait for that outcome before it acts.

The question behind the trap is who has the power to stop the action. [Hermes](https://www.cakewalk.security/blog/hermes-agent-yolo-mode-attack), an open-source agent framework with more than 140,000 GitHub stars, shipped a default it called smart approvals. A second model rated each flagged command, cleared the low-risk ones, denied the clearly dangerous ones and put the uncertain ones to a person. That rating ran inside the agent's own software, where its configuration controlled it. An attacker ran the agent on their own infrastructure, so switching it to YOLO mode was a setting change, and the prompts stopped. Nothing downstream noticed, because nothing downstream had ever demanded an approval. The agent mapped a government ministry's systems, listed the programs running with elevated privileges and reached a web directory of personnel records going back to 2012. Investigators saw no sign that those files left the network, and the ministry had no checkpoint of its own that would have caught any of it. The safety check lived in the same software the attacker controlled.

An [MCP gateway](/glossary/mcp-gateway) that holds the credential does not have that weakness. An agent can only access an app through the gateway, because the gateway holds the only key. When the gateway decides an action needs approval, it holds the request, asks the person and forwards nothing until the answer comes back. No setting on the agent's side changes that, because the check does not run on the agent's side. Whoever holds the key can enforce a rule; everyone else can only promise to follow one. Holding the only key cuts both ways: [the gateway becomes the most valuable target a company runs](https://www.cakewalk.security/blog/ai-gateway-security-attack-surface), and the tradeoff is one hardened, watched credential store in place of an unwatched copy at every server.

## Per-Server Enforcement Scatters the Record

The revision strengthens each individual MCP server as a place to enforce rules. Because credentials arrive as input on every request, a server may now scope the tool list it offers to the authorization presented, showing a caller only the tools its granted permissions allow.[8] For a company with one app behind one MCP server, that is the whole problem solved, with the rules, the log and the credential all living in one place.

Almost no company looks like that. An agent doing real work accesses the CRM, the ticketing system, the file store and the data warehouse, and each of those apps sits behind its own MCP server. Enforcement inside each server means every server carries its own copy of the company's rules. Someone has to repeat a rule change in every one of them, and when an admin misses a copy, that server keeps enforcing the old rule and nothing signals the gap until an audit compares the copies.

The logging splits the same way. Each server writes down only what happened in its own app, so the question an auditor asks first, what one agent did for one person across everything it accessed, has no single place where the answer exists. Someone has to collect four logs in four formats and merge them after the fact.

The credentials multiply as the servers do. Each server stores its own credential for its own app, so credentials sit ready in four places instead of one, and stored credentials are the first thing an attacker goes looking for.

Distributed tracing sounds like the fix for the scattered logs, and it is not. The revision documents support for OpenTelemetry, which stamps each request with an identifier that travels with it across systems.[3] That identifier links records that already exist, the way a case number pulls together documents filed in different departments. The Agentic AI Foundation draws the line in one sentence: "W3C Trace Context is the correlation layer, not the [audit trail](/glossary/audit-trail) itself."[6] Nothing in it makes a server write a record or says what a record must contain, so where a server wrote nothing there is nothing to link.

## Assembling the Record Stays Somebody's Job

The scattered record is not a flaw in the protocol. A wire protocol standardizes how two programs talk to each other, and a company-wide account of who did what was never in its scope. The job exists anyway, and leaving it unassigned does not make it go away.

That job is why Cakewalk's MCP Gateway, the enforcement point between a company's agents and the apps they access, sits where it sits. Each governed action reaches the gateway before it reaches the app. The gateway checks the action against one set of policies rather than a copy per server, and it blocks the action when a policy denies it. It attaches the credential on its own servers, which is why the agent never holds a token it could leak and no tokens pile up across servers. And for every call it rules on, it writes one [audit event](https://www.cakewalk.security/glossary/audit-trail) naming the person who delegated the work, the agent as it identified itself, the app the call targeted and the policy behind the ruling. The gateway can name the person because it created the delegation. The person connected the agent through the gateway, so the gateway recorded who that agent acts for before any call was made, and no call has to carry that fact. The same delegation carries what the company's HR system and [identity provider](/glossary/identity-provider) already know about that person, so a policy can test department, seniority, tenure or jurisdiction before the call goes through.

Approvals run outside the agent's control, at the gateway, which holds the action and puts the question to the person who delegated the work. A decline denies the call, and so does five minutes of silence.

The audit event always names the person who delegated the work, and when a call paused for approval it records what that same person answered, because the question goes to the delegating user and nowhere else.

So the balance after revision 2026-07-28 is this. Every MCP server can now check whether a call is allowed, on every call, at low cost. No MCP server can produce the combined account of one agent's work, meaning this agent, acting for this person, did these things across these apps. That combined account is what we described in [our working model for governing agent access](https://www.cakewalk.security/blog/human-agent-system-working-model-governing-agent-access), where every action traces from the person through the agent to the system it accessed. The protocol will not produce it, so a gateway has to, and that is the product we build. One gap stays open even then, because it belongs to the standard. An MCP App can turn a person's click into a tool call that names only the agent, and no gateway can see past that. The rest is somebody's job to assemble, and this revision did not hand it to the protocol.

## References

1. Model Context Protocol, Elicitation, revision 2026-07-28. <https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation>
2. Model Context Protocol, Elicitation, revision 2025-11-25. <https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation>
3. Model Context Protocol, Key Changes, revision 2026-07-28. <https://modelcontextprotocol.io/specification/2026-07-28/changelog>
4. Model Context Protocol, Streamable HTTP, revision 2026-07-28. <https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http>
5. David Soria Parra and Den Delimarsky, "The 2026-07-28 MCP Specification Release Candidate," Model Context Protocol Blog, 2026-05-21. <https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/>
6. Adora Nwodo and Arushi Garg, "Governance as Infrastructure," Agentic AI Foundation, 2026-07-30. <https://aaif.io/blog/governance-as-infrastructure-what-the-mcp-2026-07-28-migration-actually-demands-of-permissions-a>
7. Model Context Protocol, MCP Apps extension specification 2026-01-26. <https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx>
8. Model Context Protocol, Tools, revision 2026-07-28. <https://modelcontextprotocol.io/specification/2026-07-28/server/tools>
9. Model Context Protocol Blog, MCP Joins the Agentic AI Foundation, 2025-12-09. <https://blog.modelcontextprotocol.io/posts/2025-12-09-mcp-joins-agentic-ai-foundation/>
