What It Is#

A three-package framework for putting OAuth 2.0 in front of MCP servers. The MCP spec leaves auth as an exercise for the implementer; these packages handle the exercise.

  • mcp-authflow. The authorization server. Token issuance, introspection, storage (Postgres or in-memory), client validation, rate limiting.
  • mcp-authflow-resource. The resource server. Token verification via RFC 7662 introspection, OAuth discovery endpoints (RFC 9728, RFC 8414, OIDC), and a friction-control feedback loop that throttles tool calls dynamically.
  • example-mcp-server. A runnable docker compose stack wiring both halves together with a notes CRUD API.

Why Two Packages#

OAuth 2.0 separates authorization servers from resource servers for good reasons: different trust boundaries, different scaling needs, different deploy targets. Most MCP auth implementations collapse them into one process and lose that property. Splitting the framework along the same line keeps deployments honest.

MCP OAuth flow across client, resource server, and authorization server Sequence diagram showing discovery on the resource server, PKCE authorization at the auth server, a Bearer-token tool call, and RFC 7662 introspection between the resource server and the auth server. Client Claude Code / Cursor Resource Server mcp-authflow-resource Authorization Server mcp-authflow

1 GET /.well-known/oauth-protected-resource

2 metadata → auth server URL (RFC 9728)

3 Authorization request + PKCE challenge

4 code → exchange → access_token (scoped) sliding-window rate limit at /token

5 MCP tool call · Bearer access_token

6 POST /introspect (RFC 7662)

7 active=true, scopes, exp

8 tool response (or 429-free back-pressure) friction control adds latency, not errors

Auth and resource concerns split across two packages, communicating via RFC 7662 introspection.

Friction Control#

The resource server includes a proportional feedback loop on tool-call rates. Instead of a hard rate limit, it adds latency proportional to recent volume, so clients self-throttle without seeing 429s. Useful for agentic clients that retry aggressively.

Why I Built It#

I needed OAuth on the MCP servers powering my agents. The existing options either didn't separate auth and resource concerns, didn't ship discovery endpoints, or weren't pip-installable. I pulled what I had into clean packages with examples that work out of the box with Claude Code, Claude Desktop, and Cursor.