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

# MCP Server

> Connect your coding agent to the hosted Tavus MCP server to build PALs, wire bidirectional tool calls into your own code, and test the integration end to end.

The Tavus MCP server is a hosted endpoint your coding agent connects to. Once it is wired into Codex, Claude Code, Cursor, or another MCP client, your agent can build and patch a PAL, define the tools that PAL can call, attach them, and start test conversations, all from your editor against your own codebase.

There is nothing to install or run. You connect over HTTPS and authenticate once in the browser.

## Why connect your editor

A working voice agent has two parts that have to agree:

1. The PAL needs to know which tools exist and when to call them. That lives in the PAL's tool definitions and prompt.
2. Your application needs to handle those calls when they fire. That lives in your code.

Keeping those two parts in sync by hand is where integrations drift. The MCP server lets one agent work both sides: it defines the tool on the PAL and can scaffold and check the matching handler in your repo, so the two stay consistent. You then test the exchange by starting a conversation and watching the tool fire and your handler respond, without leaving your editor.

<CardGroup cols={3}>
  <Card title="Develop the PAL" icon="user-gear">
    Create and patch the PAL's layers, prompt, guardrails, and objectives.
  </Card>

  <Card title="Wire tool calls" icon="plug">
    Define tools, attach them, and generate the handler code in your own app.
  </Card>

  <Card title="Test the integration" icon="vial">
    Start chat or full conversations and watch tool calls round-trip live.
  </Card>
</CardGroup>

## Connect a client

The server is reachable at an HTTPS `/mcp` endpoint. Authentication uses a browser-based OAuth flow: the PAL Maker mints a per-user API key and the server forwards it to the Tavus API as `x-api-key`. No key or shared token sits in your client config.

<CardGroup cols={2}>
  <Card title="Production" icon="globe">
    `https://mcp.tavus.io/mcp` (custom domain).
  </Card>

  <Card title="Preview" icon="globe">
    `https://mcp.tavus-preview.io/mcp` (Cloudflare-owned domain).
  </Card>
</CardGroup>

<Steps>
  <Step title="Step 1: Add the server">
    Point your MCP client at the hosted endpoint.

    For Codex:

    ```bash theme={null}
    codex mcp add tavus --url https://mcp.tavus-preview.io/mcp
    ```

    For Claude Code:

    ```bash theme={null}
    claude mcp add -s user --transport http tavus https://mcp.tavus-preview.io/mcp
    ```

    This registers the server under the name `tavus` for your user scope.

    <Warning>
      Never put a Tavus API key or shared bearer token in your MCP client config. The hosted server authenticates each user through the PAL Maker and keeps keys user-scoped and out of client configuration.
    </Warning>
  </Step>

  <Step title="Step 2: Authenticate in the browser">
    On first use, the client runs an OAuth flow against the server. For Codex, you can start it directly:

    ```bash theme={null}
    codex mcp login tavus
    ```

    Then the flow is:

    1. The client initiates the authorize flow.
    2. The portal redirects to `/dev/cli-authorize?mode=oauth`.
    3. You sign in.
    4. The portal mints a per-user Tavus API key.
    5. You are redirected back to the client's loopback callback.
    6. The server exchanges the authorization code and forwards the minted key to the Tavus API as `x-api-key` on every downstream call.
  </Step>

  <Step title="Step 3: Drive Tavus from your agent">
    Once authenticated, the full Tavus toolset is available: PAL CRUD, faces, conversations, builder, chat-mode testing, guardrails, objectives, tools, and pronunciation dictionaries. See [Agentic PAL building & testing](/sections/agent-tools/pal-build-and-verify) for the autonomous PAL loop, or the [MCP tools reference](/sections/agent-tools/mcp-tools-reference) for the full catalog.

    <Note>
      MCP tools return data and file manifests. They do not write files themselves. Your client decides what to do with the returned data, such as writing a generated tool handler into your repo.
    </Note>
  </Step>
</Steps>

## Bidirectional tool calls

A tool call in Tavus is an exchange, and that exchange is what connects the PAL to your app:

1. During a conversation the PAL decides a tool is needed, based on the tool's `description` and the PAL's prompt, and calls it with arguments.
2. Tavus delivers that call to your code.
3. Your code runs its logic and returns a result.
4. The PAL uses the result to decide what to say and do next.

The PAL calls into your application in steps 1 and 2, and your application's response shapes the PAL's next turn in steps 3 and 4.

### Two delivery channels

A tool's `delivery` field sets where the call is delivered. It is the main choice you make when you define a tool.

<Tabs>
  <Tab title="To your client (app_message)">
    ```json theme={null}
    "delivery": { "app_message": true }
    ```

    The call is emitted to your frontend or client over the conversation's data channel as a [tool-call event](/sections/event-schemas/conversation-toolcall). Your app listens for it and runs local logic.

    Best for actions in the UI: highlight a product, change a slide, navigate a page, or update on-screen state. This is also the default channel for [LLM tool calling](/sections/conversational-video-interface/pal/llm-tool).
  </Tab>

  <Tab title="To your backend (api webhook)">
    ```json theme={null}
    "delivery": {
      "api": {
        "url": "https://your-app.example.com/api/tools/get_order_status",
        "method": "POST",
        "content_type": "application/json",
        "body_template": { "order_id": "{order_id}" },
        "timeout": 10.0
      }
    }
    ```

    Tavus makes a direct HTTPS call to your backend and waits for the JSON response. Best for server-side work such as database lookups, business logic, and third-party APIs.

    The HTTP form also supports `headers`, `query_params`, and `auth` (`none`, `bearer`, `basic`, `api_key`, `hmac`, or `oauth2_client_credentials`). `timeout` defaults to 10 seconds (max 60).

    <Note>
      Any `{placeholder}` used in `url`, `body_template`, or `query_params` must be declared as a property in the tool's `parameters.properties`. The tool's `description` plus `parameters` JSON must total 10,000 characters or fewer.
    </Note>
  </Tab>
</Tabs>

### Controlling what the PAL does around the call

Two fields shape the conversational behavior of the exchange:

| Field           | Common values                          | What it does                                                                                                                                                |
| --------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `on_call`       | `silent`                               | What the PAL does while the tool runs, for example staying silent instead of narrating the call.                                                            |
| `on_resolve`    | `generate_response`, `fire_and_forget` | What happens after the result returns. `generate_response` has the PAL speak based on the result. `fire_and_forget` (the default) does not wait or narrate. |
| `static_filler` | any string                             | A line to say while waiting on a slow tool.                                                                                                                 |

Use `on_resolve: generate_response` when the result should change what the PAL says next, such as an order status or an availability check. Use `fire_and_forget` for side effects the PAL does not need to react to.

### A complete example

A backend lookup the PAL can call to answer "where's my order?":

```json get_order_status tool theme={null}
{
  "name": "get_order_status",
  "description": "Look up the current status of a customer's order. Call this when the user asks about the state, location, or delivery date of an order they reference by number. The result tells you the status and the estimated delivery date so you can relay it.",
  "parameters": {
    "type": "object",
    "properties": {
      "order_id": {
        "type": "string",
        "description": "The order number the customer gave, e.g. 'A-10428'."
      }
    },
    "required": ["order_id"]
  },
  "delivery": {
    "api": {
      "url": "https://your-app.example.com/api/tools/get_order_status",
      "method": "POST",
      "content_type": "application/json",
      "body_template": { "order_id": "{order_id}" },
      "timeout": 10.0
    }
  },
  "origin": "llm",
  "on_call": "silent",
  "on_resolve": "generate_response"
}
```

When the PAL calls it, Tavus POSTs `{ "order_id": "A-10428" }` to your endpoint. Your handler returns JSON, for example:

```json theme={null}
{ "status": "out_for_delivery", "eta": "today by 6pm" }
```

Because `on_resolve` is `generate_response`, the PAL speaks from that result, for example: *"Good news, order A-10428 is out for delivery and should arrive today by 6pm."*

## Build and test it with your agent

One agent can do every step above. A typical loop:

1. **Define the tool.** The agent calls `tavus_tool_create` with the `parameters` and `delivery` that match what the tool should do.
2. **Attach it.** `tavus_pal_tools_attach` wires the tool onto your PAL so it is offered during conversations.
3. **Write the handler.** For an `api` tool, the agent scaffolds the matching endpoint in your repo (the route at `delivery.api.url`) so the request and response shape match the tool's `parameters`.
4. **Test the exchange.** `tavus_chat_start` and `tavus_chat_turn` (text only), or `tavus_conversation_create` (full video), start a session so you can watch the tool fire and your handler respond, then iterate.

For a new PAL, an agent can run this as one autonomous build, simulated-turn test, and judge pass with `tavus_pal_build_and_verify`. See [Agentic PAL building & testing](/sections/agent-tools/pal-build-and-verify).

<Note>
  The server flags a likely duplicate when you create a tool that resembles one you already have, so your agent can attach the existing tool instead. Prefer attaching saved tools over redefining them inline. See the [MCP tools reference](/sections/agent-tools/mcp-tools-reference) for `tavus_tool_list`, `tavus_tool_create`, and `tavus_pal_tools_attach`.
</Note>

## Environment alignment

The server must run in the same environment as the portal that minted your key.

<Warning>
  A `TEST` key authenticated against a production server, or the reverse, makes downstream Tavus API calls return `401`. Keep the endpoint and the portal you sign in to on the same environment.
</Warning>

## Troubleshooting the connection

The server exposes standard OAuth discovery metadata you can inspect directly:

```bash theme={null}
curl https://mcp.tavus-preview.io/.well-known/oauth-protected-resource/mcp
curl https://mcp.tavus-preview.io/.well-known/oauth-authorization-server
curl -i https://mcp.tavus-preview.io/mcp
```

An unauthenticated `/mcp` request should return `401` with a `WWW-Authenticate` header pointing at the protected-resource metadata URL. If that header or the discovery endpoints are missing, the OAuth flow cannot complete. Re-add the server and retry the browser sign-in.
