HTTP endpoints
When TRANSPORT=http (the default), polar-flow-mcp exposes the following
HTTP endpoints on BIND_ADDRESS:PORT.
Endpoints
Section titled “Endpoints”All /.well-known/* and /mcp/oauth/* endpoints are only mounted when OAuth
is enabled (OAUTH_PUBLIC_URL set).
| Path | Method | Auth | Purpose |
|---|---|---|---|
/healthz | GET | none | Liveness probe. Returns 200 ok if the process is up. |
/mcp, /mcp/ | POST + SSE | Bearer if auth enabled, else none | Streamable HTTP MCP endpoint. With MCP_API_KEY set, requires that exact key as the Bearer token. With OAuth enabled, requires a valid Authorization: Bearer access token (an EdDSA JWT this server signed). |
/.well-known/oauth-protected-resource | GET | none | RFC 9728 protected-resource metadata. Advertises resource and authorization_servers (which point back at this server). |
/.well-known/oauth-authorization-server | GET | none | RFC 8414 authorization-server metadata: the authorize/token/registration endpoints and S256 PKCE support. |
/mcp/oauth/register | POST | none | RFC 7591 Dynamic Client Registration. Issues a stateless client_id for a public PKCE client; redirect URIs are restricted to the Claude callbacks + loopback. |
/mcp/oauth/authorize | GET | forward-auth | Browser consent endpoint. Must be forward-auth’d by your proxy — the proxy logs the user in and sets the identity header; the server checks the email allowlist and issues a PKCE-bound code. |
/mcp/oauth/token | POST | none (PKCE) | Token endpoint: authorization_code (with PKCE verification) and refresh_token grants. Returns the signed access + refresh JWTs. |
What’s gone
Section titled “What’s gone”The previous OAuth flow (/oauth/login, /oauth/callback) and the
proxy-auth contract (X-Proxy-Secret header, Remote-User injection) no
longer exist. The Polar Flow web API uses cookie-based session auth — there
is no per-user OAuth handshake to host.
Authentication
Section titled “Authentication”There are three supported postures. The two authenticated ones are mutually
exclusive — setting both MCP_API_KEY and OAUTH_PUBLIC_URL is a startup error.
- Local / trusted-network (default). With neither
MCP_API_KEYnorOAUTH_PUBLIC_URLset,/mcphas no built-in auth. Run it on127.0.0.1for Claude Code / Claude Desktop on the same machine, or behind a trusted-network barrier (Tailscale, VPN). IfBIND_ADDRESSis non-localhost and inbound auth is off, the server logs a warning at startup. - Public, API-key-protected. Set
MCP_API_KEYto a secret of at least 24 characters. Every/mcprequest must present it asAuthorization: Bearer <key>; the comparison is constant-time and anything else gets401with a bareWWW-Authenticate: Bearerchallenge. No additional endpoints are mounted — there is nothing for a client to discover, the key is configured out of band. Suits a single-operator deployment where standing up a forward-auth proxy is more machinery than the situation needs. - Public, OAuth-protected. Set
OAUTH_PUBLIC_URL(+OAUTH_ALLOWED_EMAIL+OAUTH_TRUSTED_PROXIES) to turn the server into its own OAuth 2.1 Authorization Server. Unauthenticated requests get401with aWWW-Authenticate: Bearer resource_metadata="…"header; valid Bearer tokens (EdDSA JWTs the server signed) are verified locally on every call. This path serves Claude.ai web/mobile and Claude Code — see Expose the server securely.
Because the server provides Dynamic Client Registration, Claude Code (CLI) works over the public OAuth path too — no separate transport needed.
Health-check semantics
Section titled “Health-check semantics”/healthz returns 200 ok as long as the process is alive. It does not
verify that Polar is reachable or that the cookie jar is still valid — a
401 on the first MCP call after a cookie expiry triggers the silent-refresh
path automatically, so a hard “Polar reachable” check would either be noisy
(every refresh window) or stale.
If you need a deeper probe, call get_user_info from your MCP client; it
exercises the full request → refresh-if-needed → response path.