Try Bifrost Enterprise free for 14 days. Request access

MCP Server Authentication: How to Secure Agent Tool Access

MCP Server Authentication: How to Secure Agent Tool Access

TL;DR

  • MCP server authentication requires every remote MCP server to act as an OAuth 2.1 resource server and to reject any access token that was not issued specifically for it.
  • Token passthrough is explicitly forbidden by the MCP specification, so an agent cannot forward its own provider token to a downstream tool server.
  • Bifrost supports six MCP authentication types (none, headers, per-user headers, OAuth 2.0, per-user OAuth, and token exchange), selected per MCP server rather than globally.
  • Authentication answers who is calling; tool filtering answers what they can reach. Bifrost applies both, stacking client, request, and virtual key filters so a tool must pass every applicable filter.
  • Bifrost tool execution is off by default: tool calls returned by a model are suggestions until an explicit execution call is made, or until Agent Mode is configured with named auto-approved tools.

The Model Context Protocol authorization specification requires every protected MCP server to act as an OAuth 2.1 resource server and to validate that each access token was issued specifically for it as the intended audience. MCP server authentication is therefore not a matter of setting a bearer token and moving on, because the specification also covers discovery metadata, audience binding, per-user consent, and an explicit prohibition on passing tokens through to other services. Bifrost, the open-source AI gateway built in Go by Maxim AI, implements this at the gateway layer with six authentication types selectable per MCP server. This guide covers what the specification requires, which authentication pattern fits which situation, and how to enforce that agents reach only the tools they are approved for.

What Is MCP Server Authentication?

MCP server authentication is the process by which an MCP server verifies the identity behind a tool call and confirms that the presented credential was issued for that server. It combines OAuth 2.1 authorization flows, audience-bound access tokens, and discovery metadata that tells a client where to authenticate before any tool is listed or executed.

Two distinct questions sit behind the term, and conflating them is the most common source of design mistakes:

  • Authentication establishes which identity is making the call. That identity may be a service, a virtual key, or a specific signed-in person.
  • Authorization establishes what that identity may do once verified. In MCP terms, that means which tools appear in the tool list and which of them may actually run.

A deployment can get the first right and the second badly wrong. An agent that authenticates correctly to a database MCP server and then receives every tool that server exposes, including destructive ones, is authenticated and ungoverned at the same time. Our explainer on OAuth, API keys, and token management for MCP covers the credential mechanics in more depth, and the companion piece on security risks of ungoverned MCP server access covers what happens when the second question goes unanswered.

Why MCP Authentication Is Different From API Authentication

MCP authentication differs from ordinary API authentication because the caller is a model deciding at runtime which tools to invoke, not a developer who wrote the call sites. The credential has to be bound to a human or service identity that the model itself never sees, and the set of reachable tools has to be constrained before the model is given the chance to choose.

Three properties make this harder than issuing an API key:

  • The caller is non-deterministic. A model selects tools from whatever appears in its tool list. Anything visible is potentially callable, so the tool list itself is a security boundary.
  • Credentials belong to people, not to the agent. When an agent queries a user's issue tracker, the correct identity is that user, not a shared service account that can read every project.
  • Tokens must not travel. The specification forbids an MCP server from accepting or transiting tokens issued for anything other than itself, which rules out the pattern of handing an agent one token that opens every downstream system.

That last point is the one most implementations get wrong. Passing a token through to an upstream service creates a confused deputy: the receiving service sees a valid credential and has no way to tell that the request originated from an agent acting on behalf of someone with narrower permissions. The broader catalogue of MCP security risks covers the adjacent failure modes, including tool poisoning and over-broad tool exposure.

What the MCP Specification Requires for OAuth

The specification builds MCP authorization on OAuth 2.1 and two supporting RFCs. MCP servers must implement Protected Resource Metadata so clients can discover the authorization server, and clients must send Resource Indicators so the issued token is bound to one specific MCP server rather than usable anywhere.

The concrete requirements worth checking any implementation against:

Requirement Specification What it prevents
OAuth 2.1 with PKCE on the client OAuth 2.1 draft Authorization code interception and injection
Protected Resource Metadata on the server RFC 9728 Clients guessing or hardcoding the authorization server
WWW-Authenticate header on 401 responses RFC 9728 Section 5.1 Clients having no discovery path after a rejection
Resource Indicators in authorization and token requests RFC 8707 Tokens valid across multiple unrelated servers
Audience validation on every token OAuth 2.1 Section 5.2 A token minted for one server being replayed at another
No token passthrough MCP security best practices Confused deputy attacks against downstream services
HTTPS on all endpoints and redirect URIs OAuth 2.1 Section 1.5 Credential interception in transit

Error handling is specified too, and it carries meaning worth preserving: 401 means authorization is required or the token is invalid, 403 means the scopes are insufficient, and 400 means the request itself was malformed. Collapsing all three into a generic failure removes the signal a client needs to decide whether to re-authenticate or to stop.

Dynamic Client Registration is recommended rather than required. It matters in practice because MCP clients frequently encounter servers they have never seen before, and without it every new server pairing needs a manual client registration step that does not scale past a handful of integrations. Our primer on MCP token management and credential types covers how these flows differ from static key issuance.

MCP Authentication Types Compared

Bifrost exposes six authentication types, chosen per MCP server rather than set once for the whole deployment. The distinction that matters most is server-level versus per-user: a server-level credential means every caller reaches the upstream server under one shared identity, while a per-user credential binds each call to the person who made it.

Auth type Who authenticates Credential Best fit
none Nobody None Public MCP servers and local STDIO tools that need no key
headers Admin, once Static HTTP headers Shared API keys and bearer tokens for internal servers
per_user_headers Each user, lazily Per-user HTTP headers Services where each person holds their own API key
oauth Admin, once OAuth 2.0 token with refresh One shared third-party account used by the whole team
per_user_oauth Each user, lazily OAuth 2.0 token per identity Per-user services such as issue trackers and wikis
token_exchange Each caller, every call Exchanged identity-provider token, never stored First-party servers that trust your identity provider

Per-user authentication applies to HTTP and SSE connections. STDIO connections inherit their environment from the spawned subprocess, so they have no per-call authentication model and should be treated as trusted-local rather than user-scoped.

Token exchange deserves separate attention because it sits outside the server-level and per-user split. Every caller reaches the upstream server under their own identity, but no credential is persisted per caller: each tool call carries the caller's identity-provider token, which Bifrost exchanges on a cache miss. There is no consent step and no per-user revoke step, and offboarding at the identity provider takes effect within the cached token lifetime rather than instantly. That trade is usually right for internal servers and wrong for third-party ones.

Selecting between the remaining types comes down to one question: does every caller legitimately share the same upstream permissions? If yes, server-level OAuth or static headers are simpler to operate. If no, per-user OAuth is the only pattern that keeps one user's agent from reading another user's data.

How an MCP Gateway Secures Agent Tool Access

An MCP gateway centralizes authentication, tool discovery, and access policy for every MCP server an agent can reach, so credentials live in one governed place instead of scattered across agent configurations. Bifrost, the AI gateway built for enterprise AI traffic, acts as both an MCP client to upstream tool servers and an MCP server to clients such as Claude Desktop and Cursor.

That position produces three properties that per-agent configuration cannot:

  • Credentials never reach the agent. The agent authenticates to the gateway with a virtual key or a signed-in session, and the gateway holds the upstream credential. Rotating a downstream token is a gateway change, not a fleet-wide reconfiguration.
  • One tool registry, one policy surface. Connecting through Bifrost as an MCP gateway aggregates every connected server behind a single endpoint, so tool visibility is decided centrally.
  • Identity survives the hop. Per-user credentials are keyed to an identity resolved from request context, so the audit trail records which person's authority a tool call ran under.

Identity resolution follows a fixed priority: a signed-in user via SSO, then a virtual key, then an opaque session ID supplied by the caller. A per-user request carrying none of these is rejected with an mcp_auth_required response rather than falling back to a shared credential, which is the behavior you want, because a silent fallback is how per-user isolation quietly stops being per-user. The MCP gateway resource page covers the architecture, and what an MCP gateway is and how it works covers the broader role it plays.

How to Configure MCP Server Authentication in Bifrost

Configuration is per MCP client, where a client is one connection to one upstream MCP server. Choose the connection type, choose the authentication type, then constrain the tool set. The MCP authentication overview documents each type in full.

Step 1: connect the server. Bifrost supports STDIO for local tools, and HTTP or SSE for remote ones. Only HTTP and SSE support per-user authentication, so a server that needs user-scoped access has to be reachable over one of those.

Step 2: select the authentication type. For a third-party service where each engineer has their own account, per_user_oauth is correct. The first time a given identity calls a tool on that server, Bifrost returns an authentication prompt rather than a shared credential, and the resulting token is stored against that identity for later calls.

Step 3: constrain the tool set. This is the step most often skipped, and it is where authentication becomes access control. Tool filtering across three levels applies at three levels that stack, so a tool must pass all of them:

Available tools
  → Client config (tools_to_execute)
  → Request headers (per-request filter)
  → Virtual key filter (per-key allowlist)
  → Tools presented to the model

The client-level default is deny: an omitted or empty tools_to_execute list exposes nothing, and ["*"] exposes everything from that client. Starting from the permissive setting and narrowing later rarely happens, so set the allowlist when the server is connected.

Step 4: bind tools to keys. Per-virtual-key MCP tool filtering attaches an allowlist to the same virtual key that already carries budgets and rate limits, which keeps tool permissions and spend permissions in one object rather than two systems that drift apart.

Step 5: decide the execution model. Bifrost does not automatically execute tool calls. A tool call returned by a model is a suggestion until an explicit execution call is made. Agent Mode enables autonomous execution, and it is opt-in per tool through a tools_to_auto_execute list rather than a global switch, so read-only tools can run unattended while destructive ones still require approval.

For teams running coding agents against MCP servers, using an MCP gateway with Claude Code walks through the same configuration from the client side.

MCP Server Security Beyond Authentication

Authentication is necessary and not sufficient. MCP server security also depends on revocation, auditability, and the ability to answer which identity ran which tool against which server, which are operational questions rather than protocol ones.

Four controls close the gap between a correctly authenticated deployment and a governed one:

  • Revocation. Per-user credentials appear as one row per identity and MCP server on the MCP Sessions page, where they can be inspected, re-authenticated, edited, or revoked individually. Revoking one person's access should not require rotating a shared secret.
  • Curated tool collections. MCP tool groups let an administrator define a named set of tools once and attach it to virtual keys, teams, customers, or users, enforced at request time rather than assembled per agent.
  • Federated auth for internal APIs. MCP with federated authentication turns existing enterprise APIs into MCP tools without writing glue code, which avoids the pattern of standing up a lightly governed MCP server per internal service.
  • Audit trails. Immutable audit logs record the governance events that SOC 2, GDPR, HIPAA, and ISO 27001 reviews ask for, and in-VPC deployment keeps prompts and tool arguments inside your own network boundary.

Teams formalizing this should read our guides on MCP server governance practices and tooling and MCP gateways for security and compliance.

Frequently Asked Questions

How does MCP authentication work?

An MCP client calls a protected server and receives a 401 with a WWW-Authenticate header pointing to the server's Protected Resource Metadata. The client reads that metadata to find the authorization server, runs an OAuth 2.1 flow with PKCE, and includes a resource indicator naming the target server. The server then validates that the returned token names it as the audience.

What is token passthrough and why is it forbidden?

Token passthrough is forwarding a token issued for one service to a different service. The MCP specification forbids servers from accepting or transiting tokens not issued for them, because the receiving service cannot distinguish an agent acting with delegated authority from the original principal. That gap is the confused deputy problem, and audience validation is what closes it.

Do I need OAuth for a local MCP server?

No. Local STDIO servers spawn as subprocesses and inherit their environment from the parent process, so they have no per-call authentication model and the none type is appropriate. Treat them as trusted-local. The OAuth requirements in the specification apply to remote servers reachable over HTTP or SSE.

What is the difference between MCP authentication and MCP authorization?

Authentication verifies which identity is behind a tool call. Authorization decides which tools that identity may see and run. A correctly authenticated agent with an unfiltered tool list is still ungoverned, which is why tool filtering at the client, request, and virtual key levels matters as much as the credential itself.

How do I give each user their own credentials for a shared MCP server?

Use per-user OAuth or per-user headers on that MCP client. Bifrost keys the stored credential to an identity resolved from request context in priority order: signed-in user, then virtual key, then session ID. The first tool call from a new identity triggers authentication, and later calls reuse the stored credential without prompting again.

Can I stop an agent from running destructive tools?

Yes. Tool execution is not automatic in Bifrost: model-returned tool calls are suggestions until an explicit execution call is made. Agent Mode enables autonomous execution only for tools named in a tools_to_auto_execute list, so read-only tools can run unattended while write and delete operations continue to require a deliberate call.

How do I revoke MCP access for one person?

Revoke that identity's row on the MCP Sessions page, which is scoped to a single identity and a single MCP server. Because per-user credentials are stored per identity rather than shared, revoking one person's access leaves everyone else's tokens intact and requires no secret rotation across the deployment.

Secure MCP Server Authentication With Bifrost

MCP server authentication is best handled once, at the gateway, rather than per agent. The Bifrost gateway supports six authentication types per MCP server, resolves per-user identity from SSO, virtual keys, or session IDs, stacks tool filters across client, request, and virtual key levels, and keeps tool execution explicit unless auto-approval is deliberately configured. It is open source, runs in your own VPC or on-prem, and aggregates every connected MCP server behind one governed endpoint.

To see how Bifrost handles MCP authentication, per-user credentials, and tool-level access control for your agents, book a demo with the Bifrost team.