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

# Let a voice agent use other apps' MCP servers during a call

> Connect any remote MCP server, choose which of its tools are allowed, and attach it to an agent. During a call the agent looks things up and makes changes in that app.

An agent can call tools on another app's MCP server while it is on the phone:
look up an order in your backend, check a calendar, add a note to a CRM contact.
There is no integration to build per app. Any app with a **remote MCP server**
(Streamable HTTP or SSE) can be connected.

Three steps:

1. Connect the server with `POST /v1/mcp-servers`. Its tools are read straight away.
2. Choose which tools agents may use with `enabled_tools`.
3. Attach the server to an agent with `mcp_server_ids`.

The console does the same under **Integrations**.

## Connect a server

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.voice.wixzel.com/v1/mcp-servers \
    -H "Authorization: Bearer $WIXZEL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Orders",
      "url": "https://mcp.example.com/mcp",
      "auth": {
        "type": "headers",
        "headers": [{ "name": "Authorization", "value": "Bearer sk_live_..." }]
      }
    }'
  ```

  ```ts TypeScript theme={null}
  const server = await wixzel.mcpServers.create({
    name: 'Orders',
    url: 'https://mcp.example.com/mcp',
    auth: { type: 'headers', headers: [{ name: 'Authorization', value: 'Bearer sk_live_...' }] },
  });
  console.log(server.status, server.tools.map((t) => t.name));
  ```
</CodeGroup>

`name` is what the agent is told the app is called, so use the name a caller
would say. The answer lists every tool the server offers and a `status`:

| status | meaning |
| - | - |
| `ready` | Tools were read. Agents can use it. |
| `needs_auth` | An OAuth server that has not been signed in to, or whose sign-in expired. |
| `error` | It could not be reached. `last_error` says why. |
| `pending` | Not tried yet. |

Agents only use servers that are `ready`. `POST /v1/mcp-servers/{id}/refresh`
reads the tools again and updates the status.

### Authentication

* `none` for a public server.
* `headers` for an API key or any fixed header. Values are encrypted at rest and
  never returned; responses list only the header names. On update, send a header
  without `value` to keep the stored one.
* `oauth` for a server that signs in. Most hosted MCP servers do.

## Servers that sign in with OAuth

Create the server with `"auth": { "type": "oauth" }`, then start the sign-in:

```bash theme={null}
curl -X POST https://api.voice.wixzel.com/v1/mcp-servers/$ID/oauth/start \
  -H "Authorization: Bearer $WIXZEL_API_KEY"
```

```json theme={null}
{
  "object": "mcp_server_oauth",
  "authorization_url": "https://auth.example.com/authorize?client_id=...&state=...",
  "redirect_uri": "https://api.voice.wixzel.com/mcp-oauth/callback",
  "expires_at": "2026-10-02T10:10:00.000Z"
}
```

Open `authorization_url` in a browser and sign in. When the provider sends the
browser back, the server is connected and its tools are read. The link works
once and expires after ten minutes.

Wixzel Voice registers itself with the server's authorization server
automatically when the server allows it. If it does not (GitHub's, for one),
register an OAuth app with the provider using the `redirect_uri` above, and
send its id and secret as `auth.oauth.client_id` and `auth.oauth.client_secret`.

Tokens are refreshed automatically during calls. If a refresh fails, the server
moves to `needs_auth` and agents stop using it until it is connected again.

## Choose the tools

Only tools in `enabled_tools` are ever offered to an agent. Until you set it,
the first discovery enables only the tools the server marks read-only
(`readOnlyHint`). Anything that can change data has to be switched on on
purpose.

```bash theme={null}
curl -X PATCH https://api.voice.wixzel.com/v1/mcp-servers/$ID \
  -H "Authorization: Bearer $WIXZEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled_tools": ["lookup_order", "create_note"] }'
```

The list is replaced as a whole. A tool that disappears from the server is
removed from it at the next refresh.

## Attach it to an agent

```bash theme={null}
curl -X PATCH https://api.voice.wixzel.com/v1/agents/$AGENT_ID \
  -H "Authorization: Bearer $WIXZEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "mcp_server_ids": ["'$ID'"] }'
```

An agent can use up to five servers and 40 tools in total. Send `[]` to detach
all of them. Deleting a server detaches it from every agent.

## What happens on a call

* The tools are declared to the model when the call starts, from the stored
  list, so connecting a server never delays the greeting. The connections open
  in the background.
* Each tool is named `<app>__<tool>`, for example `orders__lookup_order`, and its
  description starts with the app's name.
* The agent says a few words before it uses a tool, so the caller is not left in
  silence. On the classic and Sarvam engines, if the model goes straight to the
  tool, the agent says "One moment, let me check that." for it.
* Before using a tool the server marks as changing data, the agent asks the
  caller to confirm.
* A tool call times out after 10 seconds. Failures become a sentence the agent
  can say ("I couldn't reach Orders right now"); they never end the call.
* Results are cut to 4,000 characters before the model sees them.
* At most 20 tool calls per call, and three rounds of tool calls per caller turn
  before the agent has to answer in words.

Every tool call is recorded on the call. `GET /v1/calls/{id}` returns them in
`tool_calls`, with the arguments, whether it worked, and how long it took.

All four engines support tools: `classic`, `sarvam`, `gemini-live` and
`deepgram-agent`.

## Cost

Tool calls are free. The extra language-model tokens a tool result adds to the
conversation are billed as usual, on the agent's LLM line in
`/v1/usage/events`.

## Security

* **Allowlist.** Only enabled tools are declared, and a call to any other name is
  refused even if the model guesses it.
* **Untrusted results.** The agent is told that tool results are data, not
  instructions.
* **Network.** Server URLs must be public `https` (or `http`) on port 443 or 80.
  Private, loopback and link-local addresses are refused when the server is saved
  and again on every request, including each redirect, and the connection goes
  to the address that was checked. A redirect to another host does not carry
  your headers.
* **Secrets.** Header values, OAuth tokens and client secrets are encrypted at
  rest and never returned by the API.
* **Scopes.** Managing servers needs `mcp_servers:read` and `mcp_servers:write`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.