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.