# ViewMax MCP Setup & Configuration Guide

Connect an MCP client to ViewMax - tools, arguments, credit costs, task polling, idempotent retries, and error handling for video, image, music, and audio generation.

Looking for an overview of what the server can do? Start from the main [ViewMax MCP page](https://viewmax.studio/mcp) - this guide covers setup and configuration in detail.

## Endpoint and authentication

ViewMax exposes a remote MCP server named `viewmax`:

```text
https://viewmax.studio/api/mcp
```

It uses Streamable HTTP only: `GET` returns 405 and there is no legacy SSE endpoint.

**OAuth (claude.ai and Claude Desktop).** Add a custom connector with the URL above, click Connect, and sign in with your ViewMax account. Clients discover the flow through `/.well-known/oauth-protected-resource`; no API key is needed.

**API key (Claude Code, Cursor, Codex, VS Code, SDKs).** Create a key in [Settings → API Keys](https://viewmax.studio/settings/apikeys) and send it on every request:

```http
Authorization: Bearer sk-your-api-key
```

Without an `Authorization` header the server still answers `initialize`, `tools/list`, and the catalog tools (`list_video_models`, `get_video_model`, `list_image_models`, `get_image_model`, `list_music_models`, `list_voices`). `get_task`, `wait_for_task`, `get_credits`, and every `generate_*` tool return an `unauthorized` error. A bearer token that is neither a valid API key nor a valid OAuth access token gets HTTP 401 with an OAuth challenge, so a client configured with a revoked key may ask you to sign in instead; create a new key.

## Connect a client

Each snippet points at the same endpoint. Keep the key in the `VIEWMAX_API_KEY` environment variable rather than in a committed file. These snippets follow each client's documented configuration format; client syntax changes between versions, so if a field is rejected, use your client's MCP guide with the URL and header above.

**claude.ai and Claude Desktop.** Settings → Connectors → Add custom connector. Name it ViewMax, paste `https://viewmax.studio/api/mcp`, click Connect, and sign in.

**Claude Code.**

```bash
claude mcp add --transport http viewmax https://viewmax.studio/api/mcp \
  --header "Authorization: Bearer $VIEWMAX_API_KEY"
```

To share the server with a project, commit `.mcp.json`. Claude Code expands `${VIEWMAX_API_KEY}` from each developer's environment:

```json
{
  "mcpServers": {
    "viewmax": {
      "type": "http",
      "url": "https://viewmax.studio/api/mcp",
      "headers": {
        "Authorization": "Bearer ${VIEWMAX_API_KEY}"
      }
    }
  }
}
```

**Cursor.** Add to `~/.cursor/mcp.json` (or `.cursor/mcp.json` in a project), then reload Cursor:

```json
{
  "mcpServers": {
    "viewmax": {
      "url": "https://viewmax.studio/api/mcp",
      "headers": {
        "Authorization": "Bearer ${env:VIEWMAX_API_KEY}"
      }
    }
  }
}
```

**Codex (ChatGPT).** Codex reads the key from the named environment variable:

```bash
codex mcp add viewmax --url https://viewmax.studio/api/mcp \
  --bearer-token-env-var VIEWMAX_API_KEY
```

The equivalent `~/.codex/config.toml` entry:

```toml
[mcp_servers.viewmax]
url = "https://viewmax.studio/api/mcp"
bearer_token_env_var = "VIEWMAX_API_KEY"
```

**VS Code.** Add `.vscode/mcp.json`; VS Code prompts for the key once and stores it securely:

```json
{
  "inputs": [
    {
      "type": "promptString",
      "id": "viewmax-api-key",
      "description": "ViewMax API key",
      "password": true
    }
  ],
  "servers": {
    "viewmax": {
      "type": "http",
      "url": "https://viewmax.studio/api/mcp",
      "headers": {
        "Authorization": "Bearer ${input:viewmax-api-key}"
      }
    }
  }
}
```

**Any other client.** Agents that can edit their own MCP configuration can connect themselves. Paste: "Add the ViewMax MCP server to this client: Streamable HTTP transport, URL https://viewmax.studio/api/mcp, HTTP header `Authorization: Bearer <my API key>`. Then call `get_credits` to verify the connection."

`list_video_models` works without authentication, so it only proves the server is reachable; `get_credits` proves the connection is authenticated.

## Tools

The server generates **video, image, music, and audio**. Generation consumes credits from the connected account. On Pro/Ultra, flagship images (GPT Image 2, GPT Image 2.5, Nano Banana 2, Grok Imagine) use the shared daily fair-use pool, and so does ViewMax C1 on Ultra; `cost_credits` is `0` when the pool covers a task.

Every tool result is one text block containing JSON. Catalog tools, `get_task`, `wait_for_task`, and `get_credits` are marked read-only (`readOnlyHint`), so clients may run them without asking. `generate_*` tools are marked not read-only, non-destructive, not idempotent, and open-world.

### Tasks and account

| Tool            | Arguments                                                        | Result                                                                                                                                                                            |
| --------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `get_task`      | `task_id`                                                        | `task_id`, `status`, `media_type`, `cost_credits`; `output_urls` once results exist (video tasks also `video_urls`); `error_code` and `error_message` when `failed` or `canceled` |
| `wait_for_task` | `task_id`, optional `timeout_seconds` (integer 1–50, default 45) | Checks every 5 seconds until the task finishes or the timeout passes; returns the `get_task` fields, plus `poll_hint` while the task is still running                             |
| `get_credits`   | none                                                             | `remaining_credits`                                                                                                                                                               |

### Video

| Tool                | Arguments                                                                                                                                                                   | Result                                                                                                                                                  |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `list_video_models` | none                                                                                                                                                                        | Each model's `id`, `label`, `vendor`, per-mode durations and resolutions, and `credits_label`                                                           |
| `get_video_model`   | `model`                                                                                                                                                                     | Full catalog entry: per-mode durations, resolutions, aspect ratios, `audio_toggle`, credits, `defaults`, and `max_prompt_length` when the model has one |
| `generate_video`    | `model`, `prompt`; optional `mode`, `image_urls`, `video_urls`, `duration`, `resolution`, `aspect_ratio`, `audio`, `source_video_duration_seconds` (> 0), `idempotency_key` | `task_id`, `status`, `cost_credits`, `poll_hint`                                                                                                        |

- If `mode` is omitted, it is `image-to-video` when `image_urls` is set, `video-to-video` when `video_urls` is set, and otherwise `text-to-video`.
- Omitted `duration`, `resolution`, and `aspect_ratio` are filled from the mode's `defaults` before pricing, so `cost_credits` matches what is rendered.
- Send `audio: true` only when the mode's `audio_toggle` is `true`.
- Per-second models (Seedance 2.x, Seedance 2.5, MiniMax H3) need `source_video_duration_seconds` with `video_urls`.
- Media URLs must be public `http(s)` URLs the provider can fetch without authentication.

### Image

| Tool                | Arguments                                                                                                                             | Result                                                                                          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| `list_image_models` | none                                                                                                                                  | Each model's `id`, `label`, `vendor`, per-mode aspect ratios and qualities, and `credits_label` |
| `get_image_model`   | `model`                                                                                                                               | Full capability and credit pricing for one image model                                          |
| `generate_image`    | `model`, `prompt`; optional `scene` (`text-to-image` or `image-to-image`), `image_urls`, `aspect_ratio`, `quality`, `idempotency_key` | `task_id`, `status`, `cost_credits`, `poll_hint`                                                |

If `scene` is omitted, it is `image-to-image` when `image_urls` is set. GPT Image 2.5 rejects an unknown `quality` or size; other models replace an unknown `aspect_ratio` or `quality` with their default and bill that value, so send only values the model lists.

### Music

| Tool                | Arguments                                                                                                       | Result                                                             |
| ------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `list_music_models` | none                                                                                                            | The music model, its controls, and credit cost                     |
| `generate_music`    | `prompt`; optional `duration_seconds` (3–300, default 60), `instrumental`, `style`, `lyrics`, `idempotency_key` | `task_id`, `status`, `cost_credits`; usually already `output_urls` |

Music costs 60 credits up to 60 seconds, then 1 credit per second; plan allowances do not cover music. To describe a track, put the description in `prompt` and omit `style`. Sending `style` makes the provider treat `prompt` as the song's lyrics, so when you use it, do not also send `lyrics`.

### Audio

| Tool                    | Arguments                                                                                                                                                               | Result                                                                                                                                                                                                        |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `list_voices`           | none                                                                                                                                                                    | `default_model`, `characters_per_credit` (20), `minimum_credits` (1), and `voices` (`id`, `name`, `gender`, `language`, `languages`, `accent`, `use_case`, `description`, `preview_url`, `recommended_model`) |
| `generate_speech`       | `text`, `voice_id`; optional `model_id` (defaults to the voice's `recommended_model`), `speed` (0.25–4), `stability` (0–1), `similarity_boost` (0–1), `idempotency_key` | `task_id`, `status`, `cost_credits`; usually already `output_urls`                                                                                                                                            |
| `generate_sound_effect` | `prompt`; optional `duration_seconds` (0.5–22), `prompt_influence` (0–1), `idempotency_key`                                                                             | `task_id`, `status`, `cost_credits`; usually already `output_urls`                                                                                                                                            |

Speech costs `ceil(characters / 20)` credits, at least 1. A sound effect costs 5 credits.

The same model validation, pricing, and refund rules as [the v1 API](https://viewmax.studio/docs/api) apply.

## Workflow for agents

1. **Choose a model.** Call the matching `list_*` tool, then `get_video_model` or `get_image_model` for the model you pick. Read its modes, allowed values, `defaults`, and `max_prompt_length`.
2. **Confirm the cost.** Tell the user which model you will use and how many credits it costs, computed from the catalog pricing and the values you will send (or the mode's `defaults`). Wait for their confirmation before any `generate_*` call. `get_credits` shows the balance.
3. **Create once.** Call the `generate_*` tool with a new `idempotency_key`, for example a UUID you generate for this request.
4. **Poll.** If `status` is `pending` or `processing`, call `wait_for_task` with the `task_id`, and call it again while the result has a `poll_hint`. Video can take several minutes. The server has no task timeout, and a task is never lost: set your own deadline and resume later with `get_task`. Music, speech, and sound effects usually finish in the create call.
5. **Return the result.** On `success`, give the user `output_urls`. On `failed` or `canceled`, report `error_message`; the credits are refunded automatically.

## Idempotent retries

Every `generate_*` tool accepts `idempotency_key` (1–200 visible ASCII characters, no spaces). If a call times out or the connection drops, call the tool again with the same key: ViewMax returns the task the first call created, with its original `cost_credits`, and charges nothing again. The arguments are not compared, so use a new key for each new request. Without a key, every call creates and charges a new task. MCP keys are separate from REST `Idempotency-Key` values.

## Errors and recovery

A failed tool call has `isError: true` and one text block containing JSON:

```json
{
  "error": "minimax-h3 prompt must be 7000 characters or fewer, got 7412",
  "error_type": "invalid_request",
  "hint": "Fix the arguments using this message, then call the tool again. Re-read the model with get_video_model or get_image_model before repeating an unsupported model or option."
}
```

`error_type` uses the same values as the REST `error.type`, and `hint` says what to do next. `task_id` is added when the call created a task before failing.

| `error_type`           | Typical causes                                                                                                                                                                                                    | What to do                                                                                                                                                              |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `unauthorized`         | No OAuth token or API key on the connection                                                                                                                                                                       | Connect with OAuth, or send `Authorization: Bearer sk-...` with a key from [Settings → API Keys](https://viewmax.studio/settings/apikeys)                               |
| `invalid_request`      | Unknown or offline model (`video model temporarily unavailable: ...`), unsupported mode or option, prompt longer than `max_prompt_length`, unknown `voice_id`, disabled model (`This capability is unavailable.`) | Fix the arguments using `error`; re-read `get_video_model` or `get_image_model`. With `task_id`, the provider rejected the settings and the task was refunded           |
| `content_rejected`     | The prompt mentions a prohibited use (deepfake, face swap, impersonation), even inside a negative instruction; or provider moderation refused the prompt or media                                                 | Change the content. Retrying unchanged fails again                                                                                                                      |
| `insufficient_credits` | The balance is below the cost; no task was created                                                                                                                                                                | Tell the user. Do not retry until credits are added at [pricing](https://viewmax.studio/pricing)                                                                        |
| `not_found`            | The `task_id` does not exist or belongs to another account                                                                                                                                                        | Use a `task_id` returned to this account                                                                                                                                |
| `internal_error`       | A provider or server failure                                                                                                                                                                                      | Follow `hint`: retry once when the task failed and was refunded; when the provider may still finish, call `wait_for_task` with `task_id` instead of creating a new task |

Arguments outside a tool's input schema, such as `timeout_seconds: 120`, are rejected before the tool runs with a plain-text `Input validation error: ...` message. See [API errors](https://viewmax.studio/docs/api/errors) for the shared classification.
