MCP Authorization: Securing Model Context Protocol Servers With Fine-Grained Access Control | Cerbos
MCP authorization: Securing Model Context Protocol servers with fine-grained access control
AI agents and large language models (LLMs) are rapidly evolving beyond simple question-answering. With the advent of the Model Context Protocol (MCP), these agents can now directly interact with external tools, databases, and APIs - essentially taking actions rather than just returning text.
This new capability unlocks powerful use cases, but it also introduces a critical challenge: how do we control “who can do what” on these MCP-connected tools? In other words, how do we enforce fine-grained authorization for AI agents operating via MCP? Ensuring proper MCP authorization is crucial to prevent unintended or malicious actions by AI agents and to protect sensitive data.
In this article, we’ll explain what MCP is and why securing MCP servers is so important. We’ll then explore the role of fine-grained authorization in mitigating MCP security risks (with real examples of what can go wrong), and how a solution like Cerbos can help implement dynamic, scalable access control for MCP servers.
What is the Model Context Protocol (MCP)?
Model Context Protocol (MCP) is an open standard, introduced by Anthropic in late 2024, that defines how AI agents, like chatbots or autonomous assistants, can connect to external data sources, tools, and services in a standardized way. Think of MCP as a specialized API for AI: instead of a typical API where one software system talks to another, MCP allows an AI agent or LLM to “talk” to databases, applications, and other resources on your behalf.
MCP has gained rapid adoption in the AI industry. In fact, it was so useful that even OpenAI adopted it as a standard interface for tools, and within months there were already thousands of MCP servers available from various vendors to enable AI assistants to connect with different services.
Gartner analysts predict that by 2026, more than 80% of independent software vendors will have embedded GenAI capabilities in their enterprise applications, underscoring that MCP is on track to become a ubiquitous AI integration standard.
It’s easy to imagine the power here. An AI employee assistant could, for example, have an MCP connection to your HR system to look up employee info, your finance system to log expenses, and your DevOps tools to create tickets or deploy code. However, with great power comes great responsibility - and risk. Handing an AI agent the keys to various internal systems can be dangerous if not managed properly.
Why MCP servers need strong security and authorization
Exposing internal tools or sensitive operations through an MCP server is not without risk. By design, MCP makes it easier for an AI agent to perform actions in your environment, some of which could be high impact, like modifying a database, initiating financial transactions, or controlling system settings. If an AI agent or an unauthorized user can invoke the wrong tool without checks, the consequences could be severe.
In practice, we’ve already seen early security incidents with MCP integrations.
For instance, when Asana launched an MCP server for its Work Graph data, within a month security researchers discovered a bug that allowed users to access other users’ data - essentially a data leakage vulnerability. Around the same time, Atlassian’s MCP server was found to have a flaw that allowed attackers to submit malicious inputs, like forged support tickets and gain privileged access they shouldn’t have. Most recently, a Supabase MCP-related incident surfaced as well.
The MCP-related risks were taken so seriously that OWASP even launched an “ MCP Top 10” security project to track common MCP vulnerabilities. In short, a poorly secured MCP server can become a new attack vector in your infrastructure.
Beyond specific bugs, the general attack surface expands with MCP. Each tool an MCP server exposes is a potential avenue for misuse if not tightly controlled. Normal API security measures such as authentication, rate limiting, etc., still apply, but there’s a new twist: AI agents might be acting on behalf of human users with varying permissions. This means we need to ensure the agent can only do what that user is allowed to do - or more securely, an attenuated set of permissions for the specific use case, derived from the original user who called the agent.
Imagine an AI assistant that has access to a finance database: a regular employee’s AI assistant should perhaps read records but not create payments, whereas a manager’s assistant might initiate a purchase order but only up to a certain amount. If the MCP server doesn’t enforce these distinctions, the AI agent could overstep its authority. Effective authorization is the safety net that prevents accidents or abuses.
To sum it up, MCP servers need strong, fine-grained security controls because they bridge powerful capabilities into the hands of AI agents. Without proper guardrails, you risk data breaches, unauthorized transactions, and a loss of control over your systems. Given how quickly MCP is being adopted and its paradigm shift in how applications integrate with AI, establishing robust authorization from day one is essential. The question becomes: how do we implement fine-grained, dynamic authorization for MCP servers in a maintainable way?
Securing MCP servers with fine-grained access control. The challenge of “Who can do what”
The core of authorization is determining, for each action, should this agent (or user) be allowed to do this? In traditional applications, this often boils down to checking a user’s role or permissions before executing an operation. With MCP and AI agents, we have a similar need, but it can get more complex.
The AI agent might be carrying a user’s identity or might be a non-human service account. We might have multiple roles, hierarchical permissions, or context-based rules that determine access. Implementing this logic directly in the MCP server code, with a bunch of if/else checks for roles, etc. is error-prone and inflexible. Hardcoding such rules leads to brittle code - any policy change means modifying the code and redeploying the server, which is not agile or scalable.
Let’s illustrate the complexity with a simple scenario. Suppose we have an AI agent that manages expense reports via an MCP server , similar to the example above. We might have requirements like: a normal employee can submit a new expense, but cannot approve expenses; a manager can approve expenses, but only those submitted by users on their team; and only an admin role can delete an expense entry. This is a classic multi-role, multi-action policy. If we tried to enforce this in code, we’d be sprinkling role checks around each tool’s implementation. It’s doable for one or two rules, but as soon as the requirements evolve, say we introduce a new role, or add a condition like “managers can only approve up to $1000” - we have to revisit the code. It’s easy to make mistakes or overlook a check.
For example, in our expense scenario: the “add expense” tool should be available to regular users, but the “approve expense” tool should be available only to managers and maybe also to admins. The “delete expense” tool might be so sensitive that it’s reserved for admins alone. On top of that, even managers who can approve might have an additional constraint - e.g. they can approve expenses for their own department or below a certain amount threshold. Implementing such fine-grained permissions requires a flexible approach. A static role-based scheme (RBAC) might not capture the nuance like the monetary limit, whereas an attribute-based approach (ABAC) can. This is why modern authorization models often use a combination of roles and attributes (contextual info) to make decisions.
The challenge for MCP servers is clear: we need a way to externalize and manage these “who can do what” rules without burying them deep in application code. We want to be able to express rules like “managers can approve expenses under $1000” or “AI agents with the ‘finance-reader’ role can access the finance database read-only tool, but not the write tool” in a clear, declarative way. This calls for a policy-based authorization system that is decoupled from the main application.
Implementing dynamic authorization for MCP servers
Cerbos is a purpose-built solution to the kind of authorization challenges we’ve outlined. It externalizes your access control logic into human-readable policy files. In simpler terms, Cerbos lets you define your authorization rules in one place as YAML policies, and then ask Cerbos at runtime whether a given action should be allowed. Your application, in this case - the MCP server, delegates the decision to Cerbos. This architecture brings a few major advantages:
| Capability | Description |
|---|---|
| Centralized, externalized authorization logic | Instead of scattering permission checks throughout your code, you write them as declarative policies. For example, you might have a policy that says resource = “mcp::expenses” with rules: managers can “approve_expense” if amount < $1000, admins can “delete_expense”, etc. This policy lives outside your application code. The MCP server simply queries Cerbos whenever an agent tries to use a tool. Cerbos evaluates the relevant policy and returns “allow” or “deny.” |
| Fine-grained decisions in milliseconds | Cerbos is designed to be fast. A policy decision usually takes a few milliseconds, meaning it won’t introduce noticeable latency in your MCP agent’s interactions. You can comfortably check authorization on each tool invocation or request. |
| Dynamic enablement of tools | When using Cerbos with MCP, a common pattern is to enable or disable tools dynamically based on the authorization check. The MCP server can be configured to list all possible tools it can provide, but after a user (or agent) identity is associated, you run an authorization query for that identity against all the tools. |
| Audit and transparency | Cerbos comes with comprehensive audit logging for every decision made. Each time the MCP server asks “Can agent X do Y on Z?”, Cerbos will log the details of that query and its outcome. |
| Ecosystem and integrations | Cerbos can be run anywhere (on-prem, cloud, at the edge) and its behavior can be inspected. It also has SDKs for multiple languages and integrates well with modern cloud-native stacks. |
Now, let’s go into how you would go about securing an MCP server with Cerbos in practice. The process involves a few clear steps:
1. Define your authorization policies
Start by writing down the rules of who can do what in a Cerbos policy file.
2. Deploy the Cerbos Policy Decision Point (PDP)
Next, run the Cerbos service with your policies loaded. This could be as simple as running the official Cerbos Docker image and mounting the directory where your policy files reside.
3. Integrate authorization checks into your MCP server
With Cerbos up and your policies in place, modify your MCP server code to call Cerbos at the points where tool access needs to be decided.
4. Test and iterate
Once integrated, you should test different scenarios to ensure the policies behave as expected.
Done - MCP server is secured
After these steps, you’ll have an MCP server that is secured by Cerbos. The AI agents connecting to it will only be able to invoke the tools that they are allowed to, according to your centralized policy.
Conclusion
Enabling AI agents to interact with your systems via MCP opens up exciting possibilities, from automation of routine tasks to entirely new AI-driven features. But with that comes the responsibility to ensure those AI agents operate within the bounds you set. MCP authorization is all about imposing the right limits: it’s the fine-grained control over which agents (or users behind them) can access which tools and data, under which conditions. We’ve seen that without these controls, organizations can quickly run into security incidents and data breaches. The good news is that we don’t have to reinvent the wheel to secure MCP servers. By adopting an externalized authorization approach using tools like Cerbos, we get a robust solution that is both developer-friendly and enterprise-grade.