# EasyVoice MCP Server — connection file

Give this file to your AI assistant. Reading only this file, an assistant can
connect to EasyVoice over MCP and drive every platform service: instant text to
speech (56 voices), long-form narration, two-speaker podcasts, voice cloning,
and account usage. Verified July 2026.

## Endpoint

```
https://easyvoice.ae/api/mcp
```

- Transport: MCP Streamable HTTP — POST only, single JSON responses (no SSE),
  stateless (no session ids). GET and DELETE return 405: that is expected
  behavior, not an outage.
- Protocol revisions accepted: 2025-11-25, 2025-06-18, 2025-03-26.

## Authentication

Primary (preferred — byte-identical to the EasyVoice REST API):

```
Authorization: Bearer ev_your_api_key
```

Fallback for clients without custom-header support (the header wins if both are
sent):

```
https://easyvoice.ae/api/mcp?key=ev_your_api_key
```

- `initialize` and `tools/list` work without a key; every `tools/call` requires
  a valid key.
- Create, revoke, and re-create keys at https://easyvoice.ae/account/keys —
  free account, no card.
- A key in the URL can land in server access logs and client config files —
  prefer the header, and revoke/re-create the key if a URL ever leaks.

## Plans — what your key can do

- **Free key:** 12 of the 56 voices, 20 requests/minute, 2 concurrent
  requests, shared 5,000 characters/day pool (resets midnight UTC). Tools:
  `text_to_speech`, `list_voices`, `get_usage`. No card required.
- **Pro ($9.99/month flat):** all 56 voices, unlimited characters (fair use
  10M/month), 60 requests/minute, plus the async tools — long-form, podcast,
  and cloning. 14-day money-back guarantee. Upgrade at
  https://easyvoice.ae/pricing
- Pro-gated tools called with a free key return a truthful error
  (`isError: true`) — for the job tools it is exactly: "The Jobs API requires
  a Pro subscription — free API keys can use /v1/audio/speech." There are no
  promo codes; $9.99 flat is the price.

## Tools — seven, in four groups

### Group 1 — Instant TTS

#### text_to_speech

Convert text to a hosted MP3/WAV download link. Works on free keys. Per-call
cap: 8,000 characters (4,000 for Arabic `ar_*` voices).

Input schema:

```json
{
  "type": "object",
  "properties": {
    "text": { "type": "string", "description": "The text to speak." },
    "voice": { "type": "string", "default": "af_aoede" },
    "speed": { "type": "number", "minimum": 0.5, "maximum": 2, "default": 1 },
    "format": { "type": "string", "enum": ["mp3", "wav"], "default": "mp3" }
  },
  "required": ["text"]
}
```

Worked example:

```json
// tools/call arguments
{ "text": "Hello from my AI agent!", "voice": "af_aoede", "format": "mp3" }

// result (abridged)
{ "audio_url": "https://easyvoice.ae/api/tts/audio/1f6f7c2e-8a41.mp3",
  "voice": "af_aoede", "format": "mp3", "characters": 23 }
```

Notes:

- The result is a hosted download URL
  (`https://easyvoice.ae/api/tts/audio/<uuid>.<ext>`).
  Audio links are not guaranteed to persist — download promptly.
- Over 8,000 characters on a Kokoro voice: use `generate_long_form` (Pro) or
  the web studio. Over 4,000 characters on an `ar_*` Arabic voice: use
  `POST /api/v1/audio/speech` (REST — Arabic sync cap 12,000) or the web app.
  Never send Arabic to `generate_long_form`: it is Kokoro-only and rejects
  `ar_*` voices.
- Cloned `voice_*` ids are NOT accepted by this tool — it returns an error
  pointing at `POST /api/v1/audio/speech` (REST, same key) for synchronous
  cloned synthesis, or `create_podcast` to use clones over MCP.

#### list_voices

No parameters (`{}`). Lists all 56 catalog voices with `tier` (`free` | `pro`)
and `available` flags, plus your cloned voices with their status. Call this
before picking a `voice` id — `af_aoede` is the default and is free.

```json
// result (abridged)
{ "plan": "free",
  "voices": [ { "id": "af_aoede", "name": "Aoede", "language": "English",
                "tier": "free", "available": true } ],
  "cloned": [ { "id": "voice_abc123", "name": "My Voice", "status": "ready" } ] }
```

### Group 2 — Async jobs (long-form, podcast, status)

**Pro gate, stated once:** these three tools require a Pro subscription key.
A free key gets back the truthful error above. The agent flow for every job:

1. Create — `generate_long_form` or `create_podcast` returns a `job_id`.
2. Poll — call `get_job_status` with that `job_id` until `status` is
   `"completed"` (or `"failed"`).
3. Download — fetch the `audio_url` from the completed result. Long-form and
   podcast audio is retained about 7 days after completion, so you can re-fetch
   the link any time within that window by calling `get_job_status` again with
   the same `job_id`.

#### generate_long_form

Narrate a full script as one async job — up to 500,000 characters. Kokoro
narration voices ONLY (`ar_*` Arabic and cloned `voice_*` ids are rejected).

Input schema:

```json
{
  "type": "object",
  "properties": {
    "input": { "type": "string", "description": "The full script, up to 500,000 characters." },
    "voice": { "type": "string", "default": "af_aoede" },
    "speed": { "type": "number", "minimum": 0.5, "maximum": 2, "default": 1 },
    "format": { "type": "string", "enum": ["mp3", "wav"], "default": "mp3" }
  },
  "required": ["input"]
}
```

Worked example (full flow):

```json
// tools/call arguments
{ "input": "Chapter 1. The full 120,000-character script...", "voice": "af_aoede" }

// result
{ "job_id": "1f6f7c2e-...", "status": "queued", "input_chars": 120000 }

// poll get_job_status with { "job_id": "1f6f7c2e-..." } until completed:
{ "id": "1f6f7c2e-...", "status": "active", "completed": 3, "total": 12 }
{ "id": "1f6f7c2e-...", "status": "completed",
  "audio_url": "https://easyvoice.ae/api/tts/audio/1f6f7c2e.mp3" }
```

#### create_podcast

Two-speaker (A/B) podcast episode as an async job. Caps: max 60 segments,
30,000 combined characters per episode (Pro). Your READY cloned `voice_*` ids
are allowed as either speaker.

Input schema:

```json
{
  "type": "object",
  "properties": {
    "segments": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "speaker": { "type": "string", "enum": ["A", "B"] },
          "text": { "type": "string" }
        },
        "required": ["speaker", "text"]
      },
      "minItems": 1,
      "maxItems": 60
    },
    "voice_a": { "type": "string" },
    "voice_b": { "type": "string" },
    "format": { "type": "string", "enum": ["mp3", "wav"], "default": "mp3" }
  },
  "required": ["segments", "voice_a", "voice_b"]
}
```

Worked example (full flow):

```json
// tools/call arguments
{ "segments": [
    { "speaker": "A", "text": "Welcome to the show." },
    { "speaker": "B", "text": "Great to be here." } ],
  "voice_a": "af_aoede", "voice_b": "am_adam" }

// result
{ "job_id": "3a9f1b7c-...", "status": "queued" }

// poll get_job_status; the completed job carries the episode audio_url plus
// per-segment audio URLs.
```

#### get_job_status

Check any job owned by your key.

Input schema:

```json
{
  "type": "object",
  "properties": {
    "job_id": { "type": "string", "description": "Job id returned by an async tool." }
  },
  "required": ["job_id"]
}
```

```json
// tools/call arguments
{ "job_id": "1f6f7c2e-..." }

// result (abridged) — long-form jobs add completed/total part progress;
// podcast jobs add per-segment audio URLs
{ "id": "1f6f7c2e-...", "status": "completed",
  "audio_url": "https://easyvoice.ae/api/tts/audio/1f6f7c2e.mp3" }
```

### Group 3 — Voice cloning

#### clone_voice

Enroll a custom cloned voice from an audio sample (async). Gating, all
enforced server-side: Pro subscription only; `consent` must be literally
`true` (an attestation that you have the recording rights — it is recorded);
5 enrollments per day; 3 cloned voices max (a full account gets a 409 —
delete one first). Sample: 10 MB max, wav/mp3/m4a, a 15–60 second clean
single-speaker recording works best. Provide exactly ONE of `audio_base64` or
`audio_url` (public https, redirects not followed).

Input schema:

```json
{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "consent": { "type": "boolean", "const": true },
    "audio_base64": { "type": "string" },
    "audio_url": { "type": "string" },
    "mime_type": { "type": "string", "default": "audio/wav" }
  },
  "required": ["name", "consent"],
  "oneOf": [ { "required": ["audio_base64"] }, { "required": ["audio_url"] } ]
}
```

Worked example:

```json
// tools/call arguments
{ "name": "My Narrator", "consent": true,
  "audio_url": "https://example.com/sample.wav" }

// result
{ "voice_id": "voice_9f2c...", "status": "enrolling" }
```

After enrolling, check `list_voices` until the clone's status is `"ready"`,
then use it in `create_podcast`. For synchronous cloned synthesis use
`POST /api/v1/audio/speech` (REST, same key) — `text_to_speech` does not take
cloned ids.

### Group 4 — Account

#### get_usage

No parameters (`{}`). Returns plan, remaining free characters, rate limits,
and the daily reset time. Call it to self-handle quota errors instead of
retrying blindly.

```json
// result (free key)
{ "plan": "free", "used": 1200, "remaining": 3800, "limit": 5000,
  "rpm_limit": 20, "concurrency_limit": 2, "reset_at": "2026-07-22T00:00:00Z" }
```

## Client setup (condensed)

- **claude.ai** — Settings → Connectors → Add custom connector. URL
  `https://easyvoice.ae/api/mcp`, request header (beta)
  `Authorization: Bearer ev_your_api_key`.
- **Claude Desktop** — same account-level Connectors UI as claude.ai. Note:
  `claude_desktop_config.json` takes local stdio servers only — for remote use
  the Connectors UI or the mcp-remote bridge below.
- **Claude Code** —
  `claude mcp add --transport http easyvoice https://easyvoice.ae/api/mcp --header "Authorization: Bearer ev_your_api_key"`
- **ChatGPT developer mode** (Plus/Pro/Business/Enterprise/Edu, web) — add a
  connector with URL `https://easyvoice.ae/api/mcp?key=ev_your_api_key` and
  authentication "None" (the form has no custom-header field). Hedge: Plus/Pro
  may restrict connector tools to read-only (multiply-reported, unconfirmed).
- **Cursor** — `~/.cursor/mcp.json`:
  `{"mcpServers":{"easyvoice":{"url":"https://easyvoice.ae/api/mcp","headers":{"Authorization":"Bearer ev_your_api_key"}}}}`
  (or keep the key out of the file with `${env:EASYVOICE_API_KEY}`)
- **Anything else** —
  `npx mcp-remote https://easyvoice.ae/api/mcp --header "Authorization:Bearer ev_your_api_key"`
  (Windows: no space after the colon, or use `?key=`).

## Limits

| Limit | Free | Pro ($9.99/mo) |
| --- | --- | --- |
| Voices | 12 free voices | All 56 + your cloned voices |
| Characters | 5,000/day shared pool, resets midnight UTC | Unlimited — fair use 10M API chars/mo |
| Requests per minute | 20 | 60 |
| Concurrent requests | 2 | No per-key cap |
| Instant TTS per call | 8,000 chars (4,000 on `ar_*`) | 8,000 chars (4,000 on `ar_*`) |
| Long-form per job | Pro only | 500,000 chars — Kokoro voices only |
| Podcast per episode | Pro only (via API key) | 30,000 chars, max 60 segments |
| Cloning | Pro only | 5 enrollments/day, 3 cloned voices max |

## Troubleshooting one-liners

- **401 on tools/call** — missing/invalid key; the connector saves fine
  without one (initialize + tools/list are open), but tools/call needs a key
  from https://easyvoice.ae/account/keys
- **403 Pro voice** — "This voice is only available on the Pro plan." (free
  key + a pro-tier voice).
- **403 job tools** — "The Jobs API requires a Pro subscription — free API
  keys can use /v1/audio/speech."
- **403 cloning** — cloning requires a Pro subscription; free keys get the
  truthful error.
- **429** — `rate_limit_exceeded` (20/min free, 60/min Pro),
  `concurrency_limit_exceeded` (2 in flight on free), or
  `daily_quota_exceeded` (free 5,000/day spent — resets midnight UTC).
  Cloning's 5/day enrollment cap also surfaces as `rate_limit_exceeded`.
  Call `get_usage` to see where you stand.
- **409 voice_quota_exceeded** — 3 cloned voices max; delete one
  (`DELETE /api/v1/voices/{id}`) and retry.
- **GET returns 405** — expected; the endpoint is POST-only.
- **mcp-remote on Windows** — write `"Authorization:Bearer ev_your_api_key"`
  with no space after the colon, or use the `?key=` URL.

## Links

- Setup and full docs: https://easyvoice.ae/mcp
- API keys (create/revoke): https://easyvoice.ae/account/keys
- Pricing: https://easyvoice.ae/pricing

---

Verified July 2026. Counts and limits in this file are literal snapshots of
the live catalog (56 voices, 12 free) — the server's `list_voices` tool is
always the source of truth.
