Skip to content

MCP server - HTTP transport

With the default stdio setup, your AI client launches the binary for you whenever it starts - you never run it yourself. With --http, you run the binary yourself as a long-lived server and leave it running, and clients connect to its local HTTP port. It's protected by loopback-only binding, Host/Origin allowlists, and a required bearer token (the Threat model below explains why that combination is safe).

Setup

Use the binary you installed in the MCP server - quick start — substitute its path for ./resilio-mcp-server in the commands below. On Windows that's the full path from your install section, e.g. "C:\Users\<YOUR-USERNAME>\AppData\Local\Programs\Resilio MCP Server\resilio-mcp-server.exe".

  1. Generate a token:

    ./resilio-mcp-server --generate-token
    

    This prints the token once to the terminal and writes only its SHA-256 hash to RESILIO_HTTP_TOKEN_HASH in your .env (the plaintext is never stored). Copy the token somewhere safe for step 3.

  2. Start the server in HTTP mode, and leave it running:

    ./resilio-mcp-server --http
    

    The server listens on http://localhost:3001 — loopback only (use --port <n> to change the port). This process must stay alive; your client connects to it over HTTP.

  3. Point your AI client at it, with the token in an Authorization: Bearer header:

    • Claude Code (native HTTP support):

      claude mcp add --transport http resilio-http http://localhost:3001/ \
        --header "Authorization: Bearer <token>"
      

      Verify with claude mcp list (should show ✓ Connected).

    • Claude Desktop and other stdio-only clients have no native HTTP transport — they can't hit the port on their own. You can still connect them by bridging to your running --http server with mcp-remote (this is what makes Claude Desktop work with --http). Simpler alternative if you don't specifically need HTTP: just use the stdio setup. To bridge, in claude_desktop_config.json:

      {
        "mcpServers": {
          "resilio-http": {
            "command": "/absolute/path/to/npx",
            "args": ["-y", "mcp-remote@latest", "http://localhost:3001/",
                    "--header", "Authorization: Bearer <token>", "--transport", "http-only"],
            "env": { "PATH": "/absolute/path/to/node/bin:/usr/local/bin:/usr/bin:/bin" }
          }
        }
      }
      
      Desktop launches MCP servers with a minimal PATH, so use absolute paths. Quit and reopen Desktop after editing, and keep the --http server from step 2 running — the bridge connects to it on demand.

Token housekeeping:

  • Rotate tokens by re-running --generate-token — it rewrites only the RESILIO_HTTP_TOKEN_HASH line (every other key preserved), the old token stops working immediately, then update your client configuration with the new one.
  • Storage is hash-only — The 256-bit random token can't be recovered from its stored hash, so a leaked .env exposes nothing usable.
  • Don't confuse it with RESILIO_API_TOKEN / RESILIO_AUTH_TYPE - The HTTP bearer token is how clients authenticate to this server; RESILIO_API_TOKEN is how this server authenticates to the Management Console — opposite directions. An incorrect RESILIO_AUTH_TYPE makes tool calls fail against the Management Console even though the HTTP token is correct.

Threat model

The HTTP transport is designed to be safe to run on your workstation against the following threats:

  • Off-machine attackers (anyone on your LAN or the internet) cannot reach the server. Kestrel binds to the loopback interface only.
  • Malicious websites you visit in a browser, including DNS-rebinding attacks where an attacker resolves evil.com to 127.0.0.1, cannot make working requests against the server. Cross-origin requests are blocked by an Origin allowlist, and rebinding-style requests are blocked by a Host allowlist.

The HTTP transport is not designed to isolate the MCP Server from other processes running on the same machine as the same user. Any local process running as your user account can connect to the loopback port and call tools. This is treated as an acceptable risk — those processes already have full access to your files, network, and existing MCP .env. If you don't trust local code running as your user, neither stdio nor --http mode will help.

How the protection works

When you run ./resilio-mcp-server --http (or dotnet run -- --http in development), four layers apply to every incoming request, in the following order:

  1. Loopback-only binding - Kestrel listens on 127.0.0.1 / [::1] only. There is no listener on any external interface.
  2. Host header check - The Host header must be localhost, 127.0.0.1, or [::1] (any port). A browser fetching http://evil.com:3001/... — even after DNS rebinding to a loopback address — still sends Host: evil.com and is rejected with 403 Forbidden.
  3. Origin header check - Cross-origin requests are rejected unless their Origin is in the allowlist (see below). Browsers stamp the page's real origin into this header; page JavaScript cannot forge it.
  4. Bearer-token check - Every request must carry Authorization: Bearer <token> matching the configured token, or it is rejected with 401 Unauthorized (no body). This runs last, after the Host/Origin checks, on purpose: a rebinding or cross-origin probe is dropped with a 403 before the token is ever consulted, so a failed probe never learns whether a token would have worked.

The token check is per request, not per connection — it runs on the very first message (initialize) and on every tool call after it. A wrong or missing token fails initialize, so the client can't even connect; there is no "authenticate once, then trust the session."

Requests with no Origin header — which is how native MCP clients connect — pass the Origin check, since they aren't browser requests. The Host and bearer-token checks still apply to them.

Origin allowlist (RESILIO_HTTP_ALLOWED_ORIGINS)

By default (with RESILIO_HTTP_ALLOWED_ORIGINS unset or empty), any loopback origin is allowed (http://localhost:<any-port>, http://127.0.0.1:<any-port>, etc.).

If you want a different origin (for example a browser-based MCP client running at http://localhost:5172), set the variable to a comma-separated list of exact origins:

RESILIO_HTTP_ALLOWED_ORIGINS=http://localhost:5172,http://127.0.0.1:5172

Any request with an Origin header not in the list is rejected with 403 Forbidden. The comparison is case-insensitive; entries must be full origins (scheme + host + port), with no trailing slash. The literal opaque origin null (sent by file:// pages and sandboxed iframes) is never accepted.

Session idle timeout (RESILIO_HTTP_IDLE_TIMEOUT)

The Streamable HTTP transport tracks one session per client and closes it after an idle period. The default is 24 hours (1440 minutes) — deliberately long so a bridged client (e.g. mcp-remote) doesn't hit Session not found between tool calls. Set RESILIO_HTTP_IDLE_TIMEOUT to a positive number of minutes to override it; empty, non-numeric, or non-positive values fall back to the default.