(feat): add --console-url testing flag for OAuth against alternative consoles#81
Conversation
…consoles Introduces a central testing-flag registry (flags.py): each flag declares its CLI name, env var, and help text once, and gets the --<name> argument and $<ENV> variable automatically, with the environment as the runtime source of truth. First flag: --console-url / MCP_CONSOLE_URL. The upstream authorization server hard-codes its consent redirect to the production console, so when the flag is set the MCP server advertises itself as the authorization server, mirrors the upstream discovery document with authorization_endpoint pointing at a local /oauth2/authorize proxy, and the proxy forwards to the real authorize endpoint and rewrites the consent redirect to the override console (e.g. https://new.appwrite.io). Token, registration, and JWKS endpoints stay upstream, so token validation is unchanged. Verified end to end against new.appwrite.io: discovery -> local proxy -> new console login/consent -> code -> PKCE token exchange -> authenticated MCP initialize/tools/call. docs/flags.md documents how to add, enable, and test flags.
Greptile SummaryAdds a centralized testing-flag registry (
Confidence Score: 5/5Safe to merge — the flag is opt-in and off by default, all three concerns raised in the prior review round are addressed, and the core token-validation path is untouched. The change is well-scoped: production behavior is unchanged when MCP_CONSOLE_URL is unset, the proxy 404s cleanly when the flag is off, and AppwriteTokenVerifier reads the un-proxied discovery cache so JWKS/issuer validation continues against the real Appwrite server. The empty-query bare-? fix and the CLI-empty-value-clears-env behavior are both present and covered by new tests. No files require special attention. Important Files Changed
Reviews (2): Last reviewed commit: "(fix): address review — no bare '?' on q..." | Re-trigger Greptile |
…CLI can clear env-set flags - The consent-redirect rewrite no longer emits a trailing bare '?' when the upstream Location has no query string. - Flag CLI arguments now default to None instead of mirroring the env var, so an explicit --console-url "" clears a flag exported in the shell while an omitted argument leaves the environment untouched. - Tests: query-less consent redirect, 404 when the flag is unset, and CLI clear-vs-omit semantics.
What
Adds a centralized testing-flag registry and its first flag,
--console-url/MCP_CONSOLE_URL, so testers can run the hosted OAuth flow through a pre-release console (e.g. the new console atnew.appwrite.io) instead of the production console.Why
The Appwrite authorization server hard-codes its login/consent redirect to the production console (
_APP_CONSOLE_OAUTH2_AUTHORIZATION_URLserver-side), so testers had no way to exercise MCP OAuth against the new console.How
flags.py(new) — central registry: each flag declares CLI name, env var, and help once, and automatically gets the--<name>argument and$<ENV>variable. The environment is the runtime source of truth; values are read at request time so tests toggle them viaos.environ.auth.py— with the flag set, protected-resource metadata names the MCP server itself as the authorization server, and the mirrored discovery document rewrites onlyauthorization_endpointto a local proxy. Token/registration/JWKS endpoints stay upstream, so token validation is unchanged.http_app.py— new/oauth2/authorizeproxy (404 when the flag is off): forwards the request to the real authorize endpoint (keeping upstream validation), rewrites the…/console/oauth2/consentredirect to<console-url>/oauth2/consent, and passes error redirects / non-redirect responses through verbatim. Also adds a/.well-known/openid-configurationalias for clients that discover via OIDC.docs/flags.md(new) — how to add a flag, enable it (CLI or env), and verify it (curl checks per hop + fullclaude mcp addflow). Linked from AGENTS.md.Verification
Verified end to end against
new.appwrite.io: discovery → local authorize proxy → new-console sign-in + consent → authorization code → PKCE token exchange (with RFC 8707resource) → authenticated MCPinitialize,tools/list, andtools/callagainst the flag-enabled server.Unit tests: 173 pass; ruff/black/pyright clean.