Skip to main content
Glama
README.md
# mcp-relay

> šŸ‡ÆšŸ‡µ ę—„ęœ¬čŖžē‰ˆ: [README.ja.md](README.ja.md)

Relay a stdio MCP server to authenticated HTTP on `127.0.0.1`, so a sandboxed
MCP client can use a server that has to run outside the sandbox.

## Why

An MCP client starts its stdio servers as child processes, so they inherit
whatever sandbox the client runs in. Some servers cannot work from there: a
server that talks to the desktop session (calendar and reminder access,
permission prompts, other applications) is refused by the operating system as
soon as it is confined.

Loosening the sandbox until the server works defeats the sandbox. The relay
keeps the two apart instead:

```
  inside the sandbox                 outside the sandbox
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”            ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ MCP client          │  HTTP on   │ mcp-relay ── stdio ── MCP server  │
│ (type: http)        ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā–ŗā”‚ 127.0.0.1, bearer token           │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜            ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
```

The sandbox only has to allow a connection to one loopback port. What the
client can do outside is exactly what that one server offers.

## How it behaves

- Listens on `127.0.0.1` only. There is no option to listen anywhere else.
- Every request needs `Authorization: Bearer <token>`. The token is read from
  a file or an environment variable, never from the command line.
- Requests whose `Host` header is not the loopback address are refused, which
  closes the DNS rebinding route from a browser.
- One server process per client session. The process is stopped when the
  session ends, when the relay stops, or when the watched process is gone.
- The token is removed from the environment of the server processes.

## Requirements

- Node.js 20 or later
- [Task](https://taskfile.dev) to run the development commands

## Quick start

```bash
git clone https://github.com/Synforger/mcp-relay.git
cd mcp-relay
task setup

export MCP_RELAY_TOKEN="$(openssl rand -hex 24)"
node bin/mcp-relay.mjs --port 8765 -- npx -y @modelcontextprotocol/server-everything
```

Register the relay in the client as an HTTP server. For a client that reads
`.mcp.json` and expands environment variables:

```json
{
  "mcpServers": {
    "everything": {
      "type": "http",
      "url": "http://127.0.0.1:8765/mcp",
      "headers": { "Authorization": "Bearer ${MCP_RELAY_TOKEN}" }
    }
  }
}
```

To tie the relay to the lifetime of the client, start it from the script that
launches the client and pass that script's process id:

```bash
node bin/mcp-relay.mjs --port 8765 --watch-pid $$ -- <server command> &
```

## Documentation

- [Setup](docs/setup/README.md): installing, starting, stopping
- [Reference](docs/reference/README.md): every option, the HTTP surface, the library entry point
- [Troubleshooting](docs/troubleshooting/README.md): what each refusal means
- [Internals](docs/internals/README.md): design notes and the development flow

## Limits

- A notification the server sends on its own, outside the answer to a
  request, reaches the client only while the client holds its event stream
  open.
- The relay does not inspect tool calls. Restricting what the client may call
  is the job of the client's own permission settings.

## License

Apache-2.0 ([`LICENSE`](LICENSE)). Dependencies are listed in
[`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md); vulnerability reports go
through [`SECURITY.md`](SECURITY.md).