Claude Code

What the plugin gives Claude

An MCP server that validates and keeps scores and drives the Piano app, a skill that teaches the score format by example, and commands named after what people ask for. Every name on this page is read out of the plugin’s source when the page is built.

Install it

/plugin marketplace add alegauss/piano /plugin install piano@piano

Nothing else to configure: the server ships inside the plugin. The tools that play start the app if it is installed and not open, bring its window to the front if it is, and say where to get it if it is not installed.

The commands

Each is a sentence you would have typed anyway, with the tool calls worked out for you.

CommandWhat it does
/piano:compose <piece, e.g. "Twinkle Twinkle, beginner, right hand melody">Write a score for a named piece, check it, keep it and play it
/piano:level <beginner | intermediate | advanced>Set the Piano app to beginner, intermediate or advanced
/piano:play [e.g. "at half speed from bar 9"]Play what is open in the Piano app, optionally slower or from a bar
/piano:practise <passage and hands, e.g. "bars 17 to 20, left hand, from half speed">Practise a passage, graded, at a tempo that climbs

The tools

In three groups, each with the first sentence of its own description. Only these reach the app, over a loopback connection that needs the token the running app wrote.

Write and keep

validate_score Validate a score

Check a score against the piano score format and say what is wrong with it.

save_score Save a score into the library

Validate a score and keep it in the local library, where the app and the other tools can find it.

read_score Read a score back

Return a score from the library as JSON, by the id it was saved under.

correct_score Correct what a score says about itself

Change what a library score says about itself — its title, composer, level, difficulty or tags — without touching its notes.

delete_score Delete a score from the library

Take a score out of the local library, by the id it is filed under.

list_scores List the library

Every score in the local library, with the id each one is addressed by and how long it lasts: easiest first, or newest first when asked.

search_scores Search the library

Scores in the library matching what you are looking for.

Play

play Play

Start the piano playing in the open window and say what is playing.

stop Stop

Stop the piano.

seek Go to a bar or a passage

Move the position to a bar number or to a named section of the score, without starting or stopping playback.

set_tempo Set the practice tempo

Play at a fraction of the written tempo: 0.5 is half speed, 1 is as written.

set_transpose Transpose

Move everything the app plays by a number of semitones, up or down, up to two octaves either way.

set_level Set the difficulty level

Choose beginner, intermediate or advanced.

piano_state What the piano is doing

What is open and what it is doing: the score, whether it is playing, where the position is, the tempo and the level.

Teach

practise Practise a passage

Repeat a passage, graded, at a tempo that climbs.
The skill

The loop it follows

  • ✓The piano-score skill shows the format by example and lists the numbers that are easy to get wrong: ticks per quarter, pitches, the length of a bar.
  • ✓validate_score answers field by field, and its warnings (the hands crossing, a chord one hand cannot span) are read and fixed where they are mistakes.
  • ✓Only a valid score is saved; save_score refuses one that is half right rather than keeping it.
  • ✓Then play, and on request practise for the passage you name.
Scope

What it refuses

The server is small on purpose. These are the things an agent with a piano might be expected to do, and does not.

✗ Copying a copyrighted piece

The compose command offers an original in that style instead.

✗ Writing a file you name

Scores go into the library, by id, and nowhere else.

✗ Running a command

The transport takes a closed set of requests and no code.

✗ Deleting without a way back

A deleted score goes to the system bin; with the app closed, a second call must say so.