https://github.com/vchaindz/go-mcp-proxy
A stdio-to-HTTP proxy for MCP (Model Context Protocol) servers. It lets stdio-based MCP clients like Claude Code connect to remote MCP servers over HTTP or SSE, with support for custom headers, TLS options, and authentication.
https://github.com/vchaindz/go-mcp-proxy
mcp proxy standalone stdio stdio-mcp
Last synced: about 2 months ago
JSON representation
A stdio-to-HTTP proxy for MCP (Model Context Protocol) servers. It lets stdio-based MCP clients like Claude Code connect to remote MCP servers over HTTP or SSE, with support for custom headers, TLS options, and authentication.
- Host: GitHub
- URL: https://github.com/vchaindz/go-mcp-proxy
- Owner: vchaindz
- License: mit
- Created: 2026-03-18T16:24:47.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-05-08T08:26:04.000Z (about 2 months ago)
- Last Synced: 2026-05-08T10:31:00.646Z (about 2 months ago)
- Topics: mcp, proxy, standalone, stdio, stdio-mcp
- Language: Go
- Homepage:
- Size: 54.7 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# go-mcp-proxy
A stdio-to-HTTP proxy for MCP (Model Context Protocol) servers. It lets stdio-based MCP clients like Claude Code connect to remote MCP servers over HTTP or SSE, with support for custom headers, TLS options, and authentication.
## Build
Requires Go 1.23+.
```bash
go build -o go-mcp-proxy ./cmd/go-mcp-proxy/
```
## Usage
```
go-mcp-proxy [flags] [server-url]
Flags:
-config string path to JSON config file
-server string server name from config (default: first/only server)
-insecure skip TLS certificate verification
-type string transport: http, sse, auto (default "auto")
-header value custom header key=value (repeatable)
```
### Basic
```bash
./go-mcp-proxy https://mcp.example.com/mcp
```
### With authentication and custom headers
```bash
./go-mcp-proxy \
-header "Authorization=Bearer my-token" \
-header "X-Api-Key=abc123" \
https://mcp.example.com/mcp
```
### Self-signed / mismatched TLS certificates
```bash
./go-mcp-proxy -insecure https://10.0.0.5:8443/mcp
```
### Calling tools (subcommand mode)
```bash
# Linux/macOS — single quotes are fine
./go-mcp-proxy call https://mcp.example.com/mcp prtg_get_sensors '{"limit":1}'
# Windows PowerShell — single quotes preserve the JSON literally (same as Unix)
.\mcp-sse-proxy.exe call https://mcp.example.com/mcp prtg_get_sensors '{"limit":1}'
# Windows cmd.exe — single quotes are literal; escape inner double quotes
mcp-sse-proxy.exe call https://mcp.example.com/mcp prtg_get_sensors "{\"limit\":1}"
# Any shell — read JSON from a file (no quoting headaches)
./go-mcp-proxy call https://mcp.example.com/mcp prtg_get_sensors @args.json
```
> **Why this matters on Windows:** PowerShell and `cmd.exe` both strip bare
> double quotes from arguments before the program sees them, so passing
> `{"sensor_id":65635}` ends up as `{sensor_id:65635}` (invalid JSON). The
> proxy detects this case and prints a "did you mean" suggestion, but the
> simplest fix is to wrap the whole payload in single quotes (PowerShell)
> or use `@file` form.
The `@file` form also works inside the `debug` REPL (`call prtg_get_sensors @args.json`).
### Using a config file
Create a JSON config:
```json
{
"mcpServers": {
"my-server": {
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer my-token"
},
"insecure": false,
"type": "auto"
}
}
}
```
```bash
./go-mcp-proxy -config servers.json -server my-server
```
## Environment Variables
Environment variables are the lowest priority — CLI flags and config file values take precedence.
| Variable | Description |
|---|---|
| `MCP_SERVER_URL` | Server URL (also accepts legacy `MCP_SSE_URL`) |
| `MCP_AUTH_TOKEN` | Sets `Authorization: Bearer ` header |
| `MCP_HEADERS` | Comma-separated headers: `Key1=Value1,Key2=Value2` |
| `MCP_INSECURE` | Skip TLS verification (`true` or `1`) |
| `MCP_TRANSPORT` | Transport type: `http` or `sse` |
Examples:
```bash
# URL + bearer token via env
export MCP_SERVER_URL=https://mcp.example.com/mcp
export MCP_AUTH_TOKEN=my-secret-token
./go-mcp-proxy
# Multiple headers via env
export MCP_HEADERS="Authorization=Bearer tok123,X-Api-Key=key456"
./go-mcp-proxy https://mcp.example.com/mcp
# Skip TLS via env
MCP_INSECURE=true ./go-mcp-proxy https://10.0.0.5:8443/mcp
```
## Configuration Priority
Settings are resolved in this order (first wins):
1. CLI flags (`-header`, `-insecure`, positional URL, `-type`)
2. Config file (`-config`)
3. Environment variables (`MCP_SERVER_URL`, `MCP_AUTH_TOKEN`, etc.)
## Transport Modes
The proxy supports two MCP transport protocols:
- **Streamable HTTP** — current MCP standard. Uses `POST` for messages, optional `GET` SSE for server-initiated notifications, session management via `Mcp-Session-Id`.
- **Legacy SSE** — older protocol. Opens a persistent `GET` SSE connection for receiving, `POST` for sending.
By default (`-type auto`), the proxy tries Streamable HTTP first and falls back to Legacy SSE if the server doesn't support it.
## Claude Code Integration
Add the proxy to `.mcp.json` in your project directory or globally at `~/.claude/.mcp.json`.
### Simple — direct URL
```json
{
"mcpServers": {
"my-server": {
"command": "/path/to/go-mcp-proxy",
"args": ["https://mcp.example.com/sse"]
}
}
}
```
### With authentication
```json
{
"mcpServers": {
"my-server": {
"command": "/path/to/go-mcp-proxy",
"args": [
"-header", "Authorization=Bearer my-token",
"https://mcp.example.com/mcp"
]
}
}
}
```
### With env variables (keeps secrets out of config)
```json
{
"mcpServers": {
"my-server": {
"command": "/path/to/go-mcp-proxy",
"args": ["https://mcp.example.com/mcp"],
"env": {
"MCP_AUTH_TOKEN": "my-secret-token"
}
}
}
}
```
### Self-signed TLS + auth header
```json
{
"mcpServers": {
"internal-server": {
"command": "/path/to/go-mcp-proxy",
"args": [
"-insecure",
"-header", "Authorization=whm root:YOUR_API_TOKEN",
"https://10.0.0.5:2087/mcp"
]
}
}
}
```
### Using a config file
```json
{
"mcpServers": {
"my-server": {
"command": "/path/to/go-mcp-proxy",
"args": [
"-config", "/path/to/servers.json",
"-server", "my-server"
]
}
}
}
```
### Multiple headers via env
```json
{
"mcpServers": {
"my-server": {
"command": "/path/to/go-mcp-proxy",
"args": [],
"env": {
"MCP_SERVER_URL": "https://mcp.example.com/mcp",
"MCP_HEADERS": "Authorization=Bearer tok123,X-Tenant-Id=acme",
"MCP_INSECURE": "true"
}
}
}
}
```
### Windows
```json
{
"mcpServers": {
"my-server": {
"command": "C:\\tools\\go-mcp-proxy.exe",
"args": ["https://mcp.example.com/sse"]
}
}
}
```
## How It Works
```
MCP Client (e.g. Claude Code)
│ stdin (JSON-RPC 2.0)
▼
┌──────────────┐
│ go-mcp-proxy │ ← flags / config / env vars
└──────────────┘
│ HTTPS POST + custom headers
▼
Remote MCP Server
│ JSON response or SSE stream
▼
┌──────────────┐
│ go-mcp-proxy │
└──────────────┘
│ stdout (JSON-RPC 2.0)
▼
MCP Client
```
The proxy reads JSON-RPC messages from stdin, forwards them as HTTP POST requests to the remote server, and writes responses back to stdout. All logging goes to stderr so it doesn't interfere with the protocol.
## Project Structure
```
cmd/go-mcp-proxy/main.go CLI entrypoint
internal/proxy/ Proxy library
config.go Config file + header flag parsing
jsonrpc.go JSON-RPC types and stdin/stdout I/O
transport.go HTTP client and header helpers
sse.go SSE parser and URL resolution
legacy_sse.go Legacy SSE transport
streamable.go Streamable HTTP transport
```
## License
See [LICENSE](LICENSE) file.