Teitunnel

Guides

AI agents (MCP)

Let Claude Code, Cursor, VS Code, Codex, Windsurf, Zed, Claude Desktop, Gemini CLI, Copilot CLI, opencode, Kiro, LM Studio or Junie share your dev server, manage Cloudflare Tunnel routes, debug webhooks and fix problems through Teitunnel's MCP server, with your approval for every change.

Teitunnel has a built-in MCP server. Your AI tool brings the model; Teitunnel gives it the same abilities you have in the app: put a local service online, add routes on your domains, find out why a route is down, read connector logs, wait for a webhook and replay it. Every change goes through the same reviewed plans as the app, waits for your approval unless you say otherwise, and shows up in Activity with the tool's name. Secrets never reach the agent.

Use it when you already work with an agent in your editor or terminal and want it to handle "give me a link to this", "why is staging down" or "debug this webhook" end to end.

AI & Integrations, AI Apps: Claude Code connected and last used 12 minutes ago, Cursor asking to be updated, Connect for VS Code, and the command for other MCP clients

Connect your AI tool

In the app: open AI & Integrations ▸ AI Apps. It lists the AI apps installed on this computer, found by their app or program (a settings folder left behind after uninstalling doesn't count), and says where each one stands:

It saysMeaningWhat to do
Connected · last used 12 min agoTeitunnel is in its settings, and an agent from it used Teitunnel then.Nothing.
Connected · not used yetTeitunnel is in its settings, but no session has started it while the app was open.Restart the app, ask it something, or choose Test Connection.
Connected to a Teitunnel that moved or changedIts entry starts a teitunnel that isn't there any more (Teitunnel was moved or reinstalled) or with other options.Update.
Not connectedInstalled, without Teitunnel.Connect, then restart the app.
Teitunnel is still in its settings, but the app isn't installed any moreLeft over from an app you removed.Remove.
Its settings file can't be readThe file isn't valid JSON or TOML; Teitunnel won't touch it.Fix the file, or add the entry by hand.

Test Connection starts the MCP server exactly as that app's settings say, does the MCP handshake and lists its tools, then stops it: Works: teitunnel 0.4.1, 41 tools, answered in 180 ms, or why not (the program is missing, it stopped with an error, it didn't answer). Details shows the settings file (with Show in Finder), the command it starts and where the app was found. Apps that aren't installed are under Other Supported Apps, each with the entry to paste by hand, and any other MCP client can run the command shown.

Nothing needs a sign-in or a key: the AI app starts teitunnel mcp on this computer, which talks to the Teitunnel app there. Last used comes from the app itself: it records each agent session while it's open (never the conversation).

From the terminal:

teitunnel mcp install claude-code     # or: claude-desktop, cursor, vscode, codex, windsurf,
                                      #     zed, gemini-cli, copilot-cli, opencode, kiro,
                                      #     lm-studio, junie

That adds a teitunnel entry to the tool's MCP configuration and leaves everything else in the file as it was, comments included. The previous file is kept next to it as <file>.teitunnel-backup. Restart the tool, or reload its MCP servers, and ask it something like "Share my dev server".

