famistudio-mcp
Official# famistudio-mcp
**English** | [简体中文](README.zh-CN.md)
> **Model Context Protocol server for [FamiStudio](https://famistudio.org).**
> Generate, inspect, validate and render NES `.fms` projects from plain JSON — no
> GUI, no manual format wrangling.
```
compile_song_spec ──▶ create_fms ──▶ validate_fms ──▶ verify_roundtrip ──▶ export_audio
JSON notes .fms file invariants FamiStudio agrees .wav
```
FamiStudio's command line can *read* `.fms`, `.txt`, `.ftm` and `.nsf`, but it has no
`fms-export` command — writing the binary format is the only supported way to *produce*
a `.fms` from a script. `famistudio-mcp` does that the same way FamiStudio 4.5.x does,
validates every load invariant before writing, and proves the result by feeding it back
to FamiStudio.
---
## Quick start
Nothing to install — point your MCP host at the published package:
```jsonc
// Claude Desktop / Cursor / any MCP client that spawns a command
{
"mcpServers": {
"famistudio": {
"command": "npx",
"args": ["-y", "famistudio-mcp"],
// Optional fallback; see "Where generated files go" in docs/USAGE.md. If your client
// can prompt, you will be asked once and can pick a directory per project instead.
"env": { "FAMISTUDIO_MCP_OUTDIR": "/absolute/path/to/your/audio-work" }
}
}
}
```
Bun users can swap the command:
```jsonc
{ "command": "bunx", "args": ["famistudio-mcp"] }
```
Then ask your agent for what you want:
> Build me a 2-second snake-move blip: a bright Square1 arpeggio, a low Triangle pulse
> underneath, and a noise tick. Write it to `D:/Game Assets/snake_move.fms`, verify
> FamiStudio can load it, and render a 44100 Hz WAV next to it.
### Without an MCP host
The same engine ships as a CLI, which is handy for scripts and CI:
```bash
npx -y famistudio-mcp-cli info
npx -y famistudio-mcp-cli compile examples/snake-move.json -o out/snake.fms
npx -y famistudio-mcp-cli verify out/snake.fms
npx -y famistudio-mcp-cli export out/snake.fms out/snake.wav --rate 44100
npx -y famistudio-mcp-cli analyze out/snake.wav --pitch
```
### As a library
```bash
npm install famistudio-mcp
```
```ts
import { compileSongSpec, writeFms, readProject } from 'famistudio-mcp/core';
import { writeFile } from 'node:fs/promises';
const { project } = compileSongSpec({
name: 'Blip',
patternLength: 16,
channels: [
{ channel: 'Square1', notes: [{ time: 0, note: 'C4', duration: 8 }, { time: 8, note: 'stop' }] },
{ channel: 'Triangle', notes: [{ time: 0, note: 'C1', duration: 16 }] },
],
});
await writeFile('blip.fms', writeFms(project));
console.log(readProject(writeFms(project)).songs[0].name); // "Blip"
```
FamiStudio itself is only needed for rendering, text export and round-trip verification.
Generating, reading, validating and diffing projects works without it.
---
## Tools
| Tool | Purpose |
|---|---|
| `famistudio_info` | Locate the FamiStudio executable, report its version and the allowed read/write roots |
| `compute_ticks` | Convert between seconds, ticks and tempo |
| `compile_song_spec` | Compile a JSON song spec into a complete project object, optionally writing a `.fms` |
| `create_fms` | Same, but always writes a file |
| `validate_fms` | Check every FamiStudio load invariant and list the problems |
| `read_fms` | Decode a `.fms` into structured JSON (songs, channels, patterns, notes, envelopes) |
| `summarize_fms` | Human-readable listing of a project with per-pattern note dumps |
| `diff_fms` | Structural diff of two projects |
| `verify_roundtrip` | Round-trip through FamiStudio: text export + WAV render, checking for desync and silence |
| `export_audio` | Render WAV / MP3 / OGG via the FamiStudio CLI |
| `export_text` | FamiStudio text, FamiTracker text, or sound-engine assembly |
| `analyze_audio` | WAV duration, peak/RMS, silence and pitch detection |
| `run_famistudio` | Escape hatch for any other FamiStudio CLI command (NSF, ROM, ...) |
### Recommended flow
1. `compute_ticks` — decide the tick budget for the sound you want.
2. `compile_song_spec` — build the notes.
3. `create_fms` — write the file (or pass the returned `project` straight on).
4. `verify_roundtrip` — prove FamiStudio loads it and produces audio.
5. `export_audio` — render the `.wav` for your game.
6. `analyze_audio` — confirm duration and pitch, e.g. with `separateChannels`.
**The one thing to know before writing notes:** a tick is one frame of the console, so a
song's length is `ticks / 60.0988` seconds (NTSC) and its tempo follows from the tick grid
you write — `bpm = 60 * frameRate / beatLength`. `groove` and `noteLength` do **not** scale
playback. Everything else about the spec, including the full grammar and an effects table,
is in [`docs/USAGE.md`](docs/USAGE.md).
---
## Documentation
| Document | What is in it |
|---|---|
| **README.md** (this file) | What the project is, install, quick start, tool list |
| [`docs/USAGE.md`](docs/USAGE.md) | The full song-spec reference: note forms, effects, tempo, output location, configuration, editor/CLI options |
| [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md) | Build/test/verify commands and their gotchas, adding a tool, code style, path policy, desync debugging, **known limitations** |
| [`docs/FMS_FORMAT.md`](docs/FMS_FORMAT.md) | The `.fms` container and payload layout, and the timing model, as implemented |
| [`AGENTS.md`](AGENTS.md) | The compact entry point for coding agents: repository map, the format invariants, the change checklist |
| [`CONTRIBUTING.md`](CONTRIBUTING.md) | How to contribute |
| [`CHANGELOG.md`](CHANGELOG.md) | Release history |
Every document exists in English and Simplified Chinese (`X.md` / `X.zh-CN.md`), with a
switcher under the title going to the other language — except `AGENTS.md`, which is
agent-facing and deliberately English-only.
---
## Compatibility
- **Writes and reads** FamiStudio **4.5.x** project files: serialization version **19**.
- Reading older files (versions 10–18) is **not** supported; open and re-save them in
FamiStudio to upgrade them. Generation is unaffected.
- Plain **2A03 only** (no expansion audio: VRC6, FDS, N163, S5B, VRC7, EPSM). DPCM
samples in an existing project are preserved byte-for-byte but cannot be authored.
- The container uses `zlib` raw deflate by design, and a re-encoded container can differ
byte-for-byte from the original while the decompressed payload is identical.
---
## License
MIT — see [LICENSE](LICENSE).
FamiStudio itself is a separate project by Mathieu Gauthier-Pilote, licensed under the
MIT license; this server only reads and writes its file format and drives its command
line.
TDQS
Scored across 13 tools
Several tools sit close together: compile_song_spec vs create_fms, validate_fms vs verify_roundtrip, read_fms vs summarize_fms, and export_audio vs analyze_audio. The descriptions do clearly separate in-memory creation from file writing, invariant checks from end-to-end verification, and structured decoding from human-readable review, but an agent must read them carefully to avoid misselection.
Most tools follow a clean verb_noun snake_case pattern such as compile_song_spec, validate_fms, and export_audio, with the repeated _fms suffix forming a recognizable family. The main deviations are famistudio_info, which is noun-style, and run_famistudio, which uses the application name as the object.
Thirteen tools is a well-scoped size for a specialized FamiStudio server, and each tool maps to a distinct part of the create-validate-export-review workflow. None feel redundant or extraneous.
The server covers the full core loop: environment info, tempo arithmetic, spec compilation, file writing, validation, round-trip verification, reading, summarizing, diffing, audio analysis, and audio/text export. A minor gap is the lack of a direct update/modify path for an existing project from structured JSON, though run_famistudio acts as an escape hatch for uncovered CLI operations.