Working Solution: MCP Server OAuth with Microsoft Entra ID on Azure Container Apps

,

For anyone trying to connect Cursor to a remote MCP server hosted on Azure Container Apps using Microsoft Entra ID (Azure AD) for authentication, I wanted to share a working solution. It took a while to get right, so hopefully this saves others some time.

The Problem

The MCP authorization spec requires support for several OAuth standards that Microsoft Entra ID doesn’t implement natively:

  • RFC 8414 (Authorization Server Metadata) — Microsoft uses OIDC discovery at /.well-known/openid-configuration instead of /.well-known/oauth-authorization-server

  • RFC 7591 (Dynamic Client Registration) — Microsoft requires manual app registrations; there’s no dynamic endpoint

  • RFC 8707 (Resource Indicators) — Cursor sends scope=access_as_user with a resource parameter, but Microsoft v2.0 requires fully qualified scopes like api://<client-id>/access_as_user and doesn’t support the resource parameter at all

On top of that, Azure Container Apps’ built-in authentication (Easy Auth) blocks OAuth discovery endpoints when set to its default Return401 mode, and its built-in 401 response doesn’t include the WWW-Authenticate header that Cursor needs to trigger the OAuth flow.

The Solution

I built a lightweight OAuth compatibility layer that sits inside the MCP server and translates between what Cursor expects and what Microsoft provides. It consists of five endpoints:

  1. /.well-known/oauth-authorization-server — Fetches Microsoft’s OIDC metadata and transforms it to RFC 8414 format

  2. /oauth/register — A mock dynamic client registration endpoint that returns the pre-configured Entra ID client_id

  3. /oauth/authorize — A proxy that rewrites scopes to fully qualified format and strips the resource parameter before redirecting to Microsoft

  4. /oauth/token — Same scope rewriting, forwarding the token exchange to Microsoft

  5. The standard /.well-known/oauth-protected-resource (RFC 9728) pointing authorization_servers to the MCP server itself (so Cursor discovers our proxy endpoints)

Two additional configuration changes were required:

  • Easy Auth set to AllowAnonymous (so unauthenticated requests reach the app, where custom middleware returns 401 with the proper WWW-Authenticate: Bearer resource_metadata="..." header)

  • The Cursor redirect URI (cursor://anysphere.cursor-mcp/oauth/callback) registered under “Mobile and desktop applications” in Entra ID, not “Web”

Result

Cursor’s OAuth flow now works end to end. Click Connect, sign in with Microsoft, tools load. Easy Auth validates tokens at the infrastructure level, and the application middleware extracts identity from the X-MS-CLIENT-PRINCIPAL headers.

Full Writeup

I published a detailed blog post, step-by-step deployment guide, lessons learned, and a drop-in Python reference implementation here:

https://ignitionai.xyz/blog/making-mcp-servers-work-with-microsoft-entra-id-on-azure/

The repo includes:

  • Complete guide covering Entra ID app registration, the OAuth layer, Azure Container Apps config, and Cursor setup

  • Lessons learned document with a debugging playbook and architecture decision records

  • Copy-paste reference implementation (Python/Starlette/FastMCP)

  • Instructions written for both humans and AI agents (so Cursor’s agent can implement this on future servers)

Hope this helps someone avoid the 8 hours of debugging it took me to figure this out.