teitunnel mcp status                  # which tools are installed and connected (--json)
teitunnel mcp config cursor           # print the entry to add by hand
teitunnel mcp uninstall cursor        # remove it again (only Teitunnel's entry)
teitunnel mcp install cursor --mode read-only
ToolFile Teitunnel edits
Claude Code~/.claude.json (user scope, mcpServers), or under CLAUDE_CONFIG_DIR
Claude Desktop~/Library/Application Support/Claude/claude_desktop_config.json · Windows: %APPDATA%\Claude\claude_desktop_config.json (from the Microsoft Store: the same file under %LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming) · Linux: ~/.config/Claude/claude_desktop_config.json
Cursor~/.cursor/mcp.json (the app and cursor-agent)
VS Code (Copilot)the user mcp.json next to settings.json (servers): ~/Library/Application Support/Code/User/mcp.json, %APPDATA%\Code\User\mcp.json, ~/.config/Code/User/mcp.json
Codex~/.codex/config.toml (or under CODEX_HOME), [mcp_servers.teitunnel]
Windsurf~/.codeium/windsurf/mcp_config.json
Zed~/.config/zed/settings.json (context_servers) · Windows: %APPDATA%\Zed\settings.json
Gemini CLI~/.gemini/settings.json
GitHub Copilot CLI~/.copilot/mcp-config.json (or under COPILOT_HOME), a local server with every tool
opencode~/.config/opencode/opencode.json (or opencode.jsonc), mcp
Kiro (IDE and kiro-cli)~/.kiro/settings/mcp.json
LM Studio~/.lmstudio/mcp.json
Junie~/.junie/mcp/mcp.json

The entry runs this teitunnel executable (its real path) with mcp and, if you chose one, --mode. Any other MCP client works too: run teitunnel mcp as a stdio server.

What it can do

ToolDoes
share_portPuts a local service online: a random trycloudflare.com link, or a hostname on your domain, optionally behind a login. Ends when stopped, when it expires, or when the session ends.
share_folderPuts a folder of files online (a random link or a hostname on your domain), without hidden files, .env files, keys, .git or node_modules.
stop_share, list_sharesEvery share, whoever started it (the app, a terminal, an agent).
pause_share, resume_share, schedule_sharePause a share on your domain (the address stays, visitors see a paused page), serve it again, or run it only during set hours (Sharing).
list_local_servicesListening ports with what they are (Vite, Next.js, Django, Docker…) and their project.
list_routes, list_domains, list_tunnelsRoutes with their live status, domains, tunnels and the machines running them.
plan_changePlans any change: add, edit or remove a route, require a login, load balance, private networks, create or delete a tunnel, import routes. Nothing changes.
apply_planApplies a reviewed plan by its id and fingerprint, with progress, then checks the routes.
verify_routeChecks a hostname end to end and says where it breaks.
undo_lastPlans the reverse of the latest change.
get_protection, protect_hostnameA hostname's rules at Cloudflare's edge (bots, AI crawlers, rate limit, headers) and quotas; plans a change, applied with apply_plan (Edge protection).
service_token_list, service_token_create, service_token_revokeService tokens that let machines through a login. A new token's secret is returned once, after your approval, marked sensitive.
get_offline_page_and_inboxes, set_offline_page, set_webhook_inboxA hostname's offline page and webhook inboxes: what it has, and setting or removing either after your approval of the plan. A verifying inbox uses the signing secret already saved in the inspector.
list_reservations, reserve_hostname, release_hostnameHostnames reserved on the account and who holds them; reserve one (optionally until a date) or give it up (Teams).
comments_list, comments_reply, comments_resolveReviewers' comments on shares and Snapshots (Comments); reviewers' email addresses are never included.
doctor, fix_issueThe Doctor's issues and their fixes (Doctor checks).
logs_tail, remote_logs, connector_statusThis machine's connector logs (per route), another machine's live logs, connector health.
list_local_domains, add_local_domain, remove_local_domainLocal HTTPS domains such as https://shop.test for a dev server, on this computer only. Served by the app while it runs, otherwise by the MCP server until its session ends; trusting the certificate authority is left to you (it asks for your password).
route_trafficWho uses a route or share and how: requests over time and per second, answers, the 5xx share, response times, top paths, countries, browsers and bots by kind, from the inspector when it's in front of it and otherwise from Cloudflare's analytics (Analytics).
route_healthWhether each route is up, its uptime over a day, week and month, response times, the outage going on and recent incidents, from the checks the app runs every minute (Analytics).
export_config, import_scanconfig.yml, Docker Compose or Terraform; existing cloudflared setups.
accounts, recent_activityConnected accounts and what they can do (never their credentials); recent changes and who made them.
traffic_list, traffic_get, traffic_replay, wait_for_request, traffic_stats, traffic_exportRequests the inspector captured on the server's shares and its recent history: list, inspect, replay, wait for the next one (for webhooks; progress is reported while waiting), numbers, cURL/HAR/Markdown.
traffic_openapiAn OpenAPI 3.1 description of the API the captured requests show (OpenAPI from traffic).
expose_mcp_serverPuts an MCP server running on this machine online at a hostname on your domain for remote AI clients: checks it answers MCP, keeps streams alive, requires a bearer token or, for claude.ai and ChatGPT, an OAuth sign-in you approve in Teitunnel, and returns configurations for Claude Code, Cursor and VS Code. The agent never sees the token (you get it with teitunnel token <hostname>).
inspection_settings, configure_inspectionWhat the inspector does for the server's shares, and changing it to test how an app copes: mock responses (always, or only while the service is down), a share of requests failing (a status, a dropped connection, a delay, a timeout), a slow network (3G, 4G, satellite), header rules and CORS, watched paths, idle stop. On this computer only; your approval first in ask mode.

It also offers resources your tool can attach as context (teitunnel://routes, teitunnel://shares, teitunnel://domains, teitunnel://issues, teitunnel://activity, teitunnel://route/{hostname}, teitunnel://logs/{tunnel}) and prompts: Put my dev server online, Debug a failing webhook, Why is my route down?, Move my routes to a server and Test how my app copes.

Modes

The server runs in one of three modes:

ModeIn the appWhat the agent can do
ask (default)Asks firstEverything, but every change waits for your yes.
read-onlyRead onlyLook only. Tools that change something aren't offered at all.
fullFull accessChanges apply without asking, still only through plans. Records Teitunnel didn't create are never replaced or deleted without an explicit confirmation.

Teitunnel reads the mode from mcp.json in its data folder ({ "mode": "read-only" }, for every tool), then the environment variable TEITUNNEL_MCP_MODE, then the --mode flag; a later one wins. teitunnel mcp install <tool> --mode read-only writes the flag into that tool's entry, so it sets the mode per tool.

mcp.json holds the server's other settings too; each takes effect the next time an AI tool starts Teitunnel's MCP server:

SettingDefaultWhat it does
mode"ask"read-only, ask or full, as above.
approveInApptrueIn ask mode, a change needs your answer in Teitunnel or in your AI tool; the agent saying you agreed isn't enough. See Approvals.
allowSecretsfalseShow agents credentials in captured requests and logs.
oauth.dynamicRegistrationtrueMCP servers you share with OAuth accept apps that register themselves.
oauth.maxGrantDays90How many days a connection to a shared MCP server lasts before you approve it again (1 to 365).

Approvals in the app

In ask mode, a change is approved by you, in this order of preference:

  1. The Teitunnel app, when it's running. The agent's teitunnel mcp asks the app over its local control connection, and the app shows a native dialog: "Allow Claude Code to make this change?" with the plan's steps. There's no Always Allow for agents. An agent's own "confirmed" never counts while you can be asked, and no answer within about three minutes counts as no. The app shows one question at a time: while one waits, the agent is told to try again after you answer it, not that you said no.
  2. Your AI tool, if it can show a question (MCP elicitation; on protocol 2026-07-28 the tool call comes back asking for your answer, and the tool calls again with it).
  3. Nobody can ask you (the app isn't running and the tool can't show a question): the change doesn't happen, and the agent is told to have you open Teitunnel and try again. Agents read web pages, issues and captured requests, and text there can try to talk them into things, so an agent saying you agreed isn't enough.

If you'd rather approve in the conversation when nobody can ask you, set "approveInApp": false in mcp.json (or TEITUNNEL_MCP_APPROVE_IN_APP=0). The agent then gets needsApproval, has to show you the plan, and can go ahead by calling again after you agree.

A person's "no" always wins. Settings ▸ General ▸ Connected Agents lists the agents using Teitunnel right now, with their mode ("Asks first", "Read only", "Full access") and any change waiting for your answer. The app doesn't host an MCP endpoint itself, so nothing new listens on a network port.

Secrets never reach the agent

The agent never sees API tokens, OAuth tokens, tunnel tokens, anything in the keychain, or reviewers' email addresses. Credentials in captured requests (Authorization, Cookie, Set-Cookie, webhook signatures and other secret headers) are masked, and tokens in logs are redacted. Bearer tokens for shared AI and MCP servers appear as <TOKEN>. Only teitunnel mcp --allow-secrets (or TEITUNNEL_MCP_ALLOW_SECRETS=1) shows captured credentials, and only to that server. The one exception is a service token an agent creates: its secret is returned once, after you approved the change, marked sensitive.

What anyone could have written (captured requests, review comments, logs, pages checked by verify_route) comes back marked untrusted: true and fenced, and the agent is told to read it as data, never as instructions.

Every Cloudflare change an agent makes is in Activity, marked with its name, and undo_last (or you, in the app) can reverse it. Calls are rate limited (240 reads, 30 changes and 12 destructive changes a minute per server), answers are bounded and paged, and long waits can be cancelled.

Examples

Share a dev server. "Put my Vite app online for my phone." The agent finds the port with list_local_services, calls share_port, you approve, and it gives you the link.

On your domain, with a login. "Share port 8080 at demo.yourhost.com, only for @yourhost.com." A temporary route with a Cloudflare Access login, removed when the session ends. For a permanent route the agent plans an addRoute change instead.

Debug a webhook. "Stripe webhooks to my app fail." The agent shares the port, asks you to send a test event, waits for it with wait_for_request, reads the request and your app's answer, fixes the handler, and replays the request until it answers 200.

Why is my route down? The agent runs verify_route (DNS, edge, tunnel, service), doctor, and the route's logs, then fixes it with fix_issue or a plan.

Act on review comments. "Address the comments on the preview." comments_list, then code changes, then comments_reply and comments_resolve, each approved by you.

Move to a server. export_config as Docker Compose, with instructions for the token.

A server over HTTP

teitunnel serve also serves MCP at /mcp (Streamable HTTP) for agents elsewhere. It uses the server's API keys:

teitunnel api-key create my-agent
teitunnel serve --mcp-mode ask        # read-only, ask (default) or full; --no-mcp turns it off

Configure the client with the URL http://127.0.0.1:8765/mcp (or your HTTPS address in front of it) and the header Authorization: Bearer ttk_…. Requests from browsers (with an Origin header) are refused unless you allow that origin with --mcp-allow-origin, and changes are recorded with the key's name. Over HTTP, approvals in ask mode go through your tool's questions; a tool that can't ask can make changes only in full mode, or with "approveInApp": false in the server's mcp.json (then through the conversation). Tools on protocol 2026-07-28 don't keep a session open, so shares an agent starts over HTTP last 60 minutes unless it asks for another time. See the Server API.

Agent Skill

Tools that support Agent Skills can load Teitunnel's: /skills/teitunnel/SKILL.md. It tells the agent when to reach for Teitunnel and the rules for working with it: show a plan before applying it, never pass confirmed: true on its own, never ask for tokens, and use a route rather than a share for anything that should stay online.

Tell your project's agent

Add this to your repository's AGENTS.md (or CLAUDE.md) so agents working on it use Teitunnel for anything that needs a public URL:

## Sharing and tunnels
This project uses Teitunnel (MCP server `teitunnel`) for public URLs.
- To show the dev server or receive webhooks: `share_port` (port 3000); for webhooks,
  `wait_for_request` then `traffic_get`/`traffic_replay`.
- Routes on our domain change only through `plan_change` → show me the plan → `apply_plan`.
- Never ask for or paste Cloudflare tokens.

Troubleshooting

Edit on GitHub

Last updated on

On this page