connect-claude
connect-claude — Foundation MCP + OAuth scaffold
One Next.js 15 app that does two things:
MCP server at
POST /mcp— JSON-RPC 2.0, Streamable-HTTP style, bearer-token protected. Exposes stubbed tools:list_sources,search_sources,summarize_source.OAuth 2.1 Authorization Server that Claude uses to authenticate users onto the MCP:
GET /.well-known/oauth-authorization-server(RFC 8414)GET /.well-known/openid-configurationGET /.well-known/oauth-protected-resource(RFC 9728, referenced from theWWW-Authenticatechallenge on 401s from/mcp)POST /oauth/register— Dynamic Client Registration (RFC 7591)GET /oauth/authorize— the multi-step "connect your sources" wizardPOST /oauth/token— authorization-code (PKCE S256 required) + refresh grants
Important: only the MCP-side OAuth (Claude → this app) is real. All provider connectors (Google Drive, Slack, …) are faked — a 1.5s mock spinner flips in-memory state. No real Google/Slack OAuth happens.
Quick start
pnpm install
cp .env.example .env.local # then set AUTH_SECRET
pnpm devApp runs at http://localhost:3000.
Connect from Claude
Claude CLI:
claude mcp add --transport http foundation http://localhost:3000/mcpClaude.ai / Claude Desktop (custom connector): add the URL
https://<your-host>/mcp. Claude will:
Probe
/mcp, receive a401with aWWW-Authenticateheader pointing at the protected-resource metadata.Discover the AS metadata, dynamically register a client at
/oauth/register.Send the user's browser to
/oauth/authorize?...→ the wizard.The user "connects" providers (mocked), hits Next, sees the celebration screen, clicks Back to Claude → we redirect to Claude's
redirect_uriwithcode+state.Claude exchanges the code at
/oauth/token(PKCE verified) for a JWT bearer token and calls the MCP tools.
Env vars
See .env.example. AUTH_SECRET is required (JWT HS256 signing key in dev —
use RS256 with a proper JWKS endpoint for production).
Storage
Everything is in-memory (codes, tokens, provider connections) behind a small
adapter interface (lib/oauth/store.ts) so it can be swapped for Cloudflare
D1/KV later. Client registrations are additionally persisted to
data/clients.json so they survive dev-server restarts.
Repo map
app/mcp/route.ts MCP JSON-RPC endpoint
app/oauth/authorize/page.tsx the wizard (UI mechanics from the prototype)
app/oauth/authorize/finalize/... POST: issues the auth code, returns redirect URL
app/oauth/token/route.ts token endpoint
app/oauth/register/route.ts dynamic client registration
app/.well-known/... AS / OIDC / protected-resource metadata
lib/oauth/* store, codes, tokens (jose), PKCE
lib/mcp/* protocol dispatch, tools, bearer auth
lib/providers/data.ts static provider catalog
components/* wizard UI components
reference/ hand-committed reference PDFs (do not touch)Spec links
MCP authorization: https://modelcontextprotocol.io/specification/draft/basic/authorization
OAuth 2.1: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1
RFC 8414 (AS metadata): https://www.rfc-editor.org/rfc/rfc8414
RFC 7591 (DCR): https://www.rfc-editor.org/rfc/rfc7591
RFC 9728 (protected resource metadata): https://www.rfc-editor.org/rfc/rfc9728