Tether
DocsGitHub

API reference

The MCP endpoint

POST /mcp serves your registered catalog over the Model Context Protocol. Point an agent at it instead of at your own tools, and every read is scoped and audited while every write stops and waits for a person.

Standard JSON-RPC. initialize, tools/list, tools/call, and notifications.

What tools/list returns

Your tenant's own agent-eligible capabilities, each with its schema — never another tenant's. The additional meta-capabilities depend on the credential used for the connection:

CredentialMeta-capabilities
Agent key (tag_)list_pending_actions
Tenant secret (tth_)register_capability, validate_catalog, list_pending_actions, confirm_action

Use the tenant secret only from a trusted onboarding or approval application. The runtime agent must use an agent key. That separation prevents an agent from changing is_write, risk, or the catalog entry that governs it, and prevents it from approving its own staged write.

What tools/call does

A read runs and returns its result.

A write does not run. It stages, and the tool result is the pending action:

{
  "preview": true,
  "action_id": "8f1c…",
  "command_type": "refund_order",
  "summary": "Refund 899.00 to the card ending 4471 — awaiting confirmation.",
  "expires_at": "2026-09-06T16:36:46Z",
  "confirmation_required": true
}

Your agent reports the pending action and stops. Confirmation belongs to a trusted application: use the Actions API, the approval inbox, or your own approval UI backed by the tenant secret. A trusted MCP client using that secret can call confirm_action; the runtime tag_ connection is neither offered that capability nor permitted to call it.

Proxying a server you already run

PUT /v1/upstreams connects an upstream MCP server. Tether lists its tools and stores them as an unmarked draft.

curl -X PUT $TETHER_URL/v1/upstreams \
  -H "X-Api-Key: $TETHER_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "kind": "mcp", "url": "https://tools.yourcompany.com/mcp", "token": "…" }'
FieldNotes
urlRequired. The upstream MCP server.
tokenSent to the upstream as Authorization: Bearer …. credential is the same field. Optional.
kindOptional. Only mcp is accepted here; for an OpenAPI document use POST /v1/tools/import.

Tether connects to the upstream with the MCP streamable HTTP transport, protocol version 2025-06-18 or whatever the server negotiates down to. For each list or call it initializes, sends notifications/initialized, makes the request, and ends the session, carrying Mcp-Session-Id and MCP-Protocol-Version when the server issues them. Servers that run stateless and servers that keep sessions both work, and a reply may be plain JSON or an event stream. A proxied read therefore costs your server three requests (initialize, initialized, the call), plus a session delete when it keeps sessions, so a server far from Tether adds about three round trips to each read. The catalog is stored, not fetched again per turn. The older HTTP+SSE transport from 2024-11-05, which needs a separate event endpoint, is not supported.

readOnlyHint and destructiveHint prefill suggested_is_write and suggested_risk. They never set is_write. Nothing is proxied until you declare it — a tool left unmarked is not served, which is the safe direction to fail in.

Mark a tool by registering it with PUT /v1/tools and "upstream": true, plus is_write and, for a write, risk. A tool that shares a name with one on your server but lacks "upstream": true is registered as your own and the response carries a warnings entry naming it.

Once marked, a proxied read is forwarded to the upstream. A proxied write stages exactly as a native one does and needs your approval, but once confirmed it runs at your tool endpoint, not on the upstream server, and staging it needs that endpoint to be set. Registration warns about each such tool.

  • Bring your AI — the door this belongs to
  • Tools — registering a catalog over HTTP
  • Actions — the same staged writes, over HTTP