# Kleo

**Category:** 💻 Developer Tools  
**Repository:** https://github.com/tonnooooo/kleo-mcp  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/kleo

## Description
Narrated 4K 60 fps films from a brief, realistic or animation, made from your assistant via MCP.

## Claude Desktop Quick Installation
Heuristic fallback — verify the package name and runner against the repository README before running it. Uses `npx` (confidence: low):

```json
"mcpServers": {
  "kleo": {
    "command": "npx",
    "args": ["-y","kleo"]
  }
}
```

## Documentation & README

# Kleo MCP server

Kleo is a remote [Model Context Protocol](https://modelcontextprotocol.io) server that renders YouTube videos and Shorts. A user connects one URL to Claude, ChatGPT, Grok, Claude Code, Cursor, VS Code, OpenCode or Gemini CLI, presses one button to get in (no email, no password, no invite code) and asks for a video in plain language. The render runs on a GPU machine rented for that job only (Vast.ai) with the Keou motion-design engine; the result comes back as signed download links (MP4, `.srt` subtitles, thumbnail) that last 7 days.

The server runs entirely on Cloudflare (Workers + KV + D1 + R2 + Workers AI + Cron), free plan. Production address: `https://mcp.kleooai.com/mcp` (Streamable HTTP, OAuth 2.1; the Worker itself answers at `https://kleo-mcp.plural-juice.workers.dev/mcp`). The public site (`../kleo-site`) reads that address from its `config.json`.

## Models

| Part of the film | Model |
|---|---|
| Moving footage (every shot of a film) | **ByteDance Seedance 2.5**, image-to-video from the shot's own frame |
| Frames and character sheets (from the user's own photos when they give some) | **Google Nano Banana Pro** |
| Picture check | a vision model compares every picture with the user's request before anything is filmed |
| Music (on request) | **Suno** |
| Narration | Kokoro voices, English or Italian |
| Finish | 4K 60 fps; optional AI upscale (Real-ESRGAN + RIFE) on the rendering GPU |

## Connect

| Where | How |
|---|---|
| Claude (web/desktop) | Settings → Connectors → Add custom connector → `https://mcp.kleooai.com/mcp` |
| Claude Code | `claude mcp add --transport http kleo https://mcp.kleooai.com/mcp` |
| ChatGPT | Settings → Connectors → Developer mode → Create → `https://mcp.kleooai.com/mcp`, OAuth |
| Cursor / VS Code / OpenCode / Gemini CLI | an `http` server named `kleo` with the same URL |
| MCP Registry | `com.kleooai/kleo` (see `server.json`) |

One button signs you in (no email, no password); 7 credits arrive with the account. Guides with screenshots: https://kleooai.com/connect/

## Tools

| Tool | What it does |
|---|---|
| `kleo_adapt_prompt` | Called first. Reads the request against Kleo's intake (subject, length, format, look; audience, tone, what must appear), answers with the questions the request leaves open, and once everything is known hands the assistant the producer's method for writing the treatment. |
| `kleo_list_templates` | The ten templates (format, length range, voices, credit cost) and the credits left on the account. |
| `kleo_storyboard_guide` | The storyboard format Kleo renders (styles, scene kinds, beats, icons, voices, rules) with examples, so the assistant can write an original storyboard. Optional: without one, Kleo plans the video from the prompt. |
| `kleo_create_video` | Queues a render from a template, a prompt and (optionally) a storyboard. Returns `job_id`, `eta_min` and the credits charged at once; nothing is charged on error. |
| `kleo_wait_for_video` | Waits (as long as the calling client allows: 45 s for ChatGPT/Grok, up to 5 min for OpenCode) and returns the links as soon as the video is ready, so the assistant keeps its spinner and delivers on its own. |
| `kleo_get_job` | State, current track, percent and minutes left; without `job_id`, the recent videos of the account. |
| `kleo_get_result` | Signed download links for a finished job. |
| `kleo_generate_thumbnail` | Not enabled yet in the beta (every render already includes a thumbnail): records the request and returns a notice. |
| `kleo_cancel_job` | Cancels a queued or running job and refunds the unused credits. |
| `kleo_account` | Credits left, the read-only link to the account page (`/credits`) and the "Kleo key" that carries the account to another browser. The link is safe to paste anywhere; the key is the account. |

Credits (`src/templates.ts`): 1 credit = 2 seconds of film, rounded up, 10 credits minimum; the film is made for accounts that bought a credit pack (€5 = 10 credits, €15 = 35, €40 = 100, one-off, no subscription). The animatic (the same storyboard with the camera moving over drawn frames, no generated clip, 15–60 s) costs 5 credits and is open to every account: the 7 credits that come with a new account pay for one. `tariffSentence()` is the sentence every page quotes. Accounts are anonymous: no email and no password, just an HMAC-signed handle (`src/accounts.ts`) kept in a cookie, which doubles as the pasteable "Kleo key". The D1 table `invites` survives only as an optional gift: a code typed into the collapsed field of the sign-in page adds credits on top of the free ones, and an unknown code never blocks anyone. Output: 2160×3840 for 9:16, 1920×1080 for 16:9, 60 fps, H.264 + AAC. A Short takes about 10–20 minutes including the machine boot; a long video takes proportionally longer, and the timeout a render is given follows the length it was quoted (`jobTimeoutMin`), never a flat number below it.

## How a job flows

```
client (Claude…) ──OAuth 2.1──▶ /mcp  (src/mcp.ts; login page in src/auth.ts)
                                │  D1: users, credits, gift codes, jobs, audit · KV: OAuth tokens · R2: rendered files
                                │  cron every minute (src/orchestrator.ts):
                                │    1. a storyboard for each queued job (Workers AI, src/storyboard.ts; validated by src/keou-contract.ts)
                                │    2. one Vast.ai instance per job (src/backends/vast.ts, image VAST_IMAGE)
                                │    3. watch running jobs, apply timeouts, purge expired files
                                ▼
                     Vast.ai instance → worker/kleo_worker.py (Keou engine) → uploads → POST /internal/jobs/:id/done → self-destroys
                     Free fallback: a GitHub Actions runner (.github/workflows/render-pool.yml) claims jobs that Vast could not start
                     (POST /internal/pool/claim with POOL_SECRET) and runs the same worker image.
```

Render backends (`RENDER_BACKEND`): `vast` (production: real GPUs, costs money), `mock` (simulated one-minute render with placeholder files, free; the server tells every client that renders are simulated), `pool` (only external runners), `manual` (a container you start by hand; used by `test/worker-e2e.mjs`).

## Worker image

`worker/Dockerfile.keou` builds `ghcr.io/tonnooooo/kleo-worker:keou` (about 11 GB: Keou engine, Chromium, Node, ffmpeg, Kokoro voices, faster-whisper). GitHub Actions (`.github/workflows/worker-image.yml`) builds and pushes it on every push to `main` that touches `worker/`, or by hand from the Actions tab. The package must stay public on ghcr.io so Vast.ai machines can pull it. Details: `worker/README-keou.md`.

## Local development

```bash
npm install
npm run db:migrate:local
npm run dev                # http://localhost:8787 with .dev.vars: simulated renders, no GPU, bundled storyboard (STORYBOARD_FIXTURE=example)
```

Connect Claude Code to the local server: `claude mcp add --transport http kleo-local http://localhost:8787/mcp`, then `/mcp` → Kleo → Authenticate and press the button; there is nothing to type.

## Tests

```bash
npm run test:smoke                                                  # starts its own wrangler dev on port 8799: OAuth, tools, queue, simulated render, signed download, cancel + refund
node --test test/keou-contract.test.mjs test/storyboard.test.mjs    # unit tests: storyboard validator and generator (offline, fake AI)
node --test test/accounts.test.mjs test/credits.test.mjs            # sign-in, signed handles, free credits, daily caps, credit lifecycle (offline, sqlite)
node test/worker-e2e.mjs                                            # real Keou render inside the container (podman, no GPU) against a local server in manual mode
node test/vast-e2e.mjs                                              # one real 20 s job on Vast.ai: costs a few cents, see the file header for the setup
npm run typecheck
```

## Deploy

Everything is provisioned: `npm run deploy` publishes `wrangler.jsonc` (every variable is explained there in a one-line comment). First-time setup, secrets and the step-by-step guide for the owner (Italian): `DEPLOY.md`. Secrets: `INTERNAL_SECRET`, `VAST_API_KEY` (set); `POOL_SECRET` (pool fallback); `RESEND_API_KEY` + `NOTIFY_FROM` (email notifications; not set, so `notify_email` is currently a no-op); `TURNSTILE_SECRET` (not set, so the bot check on the sign-in page is skipped). **`INTERNAL_SECRET` must never be rotated**: it signs the account handles as well as the download links, so a new value detaches every user from their credits.

To switch the GPUs off for a free demo, set `RENDER_BACKEND` to `mock` in `wrangler.jsonc` and deploy. To stop the spending right now, with no deploy: `POST /internal/admin/pause` with `Authorization: Bearer <INTERNAL_SECRET>` (`/internal/admin/resume` to start again). See DEPLOY.md section 5.

## Safety rails

Credits are debited when a job is queued and refunded on failure or cancellation; at most `MAX_JOBS_PER_USER` open jobs per account and `MAX_CONCURRENT_GPUS` instances in total; every job has a hard `JOB_TIMEOUT_MIN` after which the instance is destroyed, and a machine that stays silent for `START_TIMEOUT_MIN` after rental is destroyed and the job requeued; the worker carries its own watchdog and destroys its instance with Vast's restricted `CONTAINER_API_KEY`; after a "no credit / no offer" answer Vast is left alone for `VAST_RETRY_MIN`; download links are HMAC-signed and expire with the files; a prompt filter blocks forbidden content before any GPU money is spent.

Above all of those sits `DAILY_GPU_BUDGET_USD`: before renting anything, the orchestrator adds what today's rentals cost — finished, failed and cancelled alike, since `cost_usd` is written every time a machine is torn down — to what the paid machines running right now have already committed (each priced at `VAST_MAX_DPH` for its own timeout; free pool jobs commit nothing) and, over the ceiling, pauses rentals for an hour while the jobs keep their place in the queue. The figure is still an estimate: the price cap is an upper bound and the real number is the Vast.ai balance. New accounts are capped per day (`MAX_NEW_USERS_PER_DAY`) and per address per day (`MAX_NEW_USERS_PER_IP_DAY`, on a hash of the address), jobs per account per day (`MAX_JOBS_PER_DAY`, counting only the ones that were not refunded), and sign-in attempts per address per minute (the `SIGNUP_LIMIT` rate-limit binding, keyed on a hash of the address, never the address itself). Every limit runs inside the Worker and only on `/authorize`: never in front of `/mcp`, where a 403 or 429 breaks connectors before the application sees the request.

## Docs

- `DEPLOY.md` — current status, going live, day-to-day operations (Italian)
- `docs/MCP-GUIDA.md` — what MCP is, how each client connects, the seven tools (Italian)
- `docs/ARCHITETTURA.md` — the original feasibility analysis and architecture (Italian)

