Python teams moving a FastMCP server from stdio to a network transport.
Where to draw the line between what FastMCP verifies and what your identity provider issues.
The control gap
FastMCP makes the server trivial and the authentication decision easy to postpone. A server that runs locally over stdio needs nothing; the same code exposed over HTTP needs discovery, an authorization server, audience-bound tokens, and revocation. Teams usually discover this when a client fails with an opaque authentication error and there is nothing in the response telling it where to go.
What good looks like
The FastMCP server verifies inbound tokens and advertises where they come from, while issuance, consent, and revocation stay with an authorization server that already does those jobs.
- Give the server a token verifier configured with the issuer, the JWKS location, and the audience for this specific server.
- Serve protected resource metadata so a client that hits a 401 can discover the authorization server without configuration.
- Set the audience to the canonical URL of this MCP endpoint, and reject tokens issued for anything else.
- Keep tool-level authorization outside the verifier. Token validation says the caller is legitimate, not that this call is permitted.
A production workflow
- Choose the authorization server that will issue tokens for this MCP endpoint.
- Configure FastMCP's auth provider with that issuer, its keys, and this server's audience value.
- Publish the protected resource metadata document at the well-known path for the endpoint.
- Add per-tool authorization for the calls that change state, so a valid token still faces a decision.
Copy this
Class names differ between FastMCP versions, so check the version you are pinning. The structure below is what matters: the server verifies, and something else issues.
# FastMCP 2.x. Verify tokens; do not mint them here.
from fastmcp import FastMCP
from fastmcp.server.auth.providers.jwt import JWTVerifier
verifier = JWTVerifier(
jwks_uri="https://your-authorization-server/.well-known/jwks.json",
issuer="https://your-authorization-server",
audience="https://your-host/mcp/billing-tools", # this server, not a shared value
)
mcp = FastMCP("billing-tools", auth=verifier)
@mcp.tool
def issue_refund(order_id: str, amount_cents: int) -> str:
# A valid token is not an authorization. Ask before the side effect.
decision = authorize(tool="issue_refund",
resource=f"order:{order_id}",
arguments={"amount_cents": amount_cents})
if decision.effect != "allow":
raise PermissionError(decision.reason)
return refund(order_id, amount_cents)
if __name__ == "__main__":
mcp.run(transport="http", host="127.0.0.1", port=8000)The audience line is the one to get right. A shared audience across several FastMCP servers means any token works everywhere, which is the failure that resource indicators exist to prevent.
Evidence to require
- The issuer, JWKS URI, and audience the server is configured with, per environment.
- Rejected tokens by reason: signature, expiry, issuer, audience.
- Which tools performed a separate authorization check and which relied on token validity alone.
- The protected resource metadata document actually served by the deployed process.
Buyer checklist
- Is the audience unique to this server, or shared across the fleet?
- Does the server return a resource_metadata pointer on 401, or a bare 401?
- Which tools change state, and do any of them execute on token validity alone?
- How is a token revoked before its expiry, and how quickly does that take effect?
Practical answers
Common implementation questions
Should FastMCP be the authorization server too?
For a prototype it is convenient. For anything with real users, issuance, consent, and revocation belong to a system built for them, and the MCP server stays a resource server that verifies.
Which FastMCP version has these classes?
The auth provider API has moved between releases, so pin a version and read that release's documentation rather than copying a snippet from an older post. The concepts of issuer, JWKS, and audience are stable across all of them.
Where does Endram fit with FastMCP?
Endram fronts the FastMCP server as an authorized gateway. It performs discovery, registration, consent, and audience binding for clients, and evaluates each tool call before forwarding it, so the FastMCP process keeps its own transport and tools.