> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thunderphone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Servers

> Attach remote MCP tool servers to your agents, and use ThunderPhone itself as an MCP server.

Two directions of MCP (Model Context Protocol) integration:

1. **Remote MCP servers** (`/v1/mcp-servers`) — register an external
   MCP server; its tools are synced, cached, and become callable by
   any [agent](/api-reference/agents) you attach the server to via
   `mcp_server_ids`.
2. **ThunderPhone as an MCP server** (`POST /v1/mcp`) — a single
   endpoint that speaks MCP (JSON-RPC over streamable HTTP), exposing
   your org's agents and calls as tools to any MCP client (Claude,
   IDEs, agent frameworks). Authenticate with your `sk_live_` key.

## Endpoints

| Method   | Path                                     | Description                                      |
| -------- | ---------------------------------------- | ------------------------------------------------ |
| `GET`    | `/v1/mcp-servers`                        | List registered servers                          |
| `POST`   | `/v1/mcp-servers`                        | Register a server (syncs tools immediately)      |
| `GET`    | `/v1/mcp-servers/{server_id}`            | Retrieve one server                              |
| `PATCH`  | `/v1/mcp-servers/{server_id}`            | Update (re-syncs when connection details change) |
| `DELETE` | `/v1/mcp-servers/{server_id}`            | Remove a server                                  |
| `POST`   | `/v1/mcp-servers/{server_id}/sync-tools` | Re-fetch the server's tool list                  |
| `POST`   | `/v1/mcp`                                | ThunderPhone's own MCP endpoint (JSON-RPC)       |

`{server_id}` is the server's **UUID**. Writes require the `admin`
role.

## MCP server object

```json theme={null}
{
  "id": "1c9d2e4f-…",
  "display_name": "Internal ops tools",
  "url": "https://mcp.example.com/mcp",
  "transport": "streamable_http",
  "headers": [{ "key": "Authorization" }],
  "enabled": true,
  "last_tools_sync_at": "2026-04-20T18:24:10.113Z",
  "cached_tools": [
    {
      "type": "function",
      "function": {
        "name": "mcp_1c9d2e4f…_create_ticket",
        "description": "Create a support ticket",
        "parameters": { "type": "object", "properties": { "…": {} } }
      },
      "mcp": { "server_id": "1c9d2e4f-…", "tool_name": "create_ticket" }
    }
  ],
  "created_at": "2026-04-20T18:24:10.113Z",
  "updated_at": "2026-04-20T18:24:10.113Z"
}
```

| Field                | Type              | Description                                                                                                                                                  |
| -------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id`                 | UUID              | Server id                                                                                                                                                    |
| `display_name`       | string            | 1–255 chars                                                                                                                                                  |
| `url`                | string            | The server's streamable-HTTP endpoint. Must be `http(s)` and resolve **only to public IP addresses** (SSRF guard)                                            |
| `transport`          | string            | Only `streamable_http` is supported                                                                                                                          |
| `headers`            | array             | Static headers sent on every connection. **Key names only** are returned (values never leave the server), and only to `admin+` members — others see `[]`     |
| `enabled`            | boolean           | Disabled servers keep their config but their tools stop being offered to agents                                                                              |
| `last_tools_sync_at` | timestamp \| null | Last successful tool sync                                                                                                                                    |
| `cached_tools`       | array             | The synced tool list in OpenAI function format. Tool names are namespaced `mcp_<server-id>_<tool>` to avoid collisions; `mcp.tool_name` is the original name |

***

## Register a server

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.thunderphone.com/v1/mcp-servers \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "display_name": "Internal ops tools",
      "url": "https://mcp.example.com/mcp",
      "headers": [{ "key": "Authorization", "value": "Bearer secret-token" }]
    }'
  ```
</CodeGroup>

| Field          | Type                    | Required | Description                                    |
| -------------- | ----------------------- | -------- | ---------------------------------------------- |
| `display_name` | string                  | yes      | ≤ 255 chars                                    |
| `url`          | string                  | yes      | ≤ 2048 chars; public-IP HTTPS/HTTP endpoint    |
| `transport`    | string                  | no       | `streamable_http` (the only value)             |
| `headers`      | array of `{key, value}` | no       | Header names must be unique (case-insensitive) |
| `enabled`      | boolean                 | no       | Default `true`                                 |

The create **connects to the server and syncs its tools inline** — if
the server is unreachable or the MCP handshake fails, the request
fails with `400` (`{"url": "Unable to synchronize MCP tools: …"}`)
and nothing is saved. Returns `201 Created` with the
[server object](#mcp-server-object).

## Update / delete / re-sync

`PATCH` accepts any subset of the create fields. Changing
`display_name`, `url`, `transport`, or `headers` triggers a re-sync
(same `400` on failure). When updating `headers`, an entry with an
empty `value` keeps the existing stored value for that key — so you
can reorder/rename without re-sending secrets.

`DELETE` returns `204 No Content` (agents attached to the server
simply lose those tools).

`POST /v1/mcp-servers/{id}/sync-tools` re-fetches the tool list and
returns the updated server object — call it after deploying new tools
to your MCP server.

***

## ThunderPhone as an MCP server

`POST /v1/mcp` implements MCP's JSON-RPC methods: `initialize`,
`notifications/initialized`, `tools/list`, and `tools/call`. Point any
MCP client at `https://api.thunderphone.com/v1/mcp` with your API key
as a Bearer token (this endpoint accepts **only** `sk_live_` keys —
no session auth).

Available tools:

| Tool                  | Arguments                              | Description                                                                              |
| --------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------- |
| `list_agents`         | —                                      | List agents (`id`, `name`, `product`, `voice`)                                           |
| `get_agent`           | `agent_id`                             | Get one agent                                                                            |
| `place_call`          | `agent_id`, `from_number`, `to_number` | Place an outbound call (same guards as [`POST /v1/call`](/api-reference/outbound-calls)) |
| `get_call`            | `call_id`                              | Call status, summary, and grade                                                          |
| `list_calls`          | `limit` (1–100), `status`              | Recent calls                                                                             |
| `get_call_transcript` | `call_id`                              | Full transcript                                                                          |

Example `tools/call` exchange:

```json Request theme={null}
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": { "name": "list_agents", "arguments": {} }
}
```

```json Response theme={null}
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [{ "type": "text", "text": "[{\"id\": 12, \"name\": \"Customer Support Agent\", …}]" }],
    "isError": false
  }
}
```

Tool errors are reported in-band (`isError: true`); unknown JSON-RPC
methods return a `-32601` error with HTTP `400`.

***

## Related

<CardGroup cols={2}>
  <Card title="Agents" icon="robot" href="/api-reference/agents">
    Attach servers to an agent with `mcp_server_ids`.
  </Card>

  <Card title="Integrations" icon="plug" href="/api-reference/integrations">
    Simple HTTP tools without an MCP server.
  </Card>
</CardGroup>
