Docs

Write your own client

There is no separate REST API, and you do not need one. You talk to TabTunnel with plain JSON POST requests (MCP, which is JSON-RPC 2.0), so curl is enough.

The shape of it

Everything goes to one URL with one header. There are four methods: initialize, tools/list, tools/call and ping. A DELETE ends your session.

Endpointhttps://tabtunnel.dev/v1/mcp
MethodPOST, always
AuthAuthorization: Bearer tt_live_…
Protocol version2025-06-18
SessionMcp-Session-Id, handed back by initialize
Body limit1 MiB

1. Initialize

Every session starts here. Read the session id off the response headers.

terminal
curl -sD- -X POST https://tabtunnel.dev/v1/mcp \
  -H "Authorization: Bearer $TABTUNNEL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-06-18",
      "clientInfo": { "name": "my-client", "version": "1.0.0" },
      "capabilities": {}
    }
  }'

The reply carries an mcp-session-id header and a result naming the server, its capabilities and an instructions string worth reading — it is what we tell a model about how to use the rest.

2. List the tools

This is the authoritative schema: names, descriptions and every argument. Read it from here rather than from the reference page, which is a summary and does not carry argument types.

terminal
curl -s -X POST https://tabtunnel.dev/v1/mcp \
  -H "Authorization: Bearer $TABTUNNEL_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Mcp-Session-Id: $SESSION" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

3. Call one

terminal
curl -s -X POST https://tabtunnel.dev/v1/mcp \
  -H "Authorization: Bearer $TABTUNNEL_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Mcp-Session-Id: $SESSION" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": { "name": "list_browsers", "arguments": {} }
  }'

Results come back as MCP content blocks: one text block of JSON for most tools, an image block for screenshot, and prose plus a metadata block for read_page.

4. Close it, when you are done

terminal
curl -s -X DELETE https://tabtunnel.dev/v1/mcp \
  -H "Authorization: Bearer $TABTUNNEL_TOKEN" \
  -H "Mcp-Session-Id: $SESSION"

204 whether it existed or not. Sessions also end on their own, but until then each one counts towards the number a token may have open at once. Ending a session also closes the tabs it opened, unless they were opened to stay.

Two failures, and they are not the same

  • A protocol fault — malformed envelope, unknown method, missing session — is a JSON-RPC error: -32700 parse, -32600 invalid request, -32601 no such method, -32602 bad params, -32603 internal.
  • A tool failure — browser shut, tab not yours, ref stale — is a successful response carrying isError: true, with a code, whether it is worth retrying, and what to do instead — so your agent can read it and recover.

Things worth knowing before you write a client

  • There is no event stream. GET answers 405, so do not open an SSE connection and wait on it; every answer comes back on the POST that asked.
  • A 404 means start again. Your session has ended. Call initialize again.
  • Give it a generous timeout. A command to a browser that has not been used for a while waits a few seconds while it reconnects, and one the person at the browser is being asked about waits for their answer. Many clients default to 60 s; that is the number to check first when a call fails and the browser then does the thing anyway.
  • It cannot be called from a web page. Call it from your own program or server; a browser will block the request.
  • Repeated bad tokens are slowed down. Too many rejected attempts from one address are blocked for a while; calls that work never count.

Is something here wrong, or missing? Tell us.