Skip to content

MCP Authentication

Category: concept Last updated: 2026-04-04 Status: draft

Summary

The Model Context Protocol (MCP) includes an OAuth 2.1-based authorization framework that allows AI clients to send authenticated requests to MCP servers on behalf of signed-in users. When MCP servers access sensitive resources or need to identify callers, implementing authentication via an identity provider like Microsoft Entra ID becomes necessary. Python's FastMCP library provides first-class support for this pattern.

Details

What is MCP?

The Model Context Protocol is a standardized protocol for AI agents to invoke external tools. MCP servers expose tools and resources; MCP clients (e.g., VS Code, Claude Desktop) discover and call them. When tools need to know who is calling — for per-user data, access control, or downstream API calls — authentication is required.

OAuth 2.1 Model

MCP authentication maps cleanly onto OAuth 2.1 roles:

OAuth Role MCP Role
OAuth client MCP client (e.g., VS Code)
Resource server MCP server
Resource owner Signed-in user
Authorization server Identity provider (e.g., Microsoft Entra ID)

The MCP client obtains a Bearer token from the authorization server and presents it to the MCP server with each request. The server validates the token using the provider's public keys — no client secret needed at validation time.

Client Registration Options

Three approaches exist for authorization servers to recognize MCP clients:

  1. Pre-registration — The server pre-registers known client IDs. Simplest, but requires advance setup.
  2. CIMD (Client Identity Metadata Document) — Clients publish a JSON document describing their attributes; the server fetches and trusts it.
  3. DCR (Dynamic Client Registration) — Clients register themselves at discovery time, receiving a new client ID.

VS Code supports all three. Microsoft Entra ID only supports pre-registration, making it the only viable option for Entra-backed MCP servers. — [source: building-mcp-servers-entra-id.md]

Entra App Registration

To enable Entra authentication for an MCP server, you register an Entra application and configure:

  • Delegated scope (user_impersonation) — Signals the client acts as the user, not itself.
  • Pre-authorized client — VS Code's application ID is pre-authorized for the scope, eliminating per-user consent prompts.
  • Admin consent for downstream APIs — If the server calls Microsoft Graph on behalf of users (via OBO flow), an admin grants consent upfront.

The registration can be scripted via the Microsoft Graph SDK (auth_init.py).

Credential Management

Different environments call for different credential strategies:

  • Local development: Client secrets — simple, low overhead.
  • Production on Azure Container Apps: Managed Identity as Federated Identity Credential (MI-as-FIC) — no secret to manage; identity is bound to the compute resource.

FastMCP Server Implementation

FastMCP (Python) provides a RemoteAuthProvider abstraction. The server is configured with an Azure JWT verifier that fetches Entra's public keys at startup and validates tokens on each request. No client secret is needed for validation.

Custom middleware extracts the oid (object identifier) claim from validated tokens and stores it in request state, making the user's Entra identity available to all downstream tools.

# Conceptual structure (from article)
# - RemoteAuthProvider + AzureJWTVerifier handle token validation
# - Middleware extracts "oid" claim → request.state.user_id
# - Tools read request.state.user_id for per-user operations

FastMCP 3.0 adds per-tool authorization declarations. Validation runs at both tool enumeration and invocation time — clients cannot even see unauthorized tools.

On-Behalf-Of (OBO) Flow

When an MCP tool needs to call a downstream API (e.g., Microsoft Graph) as the signed-in user, it exchanges the inbound MCP Bearer token for a Graph-scoped token using the MSAL SDK's on-behalf-of flow:

MCP Bearer token → MSAL OBO exchange → Graph API token → Graph API call

This enables operations like checking Entra group membership to enforce access controls. The production version uses MI-as-FIC for the assertion credential rather than a client secret.

Key Claims & Data Points

  • MCP spec includes OAuth 2.1 authorization; MCP client = OAuth client, server = resource server — [source: building-mcp-servers-entra-id.md]
  • Entra only supports pre-registration (not CIMD or DCR), constraining client authorization architecture — [source: building-mcp-servers-entra-id.md]
  • user_impersonation scope signals delegated (user-context) access vs. app-only access — [source: building-mcp-servers-entra-id.md]
  • FastMCP's RemoteAuthProvider + Azure JWT verifier validates tokens via public keys without server-side secrets — [source: building-mcp-servers-entra-id.md]
  • Managed Identity as FIC eliminates secret rotation risk in production — [source: building-mcp-servers-entra-id.md]
  • FastMCP 3.0 supports per-tool authorization that runs at list time and call time — [source: building-mcp-servers-entra-id.md]

Open Questions

  • How does MCP authentication compare to tool-calling auth in other protocols (e.g., OpenAPI/tool-use with API keys)?
  • Is pre-registration the only viable option for Entra permanently, or is DCR support planned?
  • How do you handle token refresh in long-running MCP sessions — does FastMCP manage this automatically?
  • What happens when the OBO exchange fails mid-session (token expiry, revoked consent) — how does the server signal this to the MCP client?
  • Are there performance implications of per-request JWT verification at scale?

Sources