---
name: cutkit
description: Read, write and edit the teleprompter scripts in a person's CutKit library (the iPhone teleprompter app with voice following). Use when someone asks you to draft a video script they'll read on camera, put a script on their teleprompter or into CutKit, tighten or shorten a script for a set length, or list, update, pin or delete their CutKit scripts. Covers the CutKit MCP connector, the REST API at getcutkit.com and the cutkit-scripts CLI.
---

# CutKit

CutKit is an iPhone teleprompter. The script scrolls as the person speaks, then the app records the take and cuts retakes and filler words on the phone.

Every script lives in one library. You write to it, and the script shows up in the teleprompter the next time the app opens. It goes the other way too: edits made on the phone show up for you.

## Connect

Pick the first one that works where you run.

1. **MCP connector, by sign in.** Add `https://getcutkit.com/mcp` as a custom connector in Claude or ChatGPT. The person signs in with their CutKit account and presses Allow. There's no key to paste. In the app, Settings, Agent access, "Copy connector address" gives the same URL.
2. **MCP with an API key.** For clients that can't sign in. The person turns on the "Agent key" toggle in the app under Settings, Agent access, then taps "Copy key". Keys start with `ck_` and run 46 characters.
   ```bash
   claude mcp add --transport http cutkit https://getcutkit.com/mcp \
     --header "Authorization: Bearer ck_your_key"
   ```
3. **REST API.** `https://getcutkit.com/api/v1/` with `Authorization: Bearer ck_...`. Spec: https://getcutkit.com/openapi.json
4. **CLI.** `cutkit-scripts` is one Node file with no installs. It reads `CUTKIT_API_KEY`. Run `cutkit-scripts mcp` for a local stdio MCP server with the same tools.

You can't make a key for somebody else's library. If you have none, ask the person for theirs, or ask them to add the connector. Treat the key like a password: it opens their scripts and nothing else.

## Tools

The remote server, the CLI's `mcp` mode and the API all do the same things.

| MCP tool | Arguments | REST |
| --- | --- | --- |
| `list_scripts` | none | `GET /api/v1/scripts` |
| `get_script` | `id` or `title` (title matches without regard to case) | `GET /api/v1/scripts/{id}` |
| `create_script` | `body` (required), `title`, `pinned`, `labels`, `archived` | `POST /api/v1/scripts` |
| `update_script` | `id` (required), `title`, `body`, `pinned`, `labels` (replaces the list), `archived` | `PATCH /api/v1/scripts/{id}` |
| `delete_script` | `id` (required) | `DELETE /api/v1/scripts/{id}` |
| `list_labels` | none | `GET /api/v1/labels` |
| `rename_label` | `from`, `to` (merges onto an existing label) | `PATCH /api/v1/labels/{name}` |
| `delete_label` | `label` | `DELETE /api/v1/labels/{name}` |

- `list_scripts` gives ids, titles, word counts and pins, pinned first, then newest. Bodies are left out, so call `get_script` to read one.
- `update_script` changes only the fields you send. It needs the id, not the title, so look the id up first.
- With no title, the first line of the body becomes the title, cut at 80 characters.
- Limits: title 200 characters, on one line (line breaks fold into spaces). Body 200,000 characters. 2,000 scripts per library.
- An id is 8 to 64 letters, digits, dashes or underscores. The server makes a UUID when you don't pass one.

The REST API also has `PUT /api/v1/scripts/{id}`, `GET /api/v1/scripts?since=` for syncing, and key routes. They're all in [references/api.md](references/api.md).

## Write for the teleprompter

The person reads the body out loud while the phone listens. Voice following matches each word they say against the words on screen. So every word in the body should be a word they'll speak.

- **Only spoken words in the body.** No stage directions like `[pause]`, `(smile)` or `B-roll: desk shot`. The app expects the person to say "pause", waits for it, and the scroll stalls. Put notes like that in the chat, not the script.
- **Almost no markdown in the body.** Skip `**bold**`, links and tables. The app's editor has simple lists and headings: from version 0.1.2 the prompter skips a leading `# `, `- `, `* ` or `1. ` on each line. Older versions read `#` as the word "number", so `# Intro` waits for "number intro". Plain sentences are the safe default.
- **Short sentences.** One idea each, mostly 6 to 15 words. A long sentence on a phone screen wraps four times and the reader loses their place.
- **One paragraph per beat.** A blank line between paragraphs gives the reader a breath and a place to restart a take.
- **Write it the way they talk.** Contractions, plain words, their voice. Read it in your head at speaking pace; if you trip, they will too.
- **Numbers are fine.** `2026`, `4K`, `40%` and `$40` match "twenty twenty six", "four k", "forty percent" and "forty dollars". Spell a number out when the person says it a different way.
- **Timing.** The app estimates about 140 words a minute. A 60-second read is about 140 words, 30 seconds about 70. The API's `words` field is the same count the phone uses.
- **Title for the library.** Short and findable, like "Launch video intro". It isn't read on camera.

