lilypond-mcp
Engrave LilyPond music sources into cropped, placeable assets (PDF, EPS, SVG, PNG) entirely locally via a bundled WebAssembly engine.
engrave_file — engrave a
.lysource file into publication-quality notation assets; defaults to cropped PDF (InDesign-ready with all PDF boxes defined) plus an inline preview PNG.engrave_code — engrave LilyPond code inline without touching disk, ideal for iterating on a musical idea (defaults to PNG).
lilypond_version — report the LilyPond version the server engraves with, for choosing the right
\versionheader.Choose output formats (
pdf/eps/svg/png), toggle crop to size to the music, and set output_dir.Resolve shared
\includelibraries via include_dirs.Get inline preview PNGs to see the result without reading files (disable for batch runs).
Receive LilyPond diagnostics with line numbers on failure so sources can be fixed and retried.
Works fully offline and privately (desktop extension bundles the engine; no telemetry).
Engraves GNU LilyPond music notation sources into cropped PDF, EPS, SVG, and PNG assets, including preview images and diagnostics for iterating on scores.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@lilypond-mcpEngrave melody.ly to cropped SVG and PNG"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
lilypond-mcp
MCP server that engraves GNU LilyPond sources into placeable assets: cropped PDF, EPS, SVG, and PNG, sized to the music rather than a full page — ready to drop into page-layout software such as InDesign.
Nothing to install beyond Node: the server fetches a WebAssembly build of LilyPond on first use and engraves with that — the same engine on every machine.
Quick start
Claude Code — .mcp.json in your project:
{
"mcpServers": {
"lilypond": {
"command": "npx",
"args": ["-y", "lilypond-mcp@latest"]
}
}
}Claude Desktop — claude_desktop_config.json, same entry under
mcpServers. Or skip the config entirely: grab the .mcpb file from
the latest release
and open it with Claude Desktop — a desktop extension with the engine
bundled in, so it works offline from the first engrave.
That's the whole setup. On the first engrave, the server downloads the
engine (~35 MB, checksum-verified, cached under
~/.cache/lilypond-mcp — safe to delete at any time).
Related MCP server: inkscape-mcp
Tools
engrave_file— engrave a.lyfile. Defaults to cropped PDF — the format to place in InDesign (fonts embedded and subsetted, all PDF boxes defined). Also returns a preview PNG, both as a file and inline as an image in the tool result, so the agent sees what it engraved.engrave_code— engrave LilyPond code passed inline, for iterating on a musical idea without touching disk.lilypond_version— the LilyPond version the server engraves with, for picking the right\versionheader.
Both engrave tools accept formats (pdf/eps/svg/png), crop,
include_dirs (for shared \include libraries), output_dir, and
preview (default on; turn off to skip the inline image on batch runs). Paths
are resolved against the working directory the server is launched in — for
an .mcp.json entry, that is the project root. On failure the result
carries LilyPond's diagnostics, line numbers included, so an agent can fix
the source and retry.
What you get
This snippet, sent to engrave_code:
\version "2.26.0"
\header { tagline = ##f }
\score {
<<
\new ChordNames \chordmode { g2. | c | d | g }
\new Staff \new Voice = "m" \relative c'' {
\key g \major
\time 3/4
\tempo "Waltz" 4 = 132
g4 b d | e4.( d8) c4 | a4 fis d | g2 r4 \bar "|."
}
\new Lyrics \lyricsto "m" { Round and round the waltz goes, old and slow. }
>>
\layout { indent = 0 }
}comes back cropped to the music, as PDF, EPS, SVG or PNG — this is the SVG:
(Source in docs/example.ly.)
Engine
Engraving runs a WebAssembly build of LilyPond from
lilypond-wasi releases,
pinned in engine.json and executed in a child Node process via
node:wasi. Node 22 or newer: the engine uses WebAssembly exception
handling that V8 first shipped in Node 22. (The node:wasi fast-call
regression in Node 22.21.1+ —
nodejs/node#59600 — is
sidestepped automatically with --no-turbo-fast-api-calls.)
The engine trails lilypond-wasi's stable releases: a weekly workflow
re-pins engine.json to the newest release, engraves with it as a real
consumer, and opens a PR.
Development
npm install
npm run build # tsc → dist/
npm test # engraves real snippets with the wasm engine** The tests need an engine dir and skip without one. Either download the
pinned release into the cache — node scripts/assemble-engine-dir.mjs
prints the dir — or build one from a lilypond-wasi checkout:
./test/assemble-engine-dir.sh /tmp/engine-dir ../lilypond-wasi stable.
Then LILYPOND_MCP_ENGINE_DIR=<dir> npm test.
Releases: conventional commits → Knope bot release PR → merge → npm publish via OIDC trusted publishing (no tokens).
Privacy Policy
Everything happens on your machine. LilyPond sources are engraved locally by the bundled WebAssembly engine; neither your sources nor the generated assets ever leave your computer, and the server collects no data — no telemetry, no analytics, no accounts.
The npm package makes exactly one kind of network request: downloading
the pinned engine release from GitHub on first use (verified against
checksums, cached under ~/.cache/lilypond-mcp). The desktop extension
(.mcpb) ships the engine inside the bundle and makes no network
requests at all.
Generated assets are written to the output_dir you choose and stay
under your control; the server retains nothing else. Questions:
wilfred@eastpole.nl or the
issue tracker.
Licence
MIT. The server runs a GPL-licensed engraver (the lilypond-wasi
WebAssembly build of GNU LilyPond) as a separate program, and the npm
package contains none of its bytes — see
LICENSING.md for the analysis and the design rules that keep that
boundary clean.
Available Tools
3 toolsengrave_codeEngrave LilyPond CodeAIdempotent
Engrave LilyPond code passed inline, without needing a source file on disk. Useful for iterating on a musical idea: engrave, read the preview PNG, adjust, repeat. For anything worth keeping, write a .ly file and use engrave_file instead.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | LilyPond source code, e.g. '\version "2.26.0" { c\' e\' g\' }' | |
| crop | No | Crop assets to the music itself (required for EPS) | |
| name | No | Basename for the generated assets | snippet |
| formats | No | Asset formats to generate; png is handy while iterating on a snippet | |
| preview | No | Attach the preview PNG to the result as an image, so the engraving is visible inline without reading a file. Turn off for batch runs. | |
| output_dir | No | Directory the generated assets are written to (created if missing) | build |
| include_dirs | No | Directories searched by \include, e.g. a shared settings library |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| errors | No | |
| outputs | Yes | |
| previewPng | No | Cropped PNG of the engraved music — read this file to inspect the result |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the safety profile (readOnlyHint false, idempotentHint true, destructiveHint false). The description adds useful behavioral context — that it engraves from an in-memory string, that a preview PNG comes back for iteration, and that it is not the persistence path. It does not itself state that assets are written to a directory, but the schema and annotations cover that.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core capability, then the iteration workflow, then the hand-off to the sibling. Zero filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and 100% parameter coverage, the description need not restate outputs. It supplies the workflow and sibling routing an agent needs to pick this tool correctly, and nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and every parameter (crop, name, formats, preview, output_dir, include_dirs) is documented in the schema, so the baseline is 3. The description echoes the preview workflow but adds no syntax or format semantics beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Engrave LilyPond code') and immediately differentiates scope: inline code with no source file on disk. This cleanly separates it from the sibling engrave_file, which requires a .ly file.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use ('iterating on a musical idea: engrave, read the preview PNG, adjust, repeat') and an explicit when-not-to + alternative ('For anything worth keeping, write a .ly file and use engrave_file instead'). This is textbook routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
engrave_fileEngrave LilyPond FileAIdempotent
Engrave a LilyPond (.ly) source file into publication-quality music notation assets. Cropped assets are sized to the music, ready to place in page-layout software. Use PDF for InDesign placement (fonts embedded the way Adobe accepts, crop/bleed/trim/art boxes all defined); SVG has glyphs as outlines for the web; EPS embeds fonts in a form Ghostscript accepts but InDesign ignores. On failure, errors carries the LilyPond diagnostics, including line numbers.
| Name | Required | Description | Default |
|---|---|---|---|
| crop | No | Crop assets to the music itself instead of a full page. Required for EPS; what you want for assets placed in a layout. | |
| name | No | Basename for the assets; defaults to the source filename without .ly | |
| source | Yes | Path to the .ly file, relative to the project root or absolute | |
| formats | No | Asset formats to generate. PDF is the format to place in InDesign (fonts embedded the way Adobe accepts, all PDF boxes defined); EPS embeds fonts in a form InDesign ignores. | |
| preview | No | Attach the preview PNG to the result as an image, so the engraving is visible inline without reading a file. Turn off for batch runs. | |
| output_dir | No | Directory the generated assets are written to (created if missing) | build |
| include_dirs | No | Directories searched by \include, e.g. a shared settings library |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| errors | No | LilyPond diagnostics when compilation fails |
| outputs | Yes | Absolute path per generated format |
| previewPng | No | Cropped PNG of the engraved music — read this file to inspect the result |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare non-read-only, idempotent, non-destructive, so the safety profile is covered. The description goes beyond them with failure behavior ('errors' carries LilyPond diagnostics including line numbers), crop semantics, and the preview PNG being attached inline — real behavioral context. It stops short of stating runtime cost or overwrite behavior of output_dir.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose, then format-selection rationale, then failure behavior — every sentence carries distinct information with no filler or repetition. Sized appropriately for a tool with multiple output formats and layout-software considerations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a 7-parameter schema fully described and an output schema present, the description supplies exactly the missing layer: format tradeoffs and error reporting. An agent has everything needed to invoke it correctly without opening the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3 and the schema already documents each parameter. The description still adds meaning not in the schema, notably that SVG glyphs are outlines for web use and the font-embedding distinction between PDF and EPS. It says nothing extra about name, output_dir, or include_dirs resolution beyond their schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a concrete verb and resource ('Engrave a LilyPond (.ly) source file') and states the output class ('publication-quality music notation assets'), which is far more specific than the title alone. The phrase 'source file' implicitly separates it from the sibling engrave_code, but the distinction is never made explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives strong, actionable guidance on which output format to choose and why (PDF for InDesign, SVG outlines for web, EPS for Ghostscript but not InDesign), plus the crop and preview conditions. It does not tell the agent when to prefer engrave_file over engrave_code or when to call lilypond_version, which is the one routing gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lilypond_versionLilyPond VersionARead-only
Report the LilyPond version this server engraves with. Use it to pick the right \version header for new .ly files.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| version | Yes | LilyPond version banner, e.g. 'GNU LilyPond 2.26.0 (running Guile 3.0)' |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already tells the agent this is a safe read, and an output schema exists, so return format is covered. The description still adds a genuinely useful behavioral fact: the reported version is the one the server actually engraves with, which is what makes the compatibility check valid.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, with the core identity of the tool front-loaded before the usage hint. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read tool with an output schema and a readOnly annotation, the description covers everything an agent needs: what is reported and why to call it. No gaps remain.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no parameter semantics to convey; the 4 baseline applies. Nothing in the description is needed to understand the (empty) input.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Report') and a precisely scoped resource ('the LilyPond version this server engraves with'), which is meaningfully narrower than just 'the LilyPond version'. It is inherently distinct from the engrave_* siblings, though it never names them explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use it to pick the right \version header for new .ly files' gives a concrete triggering situation for calling the tool. There are no competing alternatives to disambiguate against, so no explicit exclusion is needed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.2.1- Changed
engrave_code1 field changed- added
Input schema / properties / previewAdded value: +{ + "default": true, + "description": "Attach the preview PNG to the result as an image, so the engraving is visible inline without reading a file. Turn off for batch runs.", + "type": "boolean" +}
- Changed
engrave_file1 field changed- added
Input schema / properties / previewAdded value: +{ + "default": true, + "description": "Attach the preview PNG to the result as an image, so the engraving is visible inline without reading a file. Turn off for batch runs.", + "type": "boolean" +}
3 tool updates
v0.1.0- First observed
engrave_code - First observed
engrave_file - First observed
lilypond_version
TDQS
Scored across 3 tools
The three tools have clearly distinct purposes: engrave_file operates on a .ly path, engrave_code takes inline source, and lilypond_version reports the engine version. The descriptions explicitly contrast the two engrave tools, reducing any misselection risk.
engrave_file and engrave_code share a consistent verb_noun pattern, but lilypond_version breaks it with a noun_noun form. The deviation is minor and still readable as a cohesive set.
Three tools is a tight, focused scope appropriate for a single-purpose LilyPond engraver wrapper. It's on the lean side but each tool earns its place without redundancy.
Core workflow (engrave file, engrave inline, check version) is fully covered with no dead ends for typical use. A preview/validate-only or batch operation is absent, but agents can work around this via engrave_code plus engrave_file.
Maintenance
Related MCP Connectors
Generate and vectorize clean, editable SVG graphics from text, images, or both.
Render HTML, Markdown, or URLs to images, PDF, or branded artifacts; extract and watch pages.
- blinkpdfOAuthio.blinkpdf
Render Markdown and LLM output into accessible PDF/UA-1 PDFs. No headless Chromium.
Compliant PDFs (PDF/A-2A + PDF/UA-1) from markdown or a compact DSL - fast, no headless browser.
Related MCP Servers
- AlicenseAqualityDmaintenanceConverts diagrams (Mermaid, PlantUML, Graphviz, etc.) to SVG, PNG, PDF, or JPEG images using Kroki.io. Supports generating diagram URLs and downloading diagrams to local files.28 npm8MIT
- AlicenseBqualityBmaintenanceEnables headless and secure control of Inkscape for creating, inspecting, and resizing SVG documents, and exporting to PNG, PDF, and SVG with validation of size, pages, structure, and hashes.19MIT
- AlicenseAqualityCmaintenanceRenders diagram-as-code to PNG files on your disk, and also provides text-art previews and syntax validation, all locally without a browser or network.44 npmMIT
- AlicenseBqualityAmaintenanceEnables driving Inkscape headlessly from an MCP client, with verified SVG editing, rendering, optimization, and animation tools.23MIT