Skip to main content

tunnel

Manage tunnel connections for exposing local services publicly. Perfect for mobile device testing and sharing development builds.

Synopsis​

tunnel {action: "<action>", ...params}

Actions​

ActionDescription
startStart a tunnel to expose a local port
stopStop a running tunnel
statusGet tunnel status and public URL
listList all active tunnels

Supported Providers​

ProviderBinaryNative SupportDescription
cloudflarecloudflaredYesFree quick tunnels via trycloudflare.com
ngrokngrokYesPopular tunneling service with stable URLs
TailscaletailscaleManualPersistent URLs for Tailscale users

Choosing a Provider​

Use CaseRecommended Provider
Quick testing, no signupCloudflare
Stable URLs for webhooksngrok (paid)
Team already on TailscaleTailscale Funnel
Maximum privacyTailscale Funnel

start​

Start a tunnel to expose a local port publicly.

tunnel {
action: "start",
id: "app",
provider: "cloudflare",
local_port: 8080
}

Parameters:

ParameterTypeRequiredDefaultDescription
idstringYes-Unique tunnel identifier
providerstringYes-Tunnel provider: cloudflare, ngrok, or tailscale
local_portintegerYes-Local port to tunnel
local_hoststringNolocalhostLocal host to tunnel
binary_pathstringNo(from PATH)Path to tunnel binary
proxy_idstringNo-Proxy ID to auto-configure with public URL

Response:

{
"id": "app",
"provider": "cloudflare",
"state": "connected",
"public_url": "https://random-words-here.trycloudflare.com",
"local_addr": "localhost:8080"
}

Auto-Configure Proxy​

When proxy_id is specified, the tunnel automatically updates the proxy's public_url once the tunnel URL is discovered:

// Start proxy first
proxy {action: "start", id: "app", target_url: "http://localhost:3000", bind_address: "0.0.0.0"}
// Response: {listen_addr: "0.0.0.0:45849"}

// Start tunnel with proxy auto-configuration
tunnel {
action: "start",
id: "app",
provider: "cloudflare",
local_port: 45849,
proxy_id: "app"
}

The proxy will now correctly rewrite URLs to use the tunnel's HTTPS scheme.

stop​

Stop a running tunnel.

tunnel {action: "stop", id: "app"}

Response:

{
"success": true,
"id": "app",
"message": "Tunnel stopped"
}

status​

Get tunnel status and public URL.

tunnel {action: "status", id: "app"}

Response:

{
"id": "app",
"provider": "cloudflare",
"state": "connected",
"public_url": "https://random-words-here.trycloudflare.com",
"local_addr": "localhost:8080"
}

Tunnel States​

StateDescription
idleNot started
startingStarting up, waiting for URL
connectedRunning with public URL available
failedFailed to start or crashed
stoppedStopped by user

list​

List all active tunnels.

tunnel {action: "list"}

Response:

{
"count": 2,
"tunnels": [
{
"id": "frontend",
"provider": "cloudflare",
"state": "connected",
"public_url": "https://abc.trycloudflare.com",
"local_addr": "localhost:8080"
},
{
"id": "api",
"provider": "ngrok",
"state": "connected",
"public_url": "https://xyz.ngrok-free.app",
"local_addr": "localhost:4000"
}
]
}

Installation Requirements​

Cloudflare (cloudflared)​

# macOS
brew install cloudflare/cloudflare/cloudflared

# Linux
curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared.deb

# Windows
winget install --id Cloudflare.cloudflared

ngrok​

# macOS
brew install ngrok/ngrok/ngrok

# Linux/Windows
# Download from https://ngrok.com/download

# Configure auth token (required)
ngrok config add-authtoken <your-token>

Tailscale Funnel (Manual Setup)​

Tailscale Funnel provides persistent, memorable URLs for teams already using Tailscale. While not natively integrated, it works well with agnt's proxy.

# Install Tailscale (if not already installed)
# macOS
brew install tailscale

# Linux
curl -fsSL https://tailscale.com/install.sh | sh

# Windows
winget install --id Tailscale.Tailscale

Setup workflow:

# 1. Start agnt proxy on all interfaces
proxy {action: "start", id: "app", target_url: "http://localhost:3000", bind_address: "0.0.0.0"}
# Note the port from listen_addr (e.g., 45849)

# 2. In a separate terminal, start Tailscale Funnel
tailscale funnel 45849
# Output: https://your-machine.tailnet-name.ts.net

# 3. Configure proxy with the public URL (for proper URL rewriting)
proxy {action: "start", id: "app", target_url: "http://localhost:3000", bind_address: "0.0.0.0", public_url: "https://your-machine.tailnet-name.ts.net"}

Requirements:

  • Tailscale installed and authenticated (tailscale up)
  • Funnel enabled on your tailnet (requires tailnet admin to enable)
  • HTTPS certificates are automatically managed by Tailscale

Advantages over other providers:

  • Persistent URL (based on your machine name)
  • No third-party accounts if you already use Tailscale
  • End-to-end encrypted
  • Works with Tailscale ACLs for access control

Real-World Patterns​

Mobile Device Testing​

// 1. Start your dev server
run {script_name: "dev"}

// 2. Wait for it to be ready
proc {action: "output", process_id: "dev", grep: "ready"}

// 3. Start proxy on all interfaces
proxy {
action: "start",
id: "app",
target_url: "http://localhost:3000",
bind_address: "0.0.0.0"
}
// Note the listen_addr port from the response

// 4. Start tunnel with auto-configuration
tunnel {
action: "start",
id: "app",
provider: "cloudflare",
local_port: 45849,
proxy_id: "app"
}
// Share the public_url with your mobile device

Multiple Environments​

// Frontend tunnel
tunnel {action: "start", id: "frontend", provider: "cloudflare", local_port: 3000}

// API tunnel
tunnel {action: "start", id: "api", provider: "cloudflare", local_port: 4000}

// List all
tunnel {action: "list"}

BrowserStack Integration​

Use agnt tunnels with BrowserStack's MCP server for automated mobile testing:

// claude_desktop_config.json
{
"mcpServers": {
"agnt": {
"command": "agnt",
"args": ["mcp"]
},
"browserstack": {
"command": "npx",
"args": ["@anthropic-ai/browserstack-mcp"],
"env": {
"BROWSERSTACK_USERNAME": "your_username",
"BROWSERSTACK_ACCESS_KEY": "your_key"
}
}
}
}

Then use both tools together:

  1. Start your proxy and tunnel with agnt
  2. Use BrowserStack MCP to run tests on the tunneled URL
  3. Capture errors and screenshots through the instrumented proxy

Error Responses​

Tunnel Not Found​

{
"error": "tunnel not found",
"id": "nonexistent"
}

Binary Not Found​

{
"error": "cloudflared not found in PATH"
}

Tunnel Already Exists​

{
"error": "tunnel already exists",
"id": "app"
}

See Also​