Using rustunnel from an AI agent / LLM harness

June 6, 2026 · View on GitHub

rustunnel ships an MCP server (rustunnel-mcp) that exposes tunnel management as tools any Model Context Protocol client can call. Once it's wired into your harness, you can just say:

"Create an HTTP tunnel to my service on port 3000." "Expose port 5432 over TCP so I can reach my database." "Spin up a load-balanced pool across ports 3000 and 3001 with a health check."

This guide is the one-stop reference for adding rustunnel to Claude Code, Claude Desktop, Codex, Cursor, Windsurf, Cline, or any custom/MCP agent.


1. Prerequisites

You need two binaries on your PATH:

  • rustunnel — the client (the MCP server spawns it to open tunnels)
  • rustunnel-mcp — the MCP server itself
# Homebrew (macOS / Linux)
brew tap joaoh82/rustunnel && brew install rustunnel

# Or build from source
git clone https://github.com/joaoh82/rustunnel.git && cd rustunnel
make release          # builds rustunnel, rustunnel-server, rustunnel-mcp
sudo install -m755 target/release/rustunnel     /usr/local/bin/rustunnel
sudo install -m755 target/release/rustunnel-mcp /usr/local/bin/rustunnel-mcp

2. Get an API token (one-time)

rustunnel requires an API token. You only need to do this once.

  • Hosted (rustunnel.com): sign up free at https://rustunnel.comDashboard → API Keys → create a key. No waiting list.
  • Self-hosted: rustunnel token create --name agent --server <host>:4040 --admin_token <admin>, or create one from your dashboard.

Set it as RUSTUNNEL_TOKEN in the MCP config below. When that variable is set, the agent never has to pass the token on individual calls.

3. The two server settings

SettingHosted exampleSelf-hosted exampleLocal dev
--server (control plane)eu.edge.rustunnel.com:4040tunnel.example.com:4040localhost:4040
--api (dashboard REST API)https://eu.edge.rustunnel.com:8443https://tunnel.example.com:8443http://localhost:4041

Add --insecure only for local dev with self-signed certs.


4. Quick install (any harness)

The installer prompts for your token and writes the right config for the harness you pick:

curl -fsSL https://raw.githubusercontent.com/joaoh82/rustunnel/main/integrations/install.sh | bash
# or, from a clone:
./integrations/install.sh

It supports claude-code, claude-desktop, codex, cursor, windsurf, cline, and generic (prints a snippet). Run ./integrations/install.sh --help for non-interactive flags.


5. Per-harness configuration

Ready-to-edit templates live in integrations/.

Claude Code

Plugin (recommended — zero config):

/plugin install rustunnel
/plugin configure rustunnel     # prompts for server, API URL, token

See claude-plugin.md.

Manual .mcp.json in your project root — see integrations/claude-code/.mcp.json:

{
  "mcpServers": {
    "rustunnel": {
      "command": "rustunnel-mcp",
      "args": ["--server", "eu.edge.rustunnel.com:4040", "--api", "https://eu.edge.rustunnel.com:8443"],
      "env": { "RUSTUNNEL_TOKEN": "<your-token>" }
    }
  }
}

Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows) — template: integrations/claude-desktop/config.json. Same mcpServers shape as above.

Codex (OpenAI)

Codex reads MCP servers from ~/.codex/config.toml. Template: integrations/codex/config.toml.

[mcp_servers.rustunnel]
command = "rustunnel-mcp"
args = ["--server", "eu.edge.rustunnel.com:4040", "--api", "https://eu.edge.rustunnel.com:8443"]
env = { RUSTUNNEL_TOKEN = "<your-token>" }

Codex also reads an AGENTS.md at the repo root for guidance.

Cursor

Project: .cursor/mcp.json. Global: ~/.cursor/mcp.json. Template: integrations/cursor/mcp.json. Same mcpServers shape.

Windsurf

~/.codeium/windsurf/mcp_config.json. Template: integrations/windsurf/mcp_config.json. Same shape.

Cline (VS Code)

cline_mcp_settings.json (via the Cline MCP settings UI). Template: integrations/cline/cline_mcp_settings.json. Same shape.

Generic / custom agent

Any MCP client uses the same command + args + env. Template: integrations/generic/mcp.json.

For a programmatic agent, spawn rustunnel-mcp and speak newline-delimited JSON-RPC 2.0 over stdin/stdout:

import subprocess, json, os

proc = subprocess.Popen(
    ["rustunnel-mcp", "--server", "eu.edge.rustunnel.com:4040",
     "--api", "https://eu.edge.rustunnel.com:8443"],
    stdin=subprocess.PIPE, stdout=subprocess.PIPE,
    env={**os.environ, "RUSTUNNEL_TOKEN": "<your-token>"},
)

def call(method, params=None, _id=[0]):
    _id[0] += 1
    msg = {"jsonrpc": "2.0", "id": _id[0], "method": method}
    if params: msg["params"] = params
    proc.stdin.write(json.dumps(msg).encode() + b"\n"); proc.stdin.flush()
    return json.loads(proc.stdout.readline())

call("initialize", {"protocolVersion": "2024-11-05"})
print(call("tools/call", {"name": "create_tunnel",
      "arguments": {"local_port": 3000, "protocol": "http"}}))

6. Available tools

Every authenticated tool accepts an optional token argument; omit it when RUSTUNNEL_TOKEN is set.

ToolPurpose
create_tunnelOpen a tunnel and get a public URL. HTTP/TCP/UDP, P2P, and load-balanced pools
close_tunnelClose a tunnel by ID
list_tunnelsList active tunnels
get_tunnel_historyPast tunnel activity (audit)
list_regionsAvailable server regions (no auth)
get_connection_infoCLI command / config for manual runs (cloud sandboxes)

create_tunnel arguments

ArgumentWhenDescription
local_portalwaysLocal port the service listens on
protocolalwayshttp, tcp, udp, or p2p
tokenoptionalFalls back to RUSTUNNEL_TOKEN
subdomainhttpCustom subdomain
regionoptionaleu / us / ap; omit to auto-select
local_hostoptionalForward to another host (default localhost)
secretp2pShared secret (publisher and subscriber match)
peer_namep2p publishPublish under this name
peer_targetp2p connectConnect to this published name
group + group_keyload balancingJoin a pool (http/tcp); members share the key
health_checkoptional{ type: tcp|http, path, interval_secs, timeout_secs, max_failed, expect_2xx, alert_webhook }

See mcp-server.md for the full tool reference, load-balancing.md for pools/health checks, and p2p-tunnels.md for peer-to-peer details.


7. Security notes

  • Tokens travel to the server over HTTPS. Use --insecure only in local dev.
  • The RUSTUNNEL_TOKEN env var keeps the token out of tool-call payloads and chat history — prefer it over passing token inline.
  • Child rustunnel processes spawned by create_tunnel are killed when the MCP server exits; temp config files for load-balanced tunnels are cleaned up too.
  • Protect any config file you save: chmod 600 ~/.rustunnel/config.yml.