[BUG] Claude Code remote HTTP MCP OAuth is not viable for plugin-installed MCP servers on remote/SSH machines, especially with Google OAuth redirect constraints
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Claude Code’s native HTTP MCP OAuth flow does not work reliably when Claude Code is running on a remote machine, such as over SSH or in a headless development environment.
The problem is the final OAuth redirect back to Claude Code. Claude Code appears to use a loopback redirect URI such as:
http://localhost:<ephemeral-port>/callback
When the browser is running on the user’s local machine but Claude Code is running on a remote machine, localhost resolves to the user’s local machine, not the remote host where Claude Code is listening. The browser then fails to deliver the authorization response to Claude Code.
This creates a major deployment problem for plugin-installed remote MCP servers that use OAuth. The same plugin configuration may work on a user’s local laptop but fail on remote machines.
Workarounds such as pinning oauth.callbackPort are not viable for broad plugin distribution because:
- Every user would need to reserve and/or forward the same port.
- Multiple MCP servers may collide on the same callback port.
- OAuth providers such as Google require explicit authorized redirect URIs.
- Each MCP/OAuth server would need to pre-register exact callback URLs.
- A shared plugin cannot realistically encode per-user/per-machine callback ports.
This makes one-plugin deployment across local and remote Claude Code environments impractical.
What Should Happen?
Claude Code should provide a first-class remote/headless-compatible OAuth completion path for native HTTP MCP servers.
Possible acceptable behaviors:
1. After browser authentication, allow the user to copy the final callback URL and paste it into Claude Code.
2. Provide a documented device-code-style flow for MCP OAuth in remote/headless environments.
3. Provide a stable HTTPS callback broker controlled by Claude/Anthropic that can hand completion back to the remote Claude Code session.
4. Provide documented support for remote SSH environments where the callback listener is on a remote host but the browser runs locally.
5. Make the manual callback fallback consistently available for plugin-installed HTTP MCP servers, not only manually configured MCP servers.
The key requirement is that a plugin author should be able to ship a single standards-compliant remote HTTP MCP configuration:
{
"mcpServers": {
"example-server": {
"type": "http",
"url": "https://example.com/mcp"
}
}
}
and have it work in both:
- Claude Code running locally
- Claude Code running on a remote SSH/headless machine
without requiring a separate plugin, a local stdio proxy, or per-user callback-port configuration.
Error Messages/Logs
When authenticating from Claude Code running on a remote machine, the browser is redirected to a localhost callback URL and fails with:
This page isn’t working
localhost didn’t send any data.
ERR_EMPTY_RESPONSE
The same remote MCP server can authenticate successfully when using a local stdio proxy that owns the OAuth flow, for example:
npx -y mcp-remote https://example.com/mcp
Representative successful proxy behavior:
Using automatically selected callback port: 34888
Discovering OAuth server configuration...
Discovered authorization server: https://example.com/
Connecting to remote server: https://example.com/mcp
Using transport strategy: http-first
Please authorize this client by visiting:
https://example.com/authorize?...&redirect_uri=http%3A%2F%2Flocalhost%3A34888%2Foauth%2Fcallback...
OAuth callback server running at http://127.0.0.1:34888
Authentication required. Waiting for authorization...
Auth code received, resolving promise
Completing authorization...
Connected to remote server using StreamableHTTPClientTransport
Local STDIO server running
Proxy established successfully between local STDIO and remote StreamableHTTPClientTransport
This suggests that:
- The remote MCP server is reachable.
- OAuth discovery works.
- The authorization server works.
- The user can complete browser-based authentication.
- The failure is specific to Claude Code’s native HTTP MCP OAuth callback behavior in remote/headless environments.
Error Messages/Logs
Steps to Reproduce
- Configure a remote HTTP MCP server that requires OAuth.
- Add it to Claude Code using native HTTP MCP configuration:
{
"mcpServers": {
"example-server": {
"type": "http",
"url": "https://example.com/mcp"
}
}
}
- Run Claude Code on a remote machine, such as over SSH.
- Trigger MCP authentication from Claude Code.
- Complete authentication in a browser running on the user’s local machine.
- Observe that the browser is redirected to a loopback URL such as:
http://localhost:<port>/callback
- The browser fails with:
This page isn’t working
localhost didn’t send any data.
ERR_EMPTY_RESPONSE
- As a comparison, run the same remote MCP server through a stdio proxy on the same remote machine:
npx -y mcp-remote https://example.com/mcp
- Observe that OAuth succeeds through the proxy flow, confirming that the MCP server and OAuth provider are functional.
Expected result: native HTTP MCP OAuth in Claude Code should support a remote/headless completion path.
Actual result: OAuth completion depends on browser access to a localhost callback listener, which breaks when Claude Code is running on a different machine than the browser.
Claude Model
Not sure / Multiple models
Is this a regression?
No, this never worked
Last Working Version
_No response_
Claude Code Version
2.1.179
Platform
Other
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Cursor
Additional Information
_No response_
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