mcp-server-entra-example
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-server-entra-exampleget my user profile"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-server-entra-example
A minimal, well-commented MCP server that authenticates its callers with Microsoft Entra ID (Azure AD).
This is the token-verifier variant of
mcp-server-example. The two are deliberately almost
identical — the tools, the MCP App, the health check and the deployment are the
same — so you can diff them and see that the only thing that really changes is
auth.py:
|
| |
Who logs the user in? | This server (its own login page + user store) | Microsoft Entra ID |
Who issues the token? | This server | Microsoft Entra ID |
What this server does with auth | Is a full OAuth authorization server | Is a pure OAuth resource server — it only verifies Entra tokens |
Secrets needed | Hashed user passwords | None (a verifier needs only your public client id + tenant id) |
It is built on FastMCP, whose AzureJWTVerifier +
RemoteAuthProvider do all the token plumbing, so the only code specific to
your application is your tools and the ~30 lines of auth.py.
How it works
This server never logs anyone in. It trusts access tokens minted by Entra and validates each one (signature via Entra's JWKS, issuer, audience, and required scope). The caller is responsible for obtaining a token from Entra first:
Caller (MCP client) Microsoft Entra ID This MCP server
─────────────────── ────────────────── ───────────────
1. discover ───────────────────────────────────────────────────▶ GET /.well-known/oauth-protected-resource/mcp
└▶ "tokens come from Entra: <tenant>/v2.0"
2. get a token ────────────────────────▶ /authorize, /token
└▶ returns an access token
3. call tools (Authorization: Bearer) ─────────────────────────▶ POST /mcp
└▶ verifies the token, runs your toolsYou write only step 3's tools. FastMCP verifies the token; Entra does 1–2.
Related MCP server: MCP Auth
Getting your Azure values (step by step)
A token verifier needs an App Registration that exposes an API. You end up
with three values — AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_REQUIRED_SCOPES
— and no client secret (a secret is only needed to obtain tokens, which
this server never does).
Do everything in the Microsoft Entra admin center (entra.microsoft.com) or the Azure Portal (portal.azure.com → Microsoft Entra ID).
1. Create the app registration
Identity → Applications → App registrations → New registration.
⚠️ It must be App registrations, not Enterprise applications — only App registrations have the "Expose an API" page you need in step 3.
Give it a name (e.g.
mcp-server-entra-example) → Register.
2. Copy the two IDs → AZURE_CLIENT_ID and AZURE_TENANT_ID
On the app's Overview page:
Application (client) ID → this is
AZURE_CLIENT_IDDirectory (tenant) ID → this is
AZURE_TENANT_ID
Both are plain GUIDs and are not secret. (The tenant ID is the same across
your whole Entra directory — if you already use Microsoft 365 / Entra SSO, it's
the GUID in your SAML issuer https://sts.windows.net/<tenant-id>/.)
3. Expose an API → add a scope → AZURE_REQUIRED_SCOPES
In the app's left menu, Manage → Expose an API:
If Application ID URI isn't set yet, click Add / Set and accept the default
api://<client-id>→ Save.+ Add a scope:
Scope name:
access_as_user← this is yourAZURE_REQUIRED_SCOPESWho can consent: Admins and users
Fill the admin consent display name/description (anything) → State: Enabled
Add scope
The full scope is now api://<client-id>/access_as_user. (Any leftover default
scope like user_impersonation is harmless — the server only checks for the
name in AZURE_REQUIRED_SCOPES.)
4. Force v2 tokens
Manage → Manifest → set "requestedAccessTokenVersion": 2 → Save. This
makes Entra issue v2 access tokens, whose issuer is
https://login.microsoftonline.com/<tenant-id>/v2.0 — which is what this server
validates against.
5. (Only if you'll test with the Azure CLI) authorize the CLI
To let az mint a token for your custom API, either consent when prompted, or
pre-authorize it: Expose an API → Authorized client applications → Add a
client application → Azure CLI id 04b07795-8ddb-461a-bbee-02f9e1bf7b46 →
tick your access_as_user scope.
Recap — how the values map
App registration field | Env var |
Application (client) ID |
|
Directory (tenant) ID |
|
Expose an API → scope name |
|
(nothing — no secret needed) | — |
These three values are all the server needs. To connect it through Connext, you'll add a client secret and a redirect URI to this same app registration — those are used by Connext (the OAuth client), not by this server. See Connecting it to Connext.
Quick start
Requires Python 3.11+.
# 1. install
python -m venv .venv && source .venv/bin/activate
pip install -e .
# 2. configure and run (values from your app registration)
export AZURE_CLIENT_ID=<application-client-id>
export AZURE_TENANT_ID=<directory-tenant-id>
export AZURE_REQUIRED_SCOPES=access_as_user
python server.py
# -> serving on http://localhost:8000 (MCP endpoint: http://localhost:8000/mcp/)
# 3. in another terminal, get a token and call the server as a client would
az login
export MCP_ACCESS_TOKEN=$(az account get-access-token \
--scope api://$AZURE_CLIENT_ID/access_as_user --query accessToken -o tsv)
python examples/connect_with_client.pyTools run as the Entra user: whoami, roll_dice and greeting_card read
the caller's identity from the token's claims (see _current_user() in
tools.py). The quickest way to confirm the whole flow works is to call
whoami — it just returns your name back to you.
Connecting it to Connext
Connext connects to this server over OAuth and lets users sign in with
Microsoft. Because the server delegates identity to Entra — which does
not support RFC 7591 dynamic client registration — you register Connext as a
client of Entra by hand: you supply a client id + client secret when adding
the server. (Contrast the self-hosted mcp-server-example,
where you leave those blank and Connext self-registers via DCR.)
Platform requirement. Connext has to speak Entra's enterprise OAuth dialect: fall back to OpenID Connect discovery (Entra publishes no RFC 8414 doc), request the resource's scope (
api://<client-id>/access_as_user, per RFC 9728 — not the AS's generic OIDC scopes), and omit the RFC 8707resourceindicator for Entra. Recent connext-core does all three. On an older build the connect fails with "Could not connect to the MCP server URL" (discovery) orAADSTS9010010: The resource parameter … doesn't match with the requested scopes.
Extra Entra app-registration steps (for the Connext OAuth flow)
These are what Connext-as-OAuth-client needs — all on the same app registration you set up above:
Client secret — Manage → Certificates & secrets → New client secret → copy the Value. Connext uses it to exchange the auth code; it's stored encrypted in Connext, not in this server. (The server itself still needs no secret — it only verifies tokens.)
Redirect URI (reply URL) — Manage → Authentication → Add a platform → Web → Redirect URIs → add Connext's MCP OAuth callback, e.g.
https://<your-connext-host>/api/v1/oauth/mcp/callback→ Save.Must be a Web platform (Connext is a confidential client), an exact match, no trailing slash. If sign-in returns
AADSTS500113: No reply address is registered for the application, this step is missing or the URL differs. The exact value is theredirect_uriin the failing/authorizeURL.
(Optional) API permissions → Grant admin consent for
access_as_user, so users don't see a one-time consent screen on first connect.
Register in Connext
Admin → MCP Servers → Add:
URL: your public MCP endpoint (e.g.
https://mcp.example.com/mcp)Auth: OAuth · Client id: your
AZURE_CLIENT_ID· Client secret: step 1's value
Then each user clicks Connect once and signs in with Microsoft — a silent
SSO redirect if they're already signed into Connext via Entra (no password). The
server requests offline_access, so Connext keeps a refresh token and the
connection persists (no reconnecting).
Alternative: AzureProvider (server-side OAuth proxy)
If your MCP platform doesn't bridge enterprise IdPs, FastMCP's AzureProvider
moves the bridge into the server: it presents a DCR-capable OAuth server to
the client and proxies the login to Entra (the client then connects with blank
creds), at the cost of a client secret + redirect URI on the server side. This
repo shows the simpler token-verifier; reach for AzureProvider when the server
must be self-contained.
The files
File | What it does |
| Entry point. Builds the FastMCP server with Entra auth, registers tools, adds |
| The only real difference from |
| The example tools ( |
| A client that calls the server with a bearer token you obtained from Entra. |
| Configuration ( |
Taking it to production
Tenant scoping: use your specific tenant GUID (single-tenant) for the tightest validation, or
organizations/commonfor multi-tenant (issuer validation is then skipped and the audience is what protects you — make sure yourAZURE_CLIENT_ID/audience is correct).Scopes/roles: enforce least privilege with
AZURE_REQUIRED_SCOPES, and add app-role or group checks in your tools if needed (both are in the token claims).HTTPS: terminate TLS in front and set
PUBLIC_URLto thehttps://URL so the advertised metadata is correct.Clock/JWKS: FastMCP caches Entra's JWKS and honours token expiry — there is no auth state to persist (no secret, no stored tokens).
Scaling / replicas: note that while auth is stateless, the MCP streamable-HTTP transport keeps per-session state in memory (
initialize→Mcp-Session-Id→ follow-up calls). To run more than one replica you need session stickiness or a shared session store, otherwise a client's follow-up request can land on another pod and get "Session not found". This example runs a single replica for simplicity.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/connextai/mcp-server-entra-example'
If you have feedback or need assistance with the MCP directory API, please join our Discord server