tunnel
Manage tunnel connections for exposing local services publicly. Perfect for mobile device testing and sharing development builds.
Synopsis
tunnel {action: "<action>", ...params}
Actions
| Action | Description |
|---|---|
start | Start a tunnel to expose a local port |
stop | Stop a running tunnel |
status | Get tunnel status and public URL |
list | List all active tunnels |
Supported Providers
| Provider | Binary | Native Support | Description |
|---|---|---|---|
cloudflare | cloudflared | Yes | Free quick tunnels via trycloudflare.com |
ngrok | ngrok | Yes | Popular tunneling service with stable URLs |
| Tailscale | tailscale | Manual | Persistent URLs for Tailscale users |
Choosing a Provider
| Use Case | Recommended Provider |
|---|---|
| Quick testing, no signup | Cloudflare |
| Stable URLs for webhooks | ngrok (paid) |
| Team already on Tailscale | Tailscale Funnel |
| Maximum privacy | Tailscale Funnel |
start
Start a tunnel to expose a local port publicly.
tunnel {
action: "start",
id: "app",
provider: "cloudflare",
local_port: 8080
}
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | Yes | - | Unique tunnel identifier |
provider | string | Yes | - | Tunnel provider: cloudflare or ngrok |
local_port | integer | Yes | - | Local port to tunnel |
local_host | string | No | localhost | Local host to tunnel |
binary_path | string | No | (from PATH) | Path to tunnel binary |
proxy_id | string | No | - | 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
| State | Description |
|---|---|
idle | Not started |
starting | Starting up, waiting for URL |
connected | Running with public URL available |
failed | Failed to start or crashed |
stopped | Stopped 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:
- Start your proxy and tunnel with agnt
- Use BrowserStack MCP to run tests on the tunneled URL
- 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
- proxy - Reverse proxy with tunnel support
- Mobile Testing Guide - Complete workflow