Summary
Authorising an MCP client against https://voicemode.dev/mcp cannot complete. The consent screen renders correctly, but clicking Approve results in POST https://voicemode.dev/consent returning HTTP 503 with an empty body. Because there is no body to render, the browser stays on the consent page and the button appears to do nothing — no error is surfaced to the user.
No authorization code is issued, the loopback listener is never called, and no tokens are ever written.
Notably, the CLI auth path works fine (voicemode connect auth login → logged in, refresh token present) and the web client is connected. It is specifically the MCP OAuth path that fails, which should help narrow this down.
Environment
- macOS 14.6 (Darwin 23.6.0), Claude Code
- voicemode plugin 8.12.0p0,
mcp-remote 0.1.38, Node v22.22.0
- Reproduced in both Chrome and Safari (separate profiles, separate cookie jars)
- Reproduced before and after a complete plugin uninstall/reinstall (plugin, cache, marketplace, data dirs, and
~/.mcp-auth state all purged; same version reinstalled)
- Account authenticates via Auth0 (
login.us.auth0.com)
Steps to reproduce
npx -y mcp-remote https://voicemode.dev/mcp 5450
- Open the printed
/authorize URL.
- Complete the Auth0/Google sign-in leg — this succeeds; the consent card renders with the correct name, email and avatar.
- Click Approve.
Expected: 302 to http://localhost:5450/oauth/callback?code=…, tokens written to ~/.mcp-auth/.
Actual: POST /consent → 503, empty body. The page does not navigate. mcp-remote sits at Authentication required. Waiting for authorization... indefinitely.
Reproduced across 9 clean flows.
Key finding: submission method changes the outcome
Same origin, same session, same consent_key, same form body:
| Submission method |
Result |
| Top-level form navigation (the Approve button) |
503, empty body |
Background fetch() with identical body |
302 redirect issued correctly |
Replayed / previously-failed consent_key |
400 "Session Expired" |
The handler works when invoked as a subresource request and fails when invoked as a navigation. That points at the navigation path specifically — possibly the Sec-Fetch-Mode: navigate / Upgrade-Insecure-Requests: 1 request, or whatever issues the plaintext http://localhost redirect for a document-level request.
This is not browser-specific: Chrome and Safari behave identically, so it is not an Upgrade-Insecure-Requests quirk of a single engine.
Ruled out (client side)
- Stale local auth state —
~/.mcp-auth/ wiped between every attempt.
- Stale plugin install — full uninstall + reinstall changed nothing.
- Click interception —
document.elementFromPoint() at the button centre returns the button itself; no overlay.
- JS preventing submit — the
submit event fires and is not defaultPrevented. The page's only script is the Cloudflare Insights beacon.
- Loopback binding / IPv6 — the listener binds
127.0.0.1:5450; http://localhost:5450/oauth/callback resolves and answers (400 for a missing code, as expected).
- Racing consent sessions — suppressed
mcp-remote's automatic browser launch so exactly one consent session existed. Still 503.
The MCP endpoint itself is otherwise healthy: POST /mcp returns 401 with a correct WWW-Authenticate: Bearer challenge, /.well-known/oauth-authorization-server resolves, and dynamic client registration at /register succeeds.
Related: can the bridge use the CLI token instead?
Since voicemode connect auth login already yields a valid token, I tried using it with the native bridge (VOICEMODE_MCP_URL / VOICEMODE_MCP_TOKEN) to bypass the consent flow:
| Endpoint |
Result with CLI access token |
https://voicemode.dev/mcp |
401 invalid_token |
https://app.voicemode.dev/mcp |
401 invalid_token |
https://api.voicemode.dev/mcp |
530 (error 1033, no origin) |
The Auth0 token appears to be a different audience from what /mcp accepts, so there is currently no way to reach the MCP endpoint without the broken consent flow. If the bridge is intended to work with CLI credentials, that would be a useful documented escape hatch while the consent bug is open.
Doc drift
.claude/skills/voicemode-connect/SKILL.md instructs users to add npx -y mcp-remote https://voicemode.dev/mcp as a separate MCP server, and links to docs/connect/README.md, docs/connect/architecture.md, docs/connect/setup/claude-code.md and docs/connect/reference/mcp-tools.md — none of which exist in the 8.12.0p0 package. It also doesn't mention the voicemode connect auth command group or the native VOICEMODE_MCP_URL bridge, which appear to be the actually-supported path.
Minor
https://voicemode.dev/logo.png returns 404 on the consent page (broken image in the card), which may indicate a partial deploy.
Suggested fixes
- Fix the 503 on the navigation path of
POST /consent.
- Regardless of the above — never return an empty-bodied 5xx to this form. Render an error page so the failure is visible rather than presenting as a dead button.
- Refresh
SKILL.md to describe the supported Connect path.
Summary
Authorising an MCP client against
https://voicemode.dev/mcpcannot complete. The consent screen renders correctly, but clicking Approve results inPOST https://voicemode.dev/consentreturning HTTP 503 with an empty body. Because there is no body to render, the browser stays on the consent page and the button appears to do nothing — no error is surfaced to the user.No authorization code is issued, the loopback listener is never called, and no tokens are ever written.
Notably, the CLI auth path works fine (
voicemode connect auth login→ logged in, refresh token present) and the web client is connected. It is specifically the MCP OAuth path that fails, which should help narrow this down.Environment
mcp-remote0.1.38, Node v22.22.0~/.mcp-authstate all purged; same version reinstalled)login.us.auth0.com)Steps to reproduce
npx -y mcp-remote https://voicemode.dev/mcp 5450/authorizeURL.Expected: 302 to
http://localhost:5450/oauth/callback?code=…, tokens written to~/.mcp-auth/.Actual:
POST /consent→503, empty body. The page does not navigate.mcp-remotesits atAuthentication required. Waiting for authorization...indefinitely.Reproduced across 9 clean flows.
Key finding: submission method changes the outcome
Same origin, same session, same
consent_key, same form body:fetch()with identical bodyconsent_keyThe handler works when invoked as a subresource request and fails when invoked as a navigation. That points at the navigation path specifically — possibly the
Sec-Fetch-Mode: navigate/Upgrade-Insecure-Requests: 1request, or whatever issues the plaintexthttp://localhostredirect for a document-level request.This is not browser-specific: Chrome and Safari behave identically, so it is not an
Upgrade-Insecure-Requestsquirk of a single engine.Ruled out (client side)
~/.mcp-auth/wiped between every attempt.document.elementFromPoint()at the button centre returns the button itself; no overlay.submitevent fires and is notdefaultPrevented. The page's only script is the Cloudflare Insights beacon.127.0.0.1:5450;http://localhost:5450/oauth/callbackresolves and answers (400 for a missingcode, as expected).mcp-remote's automatic browser launch so exactly one consent session existed. Still 503.The MCP endpoint itself is otherwise healthy:
POST /mcpreturns401with a correctWWW-Authenticate: Bearerchallenge,/.well-known/oauth-authorization-serverresolves, and dynamic client registration at/registersucceeds.Related: can the bridge use the CLI token instead?
Since
voicemode connect auth loginalready yields a valid token, I tried using it with the native bridge (VOICEMODE_MCP_URL/VOICEMODE_MCP_TOKEN) to bypass the consent flow:https://voicemode.dev/mcp401 invalid_tokenhttps://app.voicemode.dev/mcp401 invalid_tokenhttps://api.voicemode.dev/mcp530(error 1033, no origin)The Auth0 token appears to be a different audience from what
/mcpaccepts, so there is currently no way to reach the MCP endpoint without the broken consent flow. If the bridge is intended to work with CLI credentials, that would be a useful documented escape hatch while the consent bug is open.Doc drift
.claude/skills/voicemode-connect/SKILL.mdinstructs users to addnpx -y mcp-remote https://voicemode.dev/mcpas a separate MCP server, and links todocs/connect/README.md,docs/connect/architecture.md,docs/connect/setup/claude-code.mdanddocs/connect/reference/mcp-tools.md— none of which exist in the 8.12.0p0 package. It also doesn't mention thevoicemode connect authcommand group or the nativeVOICEMODE_MCP_URLbridge, which appear to be the actually-supported path.Minor
https://voicemode.dev/logo.pngreturns 404 on the consent page (broken image in the card), which may indicate a partial deploy.Suggested fixes
POST /consent.SKILL.mdto describe the supported Connect path.