## Examples

**Create a script (MCP).**

```json
{
  "name": "create_script",
  "arguments": {
    "title": "Launch video intro",
    "body": "Hi, I'm Sam. Here is what we shipped this week."
  }
}
```

The answer names the new id: `Added "Launch video intro" (10 words), id 0b8f6c1e-.... It shows up on the phone the next time CutKit opens.`

**Create a script (REST).**

```bash
curl https://getcutkit.com/api/v1/scripts \
  -H "Authorization: Bearer $CUTKIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title": "Launch video intro", "body": "Hi, I'"'"'m Sam. Here is what we shipped."}'
```

Answers `201` with `{"script": {...}}`. Send your own `id` to make a retry safe: a second POST with the same id answers `409 already_exists` and adds no copy.

**List, then update by id.**

1. Call `list_scripts`. Each line reads `Launch video intro  [0b8f6c1e-...]  10 words  pinned`.
2. Call `get_script` with that `id` to read the body before you change it.
3. Call `update_script` with the `id` and only what changes:

```json
{ "name": "update_script", "arguments": { "id": "0b8f6c1e-4f5d-4c2a-9a57-6e1d3f0c2b91", "pinned": true } }
```

REST: `PATCH /api/v1/scripts/{id}` with `{"pinned": true}`.

**CLI.**

```bash
export CUTKIT_API_KEY=ck_your_key
cutkit-scripts list
cutkit-scripts push intro.md --title "Launch video intro"   # same title updates, never adds a copy
cutkit-scripts show "Launch video intro"
cutkit-scripts label "Launch video intro" Sales      # add a label; unlabel drops one
cutkit-scripts archive "Launch video intro"          # hide it, not delete
cutkit-scripts rename-label Sales "Sales calls"      # on every script at once
cutkit-scripts rm "Launch video intro"
cutkit-scripts list --json
```

**Draft a 60-second YouTube intro.** The person says: "Write me a one-minute intro for my video on cold brew at home and put it on my teleprompter."

1. Ask only what you can't guess: their name or channel, if it isn't in the chat.
2. Draft about 140 words: a hook, who they are, what the video covers, why stay.
3. Check it against the rules above. No `[cut to]`, nothing they won't say.
4. Call `create_script`:

```json
{
  "name": "create_script",
  "arguments": {
    "title": "Cold brew intro",
    "body": "You don't need a fancy machine to make great cold brew.\n\nI'm Maya, and I've made a batch every Sunday for three years. I've tried every trick on the internet. Most of them don't matter.\n\nIn this video, I'll show you the three things that do. The right grind. The right ratio. And how long to wait.\n\nGet those right and it's smooth and sweet. Get them wrong and it's bitter, or it tastes like brown water. I've made both, many times.\n\nBy the end, you'll have a jar in your fridge that tastes better than the coffee shop. And it'll cost you about a dollar a glass.\n\nAll you need is a jar, a strainer and some coffee you already like. No scale, no special filter.\n\nIf that sounds good, stick around. Let's make some cold brew."
  }
}
```

5. Tell the person the title and word count from the answer, and that it's on the phone the next time CutKit opens.

## Errors

The REST API answers `{"error": {"code", "message", "docs"}}`. An MCP tool answers `isError: true` with the message as text. The CLI with `--json` prints `{"error": {"code", "message"}}` and exits 1.

| Code | What to do |
| --- | --- |
| `missing_key`, `invalid_key` (401) | The key is missing or was rotated. Ask the person for the current one from Settings, Agent access. |
| `invalid_token` (401) | The sign in expired or was removed. Ask them to connect CutKit again. |
| `not_found` (404) | No live script with that id. Call `list_scripts` and use a current id. |
| `missing_body`, `missing_id`, `invalid_body`, `invalid_title`, `invalid_pinned`, `invalid_id`, `invalid_json` (400) | Fix the field named in the message and send again. |
| `title_too_long`, `body_too_long` (400) | Cut the title under 200 characters, or split the body into two scripts. |
| `already_exists` (409) | That id is taken. PATCH or PUT it instead. |
| `library_full` (409) | 2,000 live scripts. Ask the person which to delete. |
| `rate_limited` (429) | Only on key minting. Wait an hour. |
| `internal` (500) | Try once more, then tell the person. |

## Privacy

Scripts stay on the phone until the person turns on agent access or signs in to a CutKit account. From then on, their library is stored on getcutkit.com so agents can reach it. Turning the agent key off without an account deletes the online library and every script in it. The copies on the phone stay. Rotating the key stops the old one at once.

Don't read scripts you weren't asked about, and ask before you delete one.

## More

- Full endpoint reference: [references/api.md](references/api.md)
- Docs: https://getcutkit.com/docs/api
- OpenAPI 3.1 spec: https://getcutkit.com/openapi.json
- Contact: hello@getcutkit.com
