Winslow Homer watercolour of a boy waiting beside a beached dory, used as the article cover
← Back to blog

DEEP DIVE

MCP, OAuth, and the Agent Permissioning Problem

MCP standardizes how agents call tools. OAuth standardizes how apps get tokens. Neither decides whether a specific agent should take a specific action for a specific user right now.

•May 11, 2026•Updated Sep 7, 2026•8 min
MCPOAuthIdentity

TL;DR

MCP standardizes how an agent talks to a tool. OAuth standardizes how an app gets a token. Neither one decides whether a specific agent should take a specific action for a specific user right now, and that decision is what actually breaks in production.

Both protocols do real work. MCP means a Claude agent and a custom agent can call the same tool server without bespoke glue; OAuth means nobody has to invent their own credential exchange. Neither was built to answer who this agent is acting for, whether this exact action is allowed, or how a revoked user's access gets pulled from every live agent session at once.

Teams that treat that gap as someone else's problem end up with permission logic scattered across every MCP server they connect, each one enforcing its own rules with no shared audit trail and no single place to cut off access.

The fix is a layer that sits between the agent and the tools: it resolves identity, checks the action against what both the user and the agent are allowed to do, mints a narrow credential, and logs what happened.

Overview

MCP and OAuth solve two real, separate problems, and it's easy to assume that between them the access question is settled. MCP gets an agent and a tool speaking the same wire format. OAuth gets that connection a credential. Put the two together and you have a working integration, which is exactly the moment teams stop asking the harder question.

A companion post in this series covers why OAuth alone falls short for agents generally; this one is narrower and specific to agents that call tools over MCP, since MCP servers are usually where teams first discover the gap, one server at a time, each with its own auth story.

The question neither protocol answers: should this particular agent, acting for this particular user, be allowed to take this particular action, right now. That's the permissioning problem, and it's the gap teams hit moving from a demo to something running in production.

MCP and OAuth are protocols. Permissioning is a decision. We think of it that way deliberately: neither protocol was built to make that decision, and something has to.

What MCP Solves

MCP is the contract that lets any agent talk to any tool. It defines how a tool advertises what it can do, how an agent discovers those tools, how a request and its response are structured, and how authentication metadata gets carried alongside the call. Before MCP, every agent framework had its own tool-integration story, bespoke glue between one specific agent and one specific API. After MCP, the wire format is consistent enough that a Claude agent and a custom-built agent can call the same tool server without either one knowing anything special about the other.

That's a genuine, useful standardization, and it's easy to mistake for more than it is. MCP describes how the conversation between agent and tool is shaped. It says nothing about whether the conversation should be happening in the first place.

What MCP Leaves Open

MCP standardizes how an agent and a tool talk. It doesn't opine on who this agent is acting on behalf of and how anyone would know, whether this user actually authorized this specific action rather than just installing the app, what organizational rule applies and who's checking it, how every live agent session gets cut off the moment a user offboards, or where the record lives of what the agent actually did.

Those are permissioning questions, and MCP servers can each answer them on their own. In practice that's exactly what happens: one server built by one team makes its own decisions about identity and access, a second server built by a different team makes different ones, and an organization running a dozen MCP servers ends up with a dozen inconsistent answers to the same set of questions. We think the result is predictable: no shared audit trail, no consistent notion of what a given user's agent is allowed to touch, and no way to revoke access in one place instead of a dozen.

Why Raw OAuth Falls Short

OAuth is the natural starting point for authorization, and most MCP servers bolt it on. The general case for why OAuth alone isn't built for autonomous agents is covered elsewhere in this series; applied specifically to MCP, three gaps matter most.

Scope granularity is app-level, not action-level. "Send a Slack message" is one scope whether the channel is one the agent's user already belongs to or one it's never seen. For a person clicking a button, that's fine, because a human decides in the moment. For an agent choosing its own next step, those are different actions that deserve different treatment, and OAuth has no vocabulary for the difference.

The identity model stops at the application. A standard OAuth flow produces a token tied to a user or to an app, not to a specific agent acting on a specific user's behalf. Without that finer identity, an audit trail can say which app made a call and nothing about which agent, serving which user, actually made the decision, and revocation ends up all-or-nothing: pull the app's access entirely, or leave everything running.

And revocation is slow relative to how fast an agent can act. OAuth tokens carry TTLs measured in minutes to hours, and refresh tokens live longer than that. A leaked or misused agent credential can stay active well after a user thinks they've revoked access, unless something checks current permissions on every call rather than trusting a token that was valid when it was issued.

Agent

Permissioning layer

resolve: which agent,
acting for which user

check: user scope
and agent scope

mint short-lived,
narrowly-scoped credential

MCP server A

MCP server B

audit record

Permissioning layer -> resolve which agent, acting for which user -> check user scope AND agent scope (intersection) -> mint a short-lived, narrowly-scoped credential -> forward to the actual MCP server, whichever one -> every call writes an audit record, in one place -->

Figure 1 — A permissioning layer sits between the agent and every MCP server, so identity, scope, and audit are decided once instead of once per server.

The Permissioning Pattern

The pattern that closes the gap is inserting a layer between the agent and the tools, whatever protocol those tools speak. That layer authenticates the agent and resolves which user it's acting for. It pulls that user's real permissions from wherever the organization already keeps them, an identity provider most teams already run. It checks the requested action against both the user's scope and the agent's own, separately, and proceeds only when both agree. It mints a short-lived, narrowly-scoped credential for the downstream call rather than handing the agent a long-lived token it can reuse indefinitely. And it writes an immutable record of what was requested, what was decided, and what happened, before the call ever reaches the tool.

Re-checking on every call is what makes revocation fast. A token that was valid an hour ago and a permission that's still valid right now are different claims, and the second is the one that matters once an agent is making a hundred calls a day instead of a person making ten.

The detail teams skip first, usually under deadline pressure, is that re-check on every call rather than at token-issuance time. It's more work up front. It's also the only version of this that makes "revoke this user's access" mean something real across every agent session running at that moment, instead of something true eventually, whenever each token happens to expire.

Building vs. Buying This Layer

Teams building this today choose between assembling it themselves and adopting something that already does it. Assembling it means wiring together an identity provider for the permissions lookup, a broker that mints and forwards short-lived credentials, and a logging pipeline that ties requests back to users and agents, then maintaining all three as the number of connected tools grows.

Agentic Fabriq is one of the platforms built for the other option: it resolves the agent and the user on each request, evaluates the action against the intersection of what both are separately permitted to do, injects a short-lived credential from a vault at the moment of the call, and writes the result to an audit log. We'd argue the pattern matters more than which option a team picks; that's one implementation of it, not the only one.

Conclusion

MCP solves the protocol question: how an agent and a tool talk to each other. OAuth solves the handshake: how that connection gets a credential. Neither one decides whether a specific action should happen, attributes it to the user it was taken for, or leaves a record once it's done. That's permissioning, and it's a separate layer, not a setting inside either protocol.

Teams that build that layer as a first-class piece of the architecture, rather than an afterthought bolted onto whichever MCP server broke first, are the ones that get agents into production and keep them there.

A protocol tells you the call is well-formed. It was never going to tell you whether the call should happen. That's the layer this post has been describing, and it's worth building before the first incident makes the case for you.