English | Русский
A local stdio↔Streamable HTTP MCP proxy in Go for connecting remote MCP servers to stdio-only clients (Claude Desktop and friends).
mcp-remote is a proxy that lets stdio-only MCP clients (primarily Claude
Desktop) talk to remote MCP servers exposed over the
Streamable HTTP
transport (MCP specification 2025-03-26). It is a Go port of the
mcp-remote npm package, focused
on a single self-contained binary with no runtime dependencies.
Under the hood, mcp-remote runs as a child process of the client, reads JSON-RPC messages from stdin, forwards them over HTTPS to the remote MCP endpoint, and pipes responses (including the SSE stream of server-initiated messages) back to stdout. On HTTP 401 it automatically launches the OAuth 2.1 flow (PKCE + RFC7591 Dynamic Client Registration + RFC9728/RFC8414 discovery), opens the browser, catches the localhost redirect, and persists tokens to disk with 0600 permissions. Subsequent runs reuse the saved tokens transparently.
go install github.com/dezer32/mcp-remote@latestThe binary will be installed to $(go env GOBIN) (defaults to $GOPATH/bin).
Download the archive for your platform from
GitHub Releases: builds
are available for darwin, linux, windows on amd64 and arm64.
Extract and place mcp-remote into any directory on your $PATH.
# macOS / Linux example
tar -xzf mcp-remote_<version>_<os>_<arch>.tar.gz
sudo install mcp-remote /usr/local/bin/brew install dezer32/tap/mcp-remotemcp-remote is launched by the client — you typically do not need to invoke it manually. Just declare the command and arguments in the client's configuration.
Configuration file:
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Linux | ~/.config/Claude/claude_desktop_config.json |
Minimal example:
{
"mcpServers": {
"my-server": {
"command": "/usr/local/bin/mcp-remote",
"args": ["https://your-mcp-server.example.com/mcp"]
}
}
}Example with an Authorization header and environment variable
substitution:
{
"mcpServers": {
"my-server": {
"command": "/usr/local/bin/mcp-remote",
"args": [
"https://api.example.com/mcp",
"--header",
"Authorization:Bearer ${TOKEN}"
],
"env": {
"TOKEN": "sk-..."
}
}
}
}More examples are in examples/claude_desktop_config.json.
mcp-remote <server-url> [port] [flags]
| Flag | Argument | Description |
|---|---|---|
--header |
"K: V" |
HTTP header appended to every request. Repeatable. Supports ${ENV} interpolation. |
--allow-http |
— | Allow non-HTTPS server-url (disabled by default). |
--debug |
— | Verbose logs to stderr (DEBUG level). |
--silent |
— | Log errors only (ERROR level). |
--auth-timeout |
30s / 30 |
OAuth callback timeout. Accepts a Go duration (30s, 2m) or a number of seconds. Default: 30s. |
--static-oauth-client-metadata |
<json> or @<path> |
Override client_metadata for DCR. Inline JSON or @file.json. |
--static-oauth-client-info |
<json> or @<path> |
Pre-existing client_id (and optionally client_secret) — DCR is skipped. |
--resource |
<uri> |
Override the RFC9728 resource URI (auto-discovered by default). |
--host |
127.0.0.1 |
Bind host for the local OAuth callback. Default: 127.0.0.1. |
--config-dir |
<path> |
Root directory for token and OAuth metadata storage. |
Positional arguments: the first is the required remote MCP server URL;
the second (optional) is the desired port for the local callback server.
If omitted or 0, the OS picks the port.
| Variable | Purpose |
|---|---|
MCP_REMOTE_CONFIG_DIR |
Overrides the token storage root (equivalent to --config-dir; the flag takes precedence). |
BROWSER |
Path to the executable that opens the OAuth URL. When set, it overrides open / xdg-open / cmd /c start. |
On HTTP 401 Unauthorized from the remote MCP server, mcp-remote
automatically launches the OAuth flow:
- Parses
WWW-Authenticateand/or performs RFC9728 protected-resource discovery to locate the Authorization Server. - Performs RFC8414 metadata discovery against the Authorization Server.
- If needed, performs RFC7591 Dynamic Client Registration (or uses the
data from
--static-oauth-client-info). - Starts a local HTTP server on
--host:portto receive the callback. - Opens the user's browser at the authorization endpoint
(PKCE S256, state, redirect_uri =
http://<host>:<port>/callback). - After a successful redirect, exchanges the
codefor access/refresh tokens. - Persists tokens, client info, and server metadata to the config-dir.
Root: --config-dir, or MCP_REMOTE_CONFIG_DIR, or the system
configuration directory (~/.config/mcp-remote on Linux,
~/Library/Application Support/mcp-remote on macOS,
%AppData%\mcp-remote on Windows).
Inside, there is one subdirectory per server, named after the first 16
hex characters of sha256(server-url):
<config-dir>/
<hash16>/
tokens.json # access + refresh token, expiry
client.json # client_id / client_secret
metadata.json # discovered authorization server metadata
All files are 0600; directories are 0700.
# macOS
rm -rf "$HOME/Library/Application Support/mcp-remote/<hash16>"
# Linux
rm -rf "$HOME/.config/mcp-remote/<hash16>"
# Windows (PowerShell)
Remove-Item -Recurse -Force "$env:AppData\mcp-remote\<hash16>"To reset everything at once, remove the entire root directory.
- No output at all — pass
--debug; mcp-remote writes detailed logs to stderr, and Claude Desktop captures subprocess stderr in its own log file. - OAuth window does not open — set the
BROWSERenvironment variable to the path of a browser executable, or open the URL printed to stderr manually. - Hangs on callback — increase
--auth-timeoutand verify that the redirect_uri is allowed on the Authorization Server side. - Server does not support DCR — register the client manually and
pass
--static-oauth-client-info '{"client_id":"...","client_secret":"..."}'(or@/path/to/file.json). - Reset stuck state — delete the token directory for that server (see above) and restart the client.
- HTTP instead of HTTPS — in a dev environment, pass
--allow-http. Do not do this in production.
- HTTPS is mandatory. Non-HTTPS URLs are rejected unless
--allow-httpis provided (development only). - Cross-origin redirects during the token-endpoint exchange are blocked
— protection against
code/refresh_tokenleakage to a third-party host. - Reserved headers (
Mcp-Session-Id,Accept,Content-Type,Content-Length,Host,Connection,Upgrade, etc.) cannot be overridden via--header— attempting to do so fails validation. - If
Authorizationis supplied via--header, it overrides the OAuth flow: mcp-remote will not initiate authorization and will not persist tokens. - Token files are stored with
0600permissions; directories with0700. ${ENV}references in--headervalues are resolved from the mcp-remote process environment; in Claude Desktop the environment is set via theenvkey in the server config.
| Package | Purpose |
|---|---|
internal/jsonrpc |
JSON-RPC 2.0 types and encoding |
internal/logging |
Structured logging (slog → stderr) |
internal/config |
CLI flags, env vars, validation |
internal/stdio |
stdin/stdout transport |
internal/httpmcp |
Streamable HTTP client to the remote MCP |
internal/oauth |
OAuth 2.1 (PKCE + RFC7591 DCR + RFC9728/RFC8414 discovery) |
internal/proxy |
JSON-RPC routing between transport and remote |
main.go |
Wire-up |
Build: make build. Tests: make test. Integration: make test-integration.
MIT — see LICENSE.