Sign-in for MCP servers behind a login form¶
For FastMCP servers in front of another service. claude.ai and the Claude apps sign in once through your server's own login (a Trilium password, a Paperless login) and then only hold OAuth tokens. Your server turns each login into a grant and reads it back on every request.
Building in TypeScript?
This library is Python only. TypeScript apps, with or without an MCP endpoint, sign in with Better Auth: see Coming from TypeScript.
How it works¶
sequenceDiagram
participant C as MCP client (claude.ai)
participant S as Your MCP server + mcp-login-oauth
participant X as The service behind it
C->>S: register, then authorize (PKCE)
S->>C: login page (your fields)
C->>S: the person submits the form
S->>X: your check, e.g. log in to the service
X-->>S: OK, a service token
S-->>C: code, then access and refresh token
C->>S: MCP request with Bearer token
S->>S: verify → your grant (the service token)
Your code supplies the login fields and the check that turns a submitted form into a grant. The library does the rest:
- discovery (RFC 8414, RFC 9728), dynamic client registration (RFC 7591), PKCE
S256, rotating refresh tokens; - revocation (RFC 7009), also for public clients like claude.ai;
- tokens bound to a resource (RFC 8707) and the issuer on the code redirect (RFC 9207);
- an encrypted store that survives restarts: a code or refresh token works once, also after a restart;
- the login page and honest dead-end pages for broken flows;
- protection against password guessing.
Every lifetime and refusal is on Lifetimes, flow and limits.
Used by¶
trilium-mcp, invoiceninja-mcp, paperless-ngx-mcp and the recall engine in trilium-llm-wiki.
License¶
Copyright © 2026 Marcel Bruckner. Licensed under the GNU Affero General Public License v3.0 or later.