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
Add MCP OAuth flow support
Adds Model Context Protocol authorization-server support to
@harperfast/oauthso 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;onLoginand the rest of the lifecycle hooks fire unchanged.Targets MCP authorization spec revision
2025-06-18(stable). The2026-07-28release 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.
/oauth/mcp/authorize(PKCE-S256, bridges to upstream IdP)/oauth/mcp/token+ JWT signing + refresh rotationwithMCPAuthwrapper +401 + WWW-AuthenticatecontractonMCPTokenIssuedhookCross-cutting decisions
These apply across stages; each sub-issue inherits them.
audclaim drives RFC 8707 validation; no token-table round trip; RFC 9068-aligned).harper_oauth_mcp_keystable — file storage would diverge across replicated Harper nodes.harper_oauth_mcp_clients— Claude Desktop cachesclient_id, ephemeral store breaks across restarts.initialAccessTokento gate.onUpstreamRevokedhook lands in v1.1 for apps that need it.mcp.resource), defaults to<issuer>/mcp. Issuer should be pinned in production viamcp.issuer(otherwise derived from request Host header).Dependencies
HarperFast/harper#465v1. Apps with their own MCP integrations (heskew/harper-kb, Cortex MCP server, custom apps) can adopt this immediately.HarperFast/harper#465v1.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
HarperFast/harper#465v1.1)onUpstreamRevokedhook)🤖 Generated with Claude Code