MCP Server
# MCP Server
> User media is private: uploads return opaque references, while media fields in read responses are temporary signed URLs valid for two hours. [Private media access](/media-access).
The [Model Context Protocol](https://modelcontextprotocol.io) (MCP) lets AI
tools call external services directly. Odrazio runs a **hosted remote MCP
server** — no local install, no API key to paste. You add it as a connector,
sign in once through your browser, and your AI tool can create avatars, clone
voices, and generate TTS audio or talking-head video on your behalf.
It exposes the 17 operations in Odrazio's public developer API as MCP tools,
using the same account, plan checks, credits, and underlying service logic.
The MCP transport and response envelope are different from REST, and a few
account-management actions remain dashboard-only.
- **Endpoint**: `https://api.odrazio.com/mcp`
- **Transport**: Streamable HTTP (JSON-RPC 2.0 over a single POST endpoint)
- **Auth**: OAuth 2.1 with PKCE — no API key required
MCP access requires the same **active paid subscription** as the REST API.
The subscription is checked again on every tool call, so an unexpired OAuth
token does not bypass a cancelled or expired plan.
## Transport details
MCP hosts normally handle these details for you. If you are making raw HTTP
requests, send all of the following headers:
```http
Authorization: Bearer
Content-Type: application/json
Accept: application/json, text/event-stream
```
The server is **stateless**: every call is an independent `POST /mcp` request.
It does not issue an `Mcp-Session-Id`, provide a persistent `GET` SSE stream,
or push completion events. Poll `get_avatar`, `get_voice`, or
`get_generation` when work is asynchronous.
Responses are sent as Server-Sent Events. The examples on this site show the
decoded JSON-RPC object from the event's `data:` line; tool data itself is a
JSON string in `result.content[0].text`.
```text
event: message
data: {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"{\"amount\":500}"}]}}
```
See [MCP OAuth](/mcp-oauth) for discovery URLs, the PKCE flow, token refresh,
and revocation.
## Connect
Most MCP hosts let you add a remote connector by URL and handle the OAuth
flow automatically:
1. Open your AI tool's connector settings (e.g. Claude: **Settings → Connectors
→ Add custom connector**; Cursor: **Settings → MCP → Add server**).
2. Enter the endpoint: `https://api.odrazio.com/mcp`.
3. Your browser opens to **Connect to Odrazio**. Log in if needed, review what
the client will be able to do, and click **Allow**.
4. The tool is now connected — no key, secret, or config file to manage.
If your host instead reads a config file, add an entry with the same URL —
it will still trigger the same one-time browser login on first use:
```json
{
"mcpServers": {
"odrazio": {
"url": "https://api.odrazio.com/mcp"
}
}
}
```
## How authentication works
The Odrazio MCP server is a full OAuth 2.1 authorization server. Your AI
tool's host registers itself automatically (RFC 7591 dynamic client
registration) the first time you add the connector — there's no client ID to
create by hand. Clients are public PKCE clients: the authorization-code
exchange uses `S256`, with no client secret.
The consent screen you approve is the same account session as the dashboard:
if you're not already logged in, you'll be sent to log in first, then
returned to **Connect to Odrazio** to approve the specific client. Approving
grants that client access to your developer-API resources — it can spend
credits and act on your avatars, voices, and generations. It cannot manage API
keys or configure webhooks through MCP.
## Tools
Each tool below has its own page with a full JSON-RPC request and response
example.
### Account & credits
| Tool | Equivalent to | Description |
| --- | --- | --- |
| [`get_account`](/mcp-get-account) | `GET /v1/me` | Account id, webhook URL, and plan entitlements. |
| [`get_credits`](/mcp-get-credits) | `GET /v1/credits` | Current credit balance. |
### Uploads
| Tool | Equivalent to | Description |
| --- | --- | --- |
| [`upload_image`](/mcp-upload-image) | `POST /v1/uploads/image` | Upload a base64 selfie/reference image and receive an opaque private reference. |
| [`upload_audio`](/mcp-upload-audio) | `POST /v1/uploads/audio` | Upload a base64 voice sample and receive an opaque private reference. |
### Avatars
| Tool | Equivalent to | Description |
| --- | --- | --- |
| [`list_avatars`](/mcp-list-avatars) | `GET /v1/avatars` | List your avatars with generated images. |
| [`list_builtin_avatars`](/mcp-list-builtin-avatars) | `GET /v1/avatars/built-in` | List platform avatars usable without cloning. |
| [`get_avatar`](/mcp-get-avatar) | `GET /v1/avatars/:id` | One avatar and its images — poll until ready. |
| [`create_avatar`](/mcp-create-avatar) | `POST /v1/avatars` | Create an avatar from a selfie. |
| [`create_avatar_image`](/mcp-create-avatar-image) | `POST /v1/avatars/:id/images` | Generate one more image from a scene preset. |
### Voices
| Tool | Equivalent to | Description |
| --- | --- | --- |
| [`list_voices`](/mcp-list-voices) | `GET /v1/voices` | List your cloned voices. |
| [`list_builtin_voices`](/mcp-list-builtin-voices) | `GET /v1/voices/built-in` | List platform voices usable without cloning. |
| [`get_voice`](/mcp-get-voice) | `GET /v1/voices/:id` | One voice — poll until `READY`. |
| [`create_voice`](/mcp-create-voice) | `POST /v1/voices` | Clone a voice from a reference sample. |
### Generations
| Tool | Equivalent to | Description |
| --- | --- | --- |
| [`list_generations`](/mcp-list-generations) | `GET /v1/generations` | List generation tasks (`status`, `type`, `page`, `limit`). |
| [`get_generation`](/mcp-get-generation) | `GET /v1/generations/:id` | Task status — poll until `COMPLETED`. |
| [`get_download_url`](/mcp-get-generation) | `GET /v1/generations/:id/download` | Mint a fresh two-hour signed result URL for a completed generation. |
| [`create_generation`](/mcp-create-generation) | `POST /v1/generations` | Create a TTS or VIDEO generation. |
Most tool inputs reuse the REST validation schemas and all creation tools call
the same service layer. MCP differs in important ways: successful values are
wrapped in `content[0].text`, tool failures use `isError: true` with a
human-readable message (not a REST error code), and REST
[`Idempotency-Key`](/idempotency) replay is not implemented for MCP calls.
## Webhooks and account settings
`get_account` returns the currently configured `webhookUrl`, but never a
webhook signing secret. Webhooks are account-level settings managed from the
dashboard's **Developers** page, not a `create_generation` argument and not an
MCP tool. The signing secret is revealed only when that dashboard setting is
first created or changed; store it then.
## Typical flow
Ask your AI tool to walk through the same steps as the
[Quickstart](/quickstart):
1. `upload_image` a selfie, then `create_avatar` — poll `get_avatar` until an
image you need is `COMPLETED` and the user avatar is `IMAGE_READY` (or use
`list_builtin_avatars`).
2. `upload_audio` a reference sample, then `create_voice` — poll `get_voice`
until `READY` (or use `list_builtin_voices`).
3. `create_generation` with `type: "TTS"` or `"VIDEO"`. Both types require a
ready `avatarId` and `voiceId`; only `VIDEO` also requires `resolution` and
`avatarImageId`.
4. Poll `get_generation` until `status` is `COMPLETED`, then use the temporary
`ttsAudioUrl` / `videoUrl`. Call `get_download_url` when it expires.
## Polling generations
`create_generation` returns immediately with `status: "PENDING"` — creation
is asynchronous, same as the REST API. The MCP server doesn't expose a
blocking "wait for completion" tool; call `get_generation` again to check
progress. Most agents do this naturally when asked to "let me know when it's
done."
## Limits and retries
The following mutating tools share a **10 requests per minute per account**
limit: `upload_image`, `upload_audio`, `create_avatar`,
`create_avatar_image`, `create_voice`, and `create_generation`. A limited call
returns HTTP `429` before MCP handles the JSON-RPC message. Read tools have no
separate fixed limit; poll at a sensible interval.
MCP does not support REST's `Idempotency-Key` replay. If a network failure
leaves the result of a mutating tool unknown, check the relevant list/get tool
before retrying so you do not create or charge for duplicate work.
## Errors
Tool handler failures are returned as a successful JSON-RPC response whose
result contains `isError: true` and a human-readable message. Invalid OAuth
tokens, an expired paid plan, rate limits, malformed HTTP requests, and
transport negotiation errors happen **before** tool execution and instead use
HTTP/OAuth error responses. See [MCP OAuth](/mcp-oauth) for those cases and
[Errors](/errors) for REST error-code meanings.