Skip to content

Add MCP OAuth flow support #86

@heskew

Description

@heskew

Add MCP OAuth flow support

Adds Model Context Protocol authorization-server support to @harperfast/oauth so any Harper app already using the plugin for human OAuth (GitHub, Google, Azure, Auth0, custom OIDC) can also act as an OAuth source for MCP clients (Claude Desktop, Cursor, mcp-remote). The MCP flow bridges to the existing upstream-IdP dance rather than reimplementing it; onLogin and the rest of the lifecycle hooks fire unchanged.

Targets MCP authorization spec revision 2025-06-18 (stable). The 2026-07-28 release candidate adds six SEPs that are tracked separately in #100 for v1.x; v1 ships against stable. Verification thread: #86 comment 2026-05-19. Reviewer credit: @Ilya0527, @supertrained.

Stages

Tracked as GitHub sub-issues — sidebar shows live status. Parent closes when Stage 7 (#97) merges.

Stage Scope Sub-issue Status
1 RFC 7591 Dynamic Client Registration (no sub — pre-carve) ✅ Shipped (PR #89)
2 RFC 9728 PRM + RFC 8414 AS metadata + JWKS placeholder #92 🟡 In review (PR #90)
3 /oauth/mcp/authorize (PKCE-S256, bridges to upstream IdP) #93 ⬜ Pending
4 /oauth/mcp/token + JWT signing + refresh rotation #94 ⬜ Pending
5 withMCPAuth wrapper + 401 + WWW-Authenticate contract #95 ⬜ Pending
6 Audit events + onMCPTokenIssued hook #96 ⬜ Pending
7 End-to-end integration fixture (v1 conformance proof) #97 ⬜ Pending
8 User-facing docs #98 ⬜ Pending

Cross-cutting decisions

These apply across stages; each sub-issue inherits them.

  • Token format: JWT, Harper-signed, audience-bound (aud claim drives RFC 8707 validation; no token-table round trip; RFC 9068-aligned).
  • Signing algorithm: RS256 default, EdDSA optional via config; advertised in AS metadata.
  • Signing keys: persisted in harper_oauth_mcp_keys table — file storage would diverge across replicated Harper nodes.
  • DCR storage: persisted in harper_oauth_mcp_clients — Claude Desktop caches client_id, ephemeral store breaks across restarts.
  • DCR access: open by default per RFC 7591; production deployments use initialAccessToken to gate.
  • Refresh tokens: rotated single-use per OAuth 2.1; replay revokes the family.
  • Token scoping: role-level (matches human OAuth); per-tool scoping is v1.1.
  • Transitive revocation when upstream IdP session ends: not in v1 — spec doesn't require it. Future onUpstreamRevoked hook lands in v1.1 for apps that need it.
  • Canonical resource URI: configurable per app (mcp.resource), defaults to <issuer>/mcp. Issuer should be pinned in production via mcp.issuer (otherwise derived from request Host header).

Dependencies

  • Independent of HarperFast/harper#465 v1. Apps with their own MCP integrations (heskew/harper-kb, Cortex MCP server, custom apps) can adopt this immediately.
  • Soft alignment: when HarperFast/harper#465 v1.1 adds OAuth to native MCP, it should delegate to this plugin, not run a parallel implementation. Track as a coordination point when that lands.

Related

Out of scope

  • OAuth in the native MCP server itself (that's HarperFast/harper#465 v1.1)
  • Tool-scoped OAuth tokens (v1.1; v1 matches human-OAuth role-level access)
  • Transitive revocation tied to upstream IdP sessions (v1.1, via onUpstreamRevoked hook)
  • Token introspection / revocation endpoints (RFC 7662 / RFC 7009 — short TTL + refresh rotation is the spec's answer)
  • Cross-instance MCP token federation

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions