Security

MCP Is the Pipe, Not the Permission Boundary

The useful test for an internal MCP deployment is not whether the happy path works. It is whether a leaked token, compromised client, or manipulated agent produces a small, predictable failure.

MCP standardizes how clients exchange context and invoke tools. It does not, by itself, decide who may search documents, modify calendars, create payments, or trigger deployments. Those decisions belong to the authorization architecture around the protocol, and the right architecture depends on the transport and deployment model.

For HTTP-based deployments, the current MCP authorization specification defines an OAuth-based authorization flow and treats the MCP server as an OAuth resource server. It also says authorization is optional and that implementations using STDIO should retrieve credentials from the environment rather than use that HTTP flow. That distinction matters: one resource-server pattern does not apply universally to every MCP transport.

The operational goal is a resilient pipeline. Assume prompts, clients, and credentials can eventually be compromised. Then make sure every unsafe request still encounters narrow grants, tenant boundaries, application policy, and an ordinary denial.

Start with the boundary, not the endpoint

An internal network location is not a permission model. Neither is SSO.

SSO can establish identity, but identity alone does not say which tools a caller may invoke or which records the caller may see. A server behind SSO may still reach repositories, HR records, documents, databases, payment systems, or deployment infrastructure. Once an agent can invoke that server, every reachable capability becomes part of the attack surface.

Map the request path before exposing tools:

  • Human user
  • MCP client or agent
  • Identity or authorization service
  • MCP server
  • Downstream service
  • Customer or organizational tenant

These are separate identities and trust boundaries. Do not derive identity, role, or tenant from model-generated arguments such as user_id, role, or tenant. Those fields may be valid business inputs, but they are not trusted authorization context.

The authenticated request path should establish identity and tenant. Where the deployment model supports delegated user access, preserve that context downstream rather than replacing it with one broadly privileged service credential. Glean’s MCP security documentation is a product-specific example: it describes user-specific execution while retaining source-system permissions for documents, objects, directories, HR systems, and repositories.

That is an implementation example, not a protocol requirement. The broader rule is simpler: an MCP grant should not erase an existing ACL. Permission to invoke document.search does not imply permission to read every indexed document.

Passing user context through the full request path is harder than attaching one service credential to the server. The service credential is easier only until it becomes a bypass around source permissions. For sensitive systems, that shortcut is not worth shipping.

Give actions explicit grants

A permission such as mcp:access usually postpones the real authorization work.

When actions have different consequences, separate their grants. Read and write are an obvious split. Payment creation, deployment, deletion, and permission administration often need tighter boundaries still.

Examples might include:

  • mcp:calendar.read
  • mcp:calendar.write
  • mcp:invoice.create
  • A narrow deployment capability
  • Separate deletion or permission-management grants

These names are descriptive examples, not a universal scope taxonomy. One scope per tool can become noisy when a server exposes many low-risk operations. Grouping coherent read-only tools may be reasonable. Grouping deployment, deletion, payment creation, and access administration under a generic write grant is not.

The MCP authorization specification requires protected HTTP requests to carry an access token and requires servers to validate that the token was issued for them. The underlying OAuth resource-indicator mechanism is defined by RFC 8707. MCP’s security guidance also prohibits token passthrough: a server must not accept or forward a token that was not issued for that MCP server.

Those protocol rules establish a safer token boundary. They do not replace tool-level policy. A token carrying mcp:invoice.create may permit the caller to request invoice creation, but the application still has to evaluate tenant ownership, account access, required fields, approval conditions, and other business rules.

For HTTP authorization, use the standards named by the current MCP specification rather than treating vendor shorthand such as “OAuth 2.1” as a complete design. Relevant primary references include OAuth 2.0 Security Best Current Practice, RFC 9700, OAuth 2.0 Protected Resource Metadata, RFC 9728, PKCE, RFC 7636, and OAuth 2.0 Authorization Server Metadata, RFC 8414.

Readable grants help consent and administration too. “Create and modify calendar events” communicates a consequence. “Enable extended integration” does not.

Enforce policy where the action happens

Start with no protected tools enabled, then grant access by user, role, client, or workflow. Two users can connect to the same server without receiving the same capabilities.

Scalekit’s SSO-backed MCP pattern is a vendor implementation example that separates enterprise identity from scoped authorization. Its practical framing is that a shared endpoint need not imply shared permissions. That is useful architecture guidance, but not a protocol-wide MCP requirement.

Before invoking a protected tool, reject requests with missing, expired, revoked, misdirected, or insufficient credentials. Also reject requests whose trusted tenant context does not match the target resource. For OAuth-protected HTTP deployments, the MCP specification requires token validation and defines the expected 401 and 403 responses for invalid or insufficient authorization.

Prompts cannot grant permission. A system instruction telling an agent not to deploy without approval may improve orchestration, but the deployment tool still needs deterministic authorization. Rephrasing a request, retrying it, or claiming that a user approved it must not change the result.

A gateway can centralize policy, but it should not leave the protected resource blind. If the server receives no verified identity, tenant, audience, or grant information, a bypass or configuration error can turn the gateway into a single brittle control. Centralize administration where useful while retaining enough authenticated context to enforce policy at the server or downstream resource.

Operators also need a kill switch for individual tools. If disabling one dangerous or malfunctioning tool requires taking down the entire server, the control plane is too coarse.

Keep credentials constrained

For routine internal HTTP access, prefer short-lived OAuth access tokens over long-lived shared API keys. Bind credentials, where supported, to the narrowest practical combination of user, client, tenant, resource, and approved grants.

Short lifetimes reduce the duration of exposure. Resource and audience restrictions reduce its breadth. Neither compensates for a token that authorizes too much while valid.

Do not place downstream credentials in prompts, model context, or tool output. The model needs a controlled capability, not the secret behind it.

Glean’s documentation describes short-lived OAuth tokens and a user-scoped API-token fallback for hosts without OAuth support or for development and troubleshooting. That fallback is product-specific. The sound operational posture is to treat compatibility credentials as a controlled exception rather than the default production path.

Permission changes need a documented refresh or revocation boundary. If an administrator removes notes:write, the system should specify when existing credentials stop carrying that grant. Some environments require immediate revocation; others may accept short token lifetimes and renewal. “It should update eventually” is not a policy.

New privileges should require new authorization material rather than silently upgrading an existing token. Scalekit’s scoped-permission example illustrates this vendor-specific pattern: a read-only user can list notes but cannot add one until notes:write is granted and a new token is issued.

Make prompt injection fail at the same boundary

Documents, tickets, web pages, and tool results can all contain instructions designed to manipulate an agent. Treat that as an authorization problem as well as a model-behavior problem.

Suppose a read-only workflow retrieves a document telling the agent to create an invoice or trigger a deployment. The secure outcome cannot depend on whether the model follows the instruction. The call should fail because the authenticated caller lacks the relevant capability.

For newly requested, destructive, or high-impact actions, add explicit user confirmation through a controlled mechanism. State the consequence plainly. Confirmation is an additional control, not a substitute for a valid grant or downstream business rules.

Minimize tool output as well. Responses should not expose authorization headers, credentials, or entire internal objects when the workflow needs only a few fields.

The layers should reinforce one another: the client requests limited capabilities, the authorization service issues constrained credentials, the MCP server verifies them, downstream systems retain ACLs and business rules, and responses reveal only what the workflow needs. A manipulated model can still attempt the wrong action, but it cannot promote its own authority.

Test the failures, not just the demo

One successful call proves connectivity. It says little about the permission boundary.

Build a test matrix that represents the actual failure cases:

Test identity or token Expected behavior
No access Cannot invoke protected tools
Read-only Can retrieve allowed data but cannot mutate it
Write-enabled Can perform only granted mutations
Wrong tenant Cannot retrieve or modify the target tenant’s data
Expired Fails consistently
Revoked Fails after the documented revocation boundary

If a read-only identity can list notes, verify that it cannot add, edit, or delete them. Repeat the negative case for every mutating handler. Correct enforcement in one tool proves nothing about another.

Test tenant isolation with guessed or directly supplied object identifiers. A token issued for one tenant should not work against another. Test retrieval separately to confirm that search and document tools still honor source-system ACLs.

During those tests, the audit path should show the authenticated identity, initiating client, trusted tenant, presented grants, required permission, allow-or-deny reason, and downstream resource. Do not log raw tokens or unnecessary sensitive payloads; auditability should not create another credential-leak channel.

A reliable release has measurable, uneventful properties:

  • A read credential cannot mutate data or route through another write-capable tool.
  • Credentials for one tenant cannot access another tenant.
  • Expired and revoked credentials fail at a documented boundary.
  • Administrators can disable a tool without rebuilding every client.
  • Sensitive calls can be attributed to an authenticated user or trusted client.
  • Existing downstream ACLs remain effective.
  • Malicious instructions cannot add privileges absent from the caller’s grant.

These are stronger than “the agent behaves safely” because they can be automated. Mutating internal tools should not ship without negative tests for the boundaries they claim to enforce.

Roll out from the safest path

Begin with one low-risk, read-only workflow and a small test group. Preserve user context and downstream ACLs from the start; retrofitting them after broad service credentials are embedded is much harder.

Classify each proposed tool as read, write, destructive, administrative, or cross-tenant. Let that classification drive grant design, confirmation requirements, audit detail, and human involvement.

Keep deterministic controls outside the model:

  • Token and audience validation
  • Grant matching
  • Tenant binding
  • Schema validation
  • Downstream ACL enforcement
  • Business-rule checks
  • Revocation
  • Audit event creation

Use schemas to constrain inputs and outputs. Reject operations when identity, tenant, or authorization context cannot be established from trusted data. Human approval, when required, should authorize a specific action through a controlled mechanism rather than free-form text interpreted by the model.

Before adding mutating tools, leak a read-only test token and attempt writes. Feed the workflow malicious instructions requesting an ungranted action. Try valid credentials against the wrong tenant. Revoke a token and verify the promised failure boundary. Remove a permission and confirm stale access does not persist beyond policy. Disable a tool and confirm clients cannot invoke it.

The standard is not an MCP server that never receives a dangerous request. It is a pipeline that receives one and answers with an ordinary denial.

Sources and further reading

Back to top ↑

Rody

Founder & CEO · RodyTech LLC

Founder of RodyTech LLC in Iowa. I write practical notes on automation, infrastructure, security, and software decisions for builders and business operators.

No comments yet

Leave a comment

Your email address will not be published. Required fields are marked *