scratch-mcp
by jmeadlock
README.md
# scratch-mcp
An [MCP](https://modelcontextprotocol.io) server for **Assimilate SCRATCH / Live FX**, generated at startup from Assimilate's published [OpenAPI file](https://github.com/Assimilate-Inc/Assimilate-REST). No hand-written tools. Read-only by default.
This is the server we used in [Can an agent drive SCRATCH from the REST API alone?](https://al-engr.com/assimilate-scratch-testing.html) — the evaluation found that an agent given only the REST docs did as well as one given these generated tools, so the honest pitch for this repo is not "you need this." It is:
- **Scoping.** Today's SCRATCH REST server exposes reads, writes, deletes and shutdown on one flat surface, and in our tests the model reached for the destructive call first, every time. `readonly` and `safe` modes filter the surface before the agent ever sees it.
- **Convenience.** If your agent host speaks MCP and not raw HTTP, this is a 100-line way in.
## Quick start
Requires Python 3.11+ and a running SCRATCH / Live FX (9.9 b1205+) with the HTTP server enabled in *System Settings*.
```bash
git clone https://github.com/jmeadlock/scratch-mcp
cd scratch-mcp
python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
export ASSIM_BASE=http://localhost:8080/APIV2 # your SCRATCH host
python server.py --list # see what readonly exposes
python server.py # stdio MCP, readonly
```
### Modes
| Mode | Tools | What's in it |
|---|---:|---|
| `readonly` (default) | 48 | every `GET` |
| `safe` | 114 | everything except `DELETE`, `/application/shutdown`, `/application/restart`, `/application/render/deletemedia/*`, and writes to `/system` |
| `full` | 145 | the whole API, including deletes and shutdown |
```bash
python server.py --mode safe
python server.py --mode full --transport http --port 8765
```
Counts are from SCRATCH REST 1.1.0 / spec `info.version 1.0.5`. They'll change when the spec does.
### Claude Desktop / Hermes / other MCP hosts
stdio config, e.g. for Claude Desktop's `claude_desktop_config.json`:
```json
{
"mcpServers": {
"scratch": {
"command": "/path/to/scratch-mcp/.venv/bin/python",
"args": ["/path/to/scratch-mcp/server.py", "--mode", "readonly"],
"env": { "ASSIM_BASE": "http://192.168.1.50:8080/APIV2" }
}
}
}
```
### Environment
| Var | Default | Notes |
|---|---|---|
| `ASSIM_BASE` | `http://localhost:8080/APIV2` | REST base including `/APIV2` |
| `ASSIM_KEY` | *(empty)* | optional access key, sent as raw `Authorization: <key>` (Assimilate's convention, not `Bearer`) |
| `ASSIM_SPEC` | `spec/assimilate_rest_api.yaml` | point at a newer YAML without editing the repo |
A `.env` file next to `server.py` is read if present (never committed — see `.gitignore`).
## Things to know before you point an agent at it
**Parameter names come straight from the spec.** Tools want `slot_idx`, `shot_uuid`, `queue_uuid` — not `index` or `id`. In our eval the model guessed `index` eight times in a row and burned its call budget. If your agent host lets you add tool descriptions, that's the one hint worth adding.
**Two requests crashed SCRATCH b1211 (macOS) during testing:**
`POST /application/player/entershot/{…}` with an unsubstituted path template, and `POST /application/tools/lut` with a model-composed body. Both are in `full`/`safe` mode. Nothing here guards against them; use `readonly` if you can't afford a relaunch.
**`GET /application/render` can return `200` with an empty body.** The generated tool handles it, but the agent will see an empty result and may re-query.
**The spec is a snapshot.** `spec/assimilate_rest_api.yaml` is copied from Assimilate's repo (MIT, see `spec/LICENSE-Assimilate.txt`) at commit `3236f85` (2026-08-03). To track upstream, replace the file or set `ASSIM_SPEC`.
## How it works
`server.py` reads the YAML, overrides `servers[0].url` with `ASSIM_BASE`, builds an `httpx.AsyncClient`, and hands both to `FastMCP.from_openapi()` with a list of `RouteMap` rules for the chosen mode. That's it. Tool names are derived from `operationId`s (`get-construct-current-slots` → `get_construct_current_slots`).
## License
MIT — see `LICENSE`. The bundled OpenAPI file is © Assimilate Inc, MIT, license preserved alongside it.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues