> For the complete documentation index, see [llms.txt](https://docs.twistly.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.twistly.ai/api-reference/twistly-mcp-server.md).

# Twistly MCP Server

Connect any compatible MCP client to Twistly, then simply ask for a deck — "make me a 12-slide presentation about renewable energy" — and get back a downloadable PowerPoint or PDF.

Server URL: `https://mcp.twistly.ai/mcp`

## How MCP differs from the REST API

Both interfaces use the same generation pipeline. What changes is who calls it and how the caller is identified — MCP is designed for interactive AI clients.

* **No API key.** Users sign in with their normal Twistly account (Google, Microsoft, or an emailed code). Nothing to issue, paste, or rotate.
* **No Twistly account needed up front.** If the email that signed in has no Twistly account yet, a Free one is created automatically on the first generation.
* **The AI client calls the tools, not your code.** The client's model reads the tool schemas and decides when to call which tool from what the user says.
* **Four tools instead of four endpoints:** `create_from_topic`, `create_from_text`, `create_from_file`, `get_job_status`.
* **Asynchronous, same as the REST API.** A `create_*` tool returns a `job_id`; `get_job_status` returns the download link.
* **Default image source is `flux`** (AI-generated), where the REST API defaults to `unsplash`. The REST API's `ai` value doesn't exist here — `flux` replaces it.
* **Billed by account, not by key** — see [Plans and billing](#plans-and-billing).

Use the REST API when integrating from code. Use MCP when users need Twistly inside an AI client.

## Get started

### What you need

* An email address the user can sign in with — Google, Microsoft, or any inbox that can receive a code. A Twistly account is **not** a prerequisite: a Free one is created automatically on the first generation.
* An MCP client that supports **Streamable HTTP** and **OAuth**.
* The server URL: `https://mcp.twistly.ai/mcp`.

### Your first presentation

**Step 1 — Connect Twistly.** Add Twistly using the server URL in your MCP client's connector settings. The client opens the Twistly sign-in page: continue with **Google**, **Microsoft**, or **email** (a 6-digit code arrives by email). Access is granted automatically and the page closes itself after a 5-second countdown.

**Step 2 — Ask for a deck.** In natural language:

```
Make a presentation about the history of coffee — 12 slides, Berlin template
```

The client calls `create_from_topic` and receives a queued job:

```json
{
  "job_id": "9f1c2a4e-6e2c-4f8a-9b3d-1a2b3c4d5e6f",
  "status": "queued",
  "created_at": "2026-07-30T10:15:00.000Z"
}
```

**Step 3 — Get the file.** The client checks the job until generation completes, then shows a permanent download link from `result.url`. Generation usually takes **30–90 seconds**, with status updates while it runs.

### Use with ChatGPT

ChatGPT is one supported MCP client. Add a connector with the server URL above — or, when Twistly appears in the ChatGPT app directory, select it there and choose **Connect**.

## Authentication

Twistly uses OAuth — neither the user nor the MCP client ever handles an API key.

|                         |                                                                                                                    |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------ |
| **Sign-in methods**     | Google, Microsoft, email code (6 digits)                                                                           |
| **Permissions granted** | `presentations:create` — create presentations. `presentations:read` — read the status of presentations it created  |
| **Session length**      | 7 days, then sign-in again                                                                                         |
| **Account binding**     | The connection is bound to the account that signed in. Switching accounts means reconnecting                       |
| **New accounts**        | An email with no Twistly account gets a Free one created automatically — on the first *generation*, not at sign-in |

Everything is billed to the email the user signed in with, so MCP generations draw on the **same plan and balance** as that person's generations in the add-in or on the web. Signing in with an email that already has a Twistly account picks up that account — plan, balance, and history included.

When a session expires or a permission is missing, the client receives an authorization challenge instead of an error and prompts the user to reconnect.

## The tools

| Tool                | Use when                                                  | Permission             |
| ------------------- | --------------------------------------------------------- | ---------------------- |
| `create_from_topic` | The user has a topic or idea — the AI writes the content  | `presentations:create` |
| `create_from_text`  | The user already has text and wants it turned into slides | `presentations:create` |
| `create_from_file`  | The user has a PDF / PPTX / DOCX / TXT to convert         | `presentations:create` |
| `get_job_status`    | Check status, fetch the download URL                      | `presentations:read`   |

Every `create_*` tool replies immediately with `{ job_id, status: "queued", created_at }`. The file URL is delivered by `get_job_status` once `status` becomes `completed`.

`get_job_status` also accepts `wait: true`, which polls internally for up to **25 seconds** (2s → 5s backoff) before answering. If the job hasn't finished by then it returns `processing` with an explicit "call again in a few seconds" message. Status is one of `queued`, `processing`, `completed`, `failed`.

### 1. `create_from_topic`

Generates a presentation from a short topic prompt.

| Field               | What it does                                                                                                                                                 | Required | Default                                                              |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | -------------------------------------------------------------------- |
| `topic`             | Subject of the presentation (1–450 chars)                                                                                                                    | Yes      | —                                                                    |
| `num_slides`        | Slide count (`-1` for auto, or `1`–`50`; `0` is invalid; Free-plan accounts get at most 7)                                                                   | No       | auto                                                                 |
| `language`          | Output language                                                                                                                                              | No       | auto-detect                                                          |
| `template`          | Design theme (see [Templates](#templates))                                                                                                                   | No       | `auto` — Twistly picks the best-matching template your plan includes |
| `format`            | `pptx` \| `pdf`                                                                                                                                              | No       | `pptx`                                                               |
| `image_source`      | `unsplash` \| `pexels` \| `scrapingdog` \| `flux`                                                                                                            | No       | `flux`                                                               |
| `image_style`       | `auto` \| `photorealistic` \| `illustration` \| `neon` \| `abstract` \| `black-and-white` \| `3d` \| `linear` *(applies only when `image_source` is `flux`)* | No       | —                                                                    |
| `content`           | Text verbosity: `short` \| `detailed` \| `bulletPoints`                                                                                                      | No       | `detailed`                                                           |
| `presentation_type` | `General` \| `Educational Project` \| `Business Pitch` \| `Reports and Insights`                                                                             | No       | —                                                                    |
| `target_audience`   | Free text, ≤ 200 chars                                                                                                                                       | No       | —                                                                    |
| `tone_and_style`    | Free text, ≤ 200 chars                                                                                                                                       | No       | —                                                                    |

Example — the user asks for "a 5-slide illustrated digital-marketing pitch for marketing managers with upbeat bullet points", and the client sends:

```json
{
  "topic": "Digital Marketing Strategy",
  "num_slides": 5,
  "image_source": "flux",
  "image_style": "illustration",
  "content": "bulletPoints",
  "presentation_type": "Business Pitch",
  "target_audience": "Marketing managers",
  "tone_and_style": "Enthusiastic"
}
```

### 2. `create_from_text`

Turns text the user supplies in the MCP client into slides.

| Field                 | What it does                                                               | Required | Default                                                              |
| --------------------- | -------------------------------------------------------------------------- | -------- | -------------------------------------------------------------------- |
| `text`                | Source text (1–2,000,000 chars at this layer)                              | Yes      | —                                                                    |
| `num_slides`          | Slide count (`-1` for auto, or `1`–`50`; Free-plan accounts get at most 7) | No       | auto                                                                 |
| `language`            | Output language                                                            | No       | auto-detect                                                          |
| `template`            | Design theme                                                               | No       | `auto` — Twistly picks the best-matching template your plan includes |
| `format`              | `pptx` \| `pdf`                                                            | No       | `pptx`                                                               |
| `content_modificator` | `preserve` \| `expand` \| `condense`                                       | No       | `expand`                                                             |
| `text_density`        | `minimal` \| `concise` \| `detailed`                                       | No       | `concise`                                                            |
| `verbosity`           | `short` \| `detailed` \| `bulletPoints`                                    | No       | —                                                                    |
| `image_source`        | `unsplash` \| `pexels` \| `scrapingdog` \| `flux`                          | No       | `flux`                                                               |
| `image_style`         | See `image_style` values above *(only with `flux`)*                        | No       | —                                                                    |

The 2,000,000-character ceiling is only this layer's input guard. The real limit is the backend's **665,000-token** budget (≈ 500,000 words) — longer input returns `input_too_large`.

### 3. `create_from_file`

Converts an uploaded document into slides. The file arrives one of three ways, and **exactly one** must be used.

| Field                 | What it does                                                                                                                                                                                                  | Required     | Default                                                              |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | -------------------------------------------------------------------- |
| `file`                | **Preferred.** The file the user attached in the MCP client. The client passes a reference (`download_url`, `file_id`, `mime_type`, `file_name`) and the server fetches the bytes itself, so large files work | one of three | —                                                                    |
| `file_base64`         | Inline bytes for small files. Requires `mime_type`                                                                                                                                                            | one of three | —                                                                    |
| `file_url`            | An `https` URL the server downloads. Requires `mime_type`                                                                                                                                                     | one of three | —                                                                    |
| `filename`            | Name to use for the upload, ≤ 255 chars                                                                                                                                                                       | No           | derived                                                              |
| `mime_type`           | Declared type — required with `file_base64` / `file_url`                                                                                                                                                      | conditional  | —                                                                    |
| `num_slides`          | Slide count (`-1`, or `1`–`50`; Free-plan accounts get at most 7)                                                                                                                                             | No           | auto                                                                 |
| `language`            | Output language                                                                                                                                                                                               | No           | auto-detect                                                          |
| `template`            | Design theme                                                                                                                                                                                                  | No           | `auto` — Twistly picks the best-matching template your plan includes |
| `format`              | `pptx` \| `pdf`                                                                                                                                                                                               | No           | `pptx`                                                               |
| `content_modificator` | `preserve` \| `expand` \| `condense`                                                                                                                                                                          | No           | `expand`                                                             |
| `text_density`        | `minimal` \| `concise` \| `detailed`                                                                                                                                                                          | No           | `concise`                                                            |
| `verbosity`           | `short` \| `detailed` \| `bulletPoints`                                                                                                                                                                       | No           | —                                                                    |
| `image_source`        | as above                                                                                                                                                                                                      | No           | `flux`                                                               |
| `image_style`         | as above                                                                                                                                                                                                      | No           | —                                                                    |

**Accepted file types** (validated by content, not just extension — extension spoofing is rejected):

* PDF (`application/pdf`)
* PowerPoint (`application/vnd.openxmlformats-officedocument.presentationml.presentation`)
* Word (`application/vnd.openxmlformats-officedocument.wordprocessingml.document`)
* Plain text (`text/plain`)

With `file_base64` or `file_url`, the detected type must match the declared `mime_type` — otherwise the call fails with `unsupported_file_type`.

{% hint style="info" %}
**Attach files through the MCP client whenever possible.** Attachments and URL files support up to **100 MB** because the server downloads them directly; inline base64 is limited to **25 MB**.
{% endhint %}

### 4. `get_job_status`

Owner-scoped: a job is visible only to the account that created it.

| Field    | What it does                                    | Required | Default |
| -------- | ----------------------------------------------- | -------- | ------- |
| `job_id` | The id returned by a `create_*` tool (UUID)     | Yes      | —       |
| `wait`   | Poll internally for up to 25 s before answering | No       | `false` |

Response shape:

```
{
  "job_id": "uuid",
  "status": "queued" | "processing" | "completed" | "failed",
  "created_at": "ISO-8601",
  "completed_at": "ISO-8601",   // only when status ∈ {completed, failed}
  "result": {                   // only when status = completed
    "url": "https://...",
    "export_url": "https://..." // only when the backend returns one
  },
  "error": {                    // only when status = failed
    "code": "UPSTREAM_FAILURE",
    "message": "human-readable reason"
  },
  "message": "…"                // only while queued / processing
}
```

## Responses and errors

A `create_*` tool returns the job descriptor; the download URL appears in `result.url` once `get_job_status` reports `completed`.

Every failure carries a user-facing message, a machine-readable code, and whether it is retryable. `rate_limited` can additionally carry `retry_after`, and upstream failures can carry a `request_id` for support.

| Code                     | Meaning                                                                                                   | Retryable |
| ------------------------ | --------------------------------------------------------------------------------------------------------- | --------- |
| `invalid_input`          | A parameter failed validation, or the request was rejected upstream                                       | No        |
| `input_too_large`        | Source content exceeded the backend's token budget                                                        | No        |
| `file_too_large`         | Inline base64 file over 25 MB — attach it or use `file_url` instead                                       | No        |
| `unsupported_file_type`  | Not a PDF/PPTX/DOCX/TXT, or content doesn't match the declared `mime_type`                                | No        |
| `credits_exhausted`      | Out of AI credits — upgrade the plan                                                                      | No        |
| `template_not_available` | A Free-plan account named a template its plan doesn't include. The message lists the templates it can use | No        |
| `job_not_found`          | No job with that id for this account                                                                      | No        |
| `rate_limited`           | Too many requests. Carries `retry_after` when available                                                   | Yes       |
| `upstream_unavailable`   | The generation service is unreachable or returned an error                                                | Yes       |
| `service_misconfigured`  | Server-side auth problem between MCP and the backend                                                      | No        |
| `not_authenticated`      | The session carries no usable account email                                                               | No        |

**Authorization challenges** are returned as OAuth challenges rather than plain errors, which is what makes the MCP client prompt the user to reconnect: `invalid_token` (not connected, session expired, or the account email couldn't be resolved) and `insufficient_scope` (the connection lacks a permission a tool needs).

## Limits

| Limit                     | Value                                                                 |
| ------------------------- | --------------------------------------------------------------------- |
| Slides per presentation   | 1–50 (or `-1` for auto); Free plan: up to 7                           |
| `topic` length            | 450 characters                                                        |
| `text` length             | 2,000,000 characters at this layer; **665,000 tokens** at the backend |
| Inline `file_base64` size | 25 MB decoded                                                         |
| Attached / URL file size  | 100 MB                                                                |
| File download timeout     | 30 seconds                                                            |
| `wait: true` poll budget  | 25 seconds                                                            |
| Typical generation time   | 30–90 seconds                                                         |
| Sign-in session           | 7 days                                                                |
| Output formats            | `pptx`, `pdf`                                                         |

## Plans and billing

Which balance a generation is charged to depends on the plan — and, for Pro/Team, on whether the user ever issued an API key.

| Account                                    | Charged to                                                                      | Cost                                                |
| ------------------------------------------ | ------------------------------------------------------------------------------- | --------------------------------------------------- |
| Free / Starter                             | The account's AI-credit balance                                                 | **20 credits per generation** (any `create_*` tool) |
| Pro / Team **without** an API key          | A per-account daily quota                                                       | **100 generations per day** by default              |
| Pro / Team **with** an API key they issued | That key's daily limits — MCP usage shares the balance with their own API calls | per the key's limits                                |

An MCP connection **never creates an API key**. A Pro/Team user who has never issued one simply runs on the daily quota.

A brand-new account starts with **60 AI credits** — 3 generations before it needs an upgrade. When the balance is too low, the tool returns `credits_exhausted` with an upgrade link, and nothing is generated.

**Failed generations are refunded.** Credits and quota are reserved when the job is submitted and returned if it fails, so a crashed job costs nothing.

## Templates

Pass the exact id (case-sensitive, no spaces). There are 53 built-in themes:

`Tokyo`, `NewYork`, `Seoul`, `Rome`, `Berlin`, `Copenhagen`, `Oslo`, `Rotterdam`, `Cambridge`, `Houston`, `Pasadena`, `Lisbon`, `MexicoCity`, `Doha`, `Vienna`, `Edinburgh`, `Toronto`, `Melbourne`, `Boston`, `SantaFe`, `FlowerMound`, `Tallinn`, `Porto`, `Dubai`, `BuenosAires`, `Seattle`, `Zurich`, `Reykjavik`, `Helsinki`, `Nairobi`, `Dublin`, `Oxford`, `Brussels`, `LosAngeles`, `Florence`, `Havana`, `TelAviv`, `Portland`, `Milan`, `Madrid`, `Singapore`, `Stockholm`, `Geneva`, `Chicago`, `HongKong`, `Tashkent`, `SanFrancisco`, `Batumi`, `PalmSprings`, `Paris`, `Marrakech`, `Baltimore`, `Pittsburgh`

**On the Free plan**, an account can use `auto` or one of these 15 templates: `NewYork`, `Houston`, `Cambridge`, `Seoul`, `Rome`, `Copenhagen`, `Pasadena`, `Tokyo`, `Berlin`, `Oslo`, `FlowerMound`, `Singapore`, `Doha`, `PalmSprings`, `Brussels`. With `auto`, Twistly picks only from the templates the account's plan includes. Naming any other template from a Free account returns `template_not_available` — nothing is generated and no credits are used, and the message lists the templates the account can use and points to twistly.ai to upgrade. Starter, Pro and Team accounts can use every built-in template.

Custom user-uploaded templates are **not** available over MCP.

## What you get

Each generated presentation includes:

* A title slide with an image
* An outline of the main points
* Content slides with images and text
* Professional formatting
* A permanent download link, delivered in the chat
* A file ready to edit in PowerPoint or Google Slides

## Limitations

* **Generation only.** There are no tools for editing, restyling, or appending to an existing presentation.
* **No custom templates** — only the 53 built-in themes.
* **Free plan: 15 templates.** Other templates need a paid plan — see [Templates](#templates).
* **No layout controls.** Layout selection is entirely up to the generation pipeline.
* **`pptx` and `pdf` only.**
* **One account per connection.** Switching Twistly accounts means reconnecting the connector.
* **7-day sessions.** After that the user signs in again.
* Free/Starter users can run out of credits mid-conversation. The tool says so explicitly, but partial work isn't refunded.

## FAQ

**Does the user need an API key?** No — that's the point of MCP. They sign in with an email, and MCP never issues a key.

**What if they've never used Twistly before?** It still works. The first generation creates a Free account for that email automatically, with 60 AI credits — 3 generations. Nothing to sign up for beforehand.

**Does this work on a Free Twistly plan?** Yes. Connector availability depends on the MCP *client's* plan and capabilities, not the Twistly plan. On a Free plan, decks can use 15 of the built-in templates — see [Templates](#templates).

**If a user already has a Twistly subscription, does MCP see it?** Yes, as long as they sign in with the same email. Their plan, balance, and history are the same account.

**How long is the download link valid?** It's permanent — the file stays in storage and the URL keeps working.

**Can the user attach a 60 MB PDF?** Yes, as a client attachment — attachments and URL files support up to 100 MB. Inline base64 is capped at 25 MB.

**What if the user asks for 80 slides?** The tool rejects it — the maximum is 50.

**Does the MCP server see the conversation?** No. It receives only the tool calls the client's model makes, with their parameters.

**Which languages are supported?** Any. The AI auto-detects from the input, or the user can pin it with `language`.

**Are the images copyrighted?** Unsplash and Pexels images are stock — credit photographers when sharing publicly. `flux` images are AI-generated and free to use.

**Which MCP clients can connect?** Any client that supports Streamable HTTP and standard OAuth discovery. ChatGPT and Claude are supported client experiences.

## Support

If something fails:

1. Disconnect and reconnect Twistly in the MCP client — this covers expired sessions and half-finished sign-ins.
2. Check the error code the tool returned. `credits_exhausted` and `rate_limited` reflect account state, not bugs.
3. Confirm the signed-in email is the account you expect to be billed.
4. For anything server-side, [contact us](/help/contact-us.md) with the `job_id` — every generation is logged against it.

## Next steps

* Connect Twistly in your MCP client and generate a first deck.
* Try all three inputs — a topic, pasted text, and an attached PDF — they produce noticeably different decks from the same source material.
* Mix `template`, `image_source`, and `presentation_type` to tune the output for an audience.
