PlayByKey Music Theory

com.playbykeyPublished by playbykey.comv1.6.0Updated Oct 24, 2026

Chords, scales, progressions, transposition, and MIDI tools for music theory AI agents.

VerifiedSTDIODesktop onlyMedia & Design

Overview

AI-generated overview

Gives an assistant deterministic music theory tools for chords, scales, modes, progressions, transposition, note spelling, and MIDI or frequency conversion.

What you can do
This local MCP server exposes the PlayByKey theory engine as callable tools instead of relying on the model's own music theory knowledge. Tools cover modes and their parent scales, key signatures, scale notes and degrees, intervals, note spelling and enharmonic labels, chord construction, diatonic chords, inversions, chord detection, catalog progressions, roman numerals, transposition, and MIDI number or frequency conversion. Results are resolved deterministically from fixed interval and scale-degree relationships.
When to use it
Useful when an assistant needs exact, repeatable answers about keys, scales, chords, or progressions rather than approximate ones, for example in music composition, practice, or teaching workflows. It is a good fit when you want note spelling, transposition, or MIDI and frequency values computed rather than guessed.
Requirements
Runs locally over stdio via npx, so Node.js is required; no global install is needed. No authentication, environment variables, or headers are declared. Configuration is added to the MCP settings of a desktop client such as Claude Desktop, Cursor, or Claude Code, followed by a restart.
Before you install
The server is read-only music theory computation: it does not write, send, or delete data, and it asks for no credentials or payments. The README notes that some tools require sharp-spelled input, so flat-spelled notes may need normalizing first, and key signature results use conventional enharmonic spelling rather than the exact spelling given.

Installation

In SourceWeft

  1. Open PlayByKey Music Theory in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

@playbykey/theory-mcp

An MCP server that exposes @playbykey/theory as AI-callable music theory tools.

MCP lets an AI assistant call the theory engine directly as tools instead of reasoning about scales, modes, and key relationships from training data. Music theory relationships, resolved deterministically through fixed interval and scale-degree relationships.

See the @playbykey/mcp page for the same setup instructions and full tool reference.

Installation

No global install needed - npx fetches and runs the package on demand. Requires Node.js (for npx).

Claude Desktop

Edit the MCP config file (claude_desktop_config.json) via Claude Desktop's settings.

json
{  "mcpServers": {    "theory": {      "command": "npx",      "args": ["-y", "@playbykey/theory-mcp"]    }  }}

Restart Claude Desktop after saving, then check its settings to confirm theory shows as connected.

Cursor

Config file location:

  • Global (all projects): ~/.cursor/mcp.json
  • Project only: .cursor/mcp.json in your project root
json
{  "mcpServers": {    "theory": {      "command": "npx",      "args": ["-y", "@playbykey/theory-mcp"]    }  }}

Restart Cursor after saving, then check its MCP settings to confirm theory shows as connected.

Claude Code

Project scope (recommended) - commit an .mcp.json at your repo root so the server is available to every contributor after git clone:

json
{  "mcpServers": {    "theory": {      "command": "npx",      "args": ["-y", "@playbykey/theory-mcp"]    }  }}

Local scope - register the server for yourself in this project only, without committing anything:

sh
claude mcp add theory npx -y @playbykey/theory-mcp

Global scope - register the server for yourself across every project on this machine:

sh
claude mcp add theory npx -y @playbykey/theory-mcp --scope user

Run claude mcp list to confirm theory shows as connected.

Tools

Modes

get_mode_notes - Returns the 7 notes of a diatonic mode.
Input: root (note), mode (mode name)
Example: get_mode_notes("D", "dorian") → D, E, F, G, A, B, C

get_parent_scale_modes - Returns all 7 modal rotations of the parent key.
Input: root (note), mode (mode name)
Example: get_parent_scale_modes("D", "dorian") → C ionian, D dorian, E phrygian, F lydian, G mixolydian, A aeolian, B locrian

get_modal_root - Returns the root note of a mode within a parent (major) key.
Input: parent_key (note), mode (mode name)
Example: get_modal_root("C", "dorian") → D

get_relative_minor - Returns the relative minor root for a major key.
Input: major_key (note)
Example: get_relative_minor("C") → A

get_relative_major - Returns the relative major root for a minor key.
Input: minor_key (note)
Example: get_relative_major("A") → C

get_mode_info - Returns display metadata for a mode: name, scale degree, and characteristic description.
Input: mode (mode name)
Example: get_mode_info("dorian") → Dorian, degree 2, "Minor with a raised 6th"

Circle of Fifths

get_circle_of_fifths - Returns all 12 chromatic notes in ascending-fifths order starting from C.
Input: none
Example → C, G, D, A, E, B, F#, C#, G#, D#, A#, F

Key Signatures

get_key_signature - Returns the sharp or flat count for a given key, treated as a major-key tonic (minor-key signatures are not exposed by this tool). Resolves to whichever enharmonic spelling is conventionally written - get_key_signature("A#") returns Bb major's 2 flats, not A#'s own. For the count of a root exactly as spelled, use get_spelled_accidental_count with get_root_letter.
Input: key (note)
Example: get_key_signature("D") → 2 sharps

Scales

get_scale_notes - Returns the notes of a scale by type.
Input: root (note), scale_type (one of: major, blues, pentatonic-major, pentatonic-minor, harmonic-minor, melodic-minor, chromatic)
Example: get_scale_notes("A", "blues") → A, C, D, D#, E, G

build_note_map - Returns structured per-note data: note name, scale degree (1-based), and semitone offset from root.
Input: root (note), scale_type
Example: build_note_map("C", "major") → [{note:"C", scaleDegree:1, semitoneOffset:0}, {note:"D", scaleDegree:2, semitoneOffset:2}, ...]

get_scale_degree - Returns the 1-based scale degree of a note within a scale, or null if the note is not in the scale.
Input: root (note), scale_type, note (note)
Example: get_scale_degree("C", "major", "E") → 3

is_note_in_scale - Returns whether a note belongs to a given scale.
Input: root (note), scale_type, note (note)
Example: is_note_in_scale("C", "major", "F#") → false

get_melodic_minor_notes - Returns the seven notes of the ascending melodic minor scale.
Input: root (note)
Example: get_melodic_minor_notes("C") → C, D, D#, F, G, A, B

get_melodic_minor_mode_notes - Returns the seven notes of a melodic minor mode.
Input: root (note), mode (one of: melodic-minor, dorian-b2, lydian-augmented, lydian-dominant, mixolydian-b6, locrian-nat2, altered)
Example: get_melodic_minor_mode_notes("C", "altered") → C, C#, D#, E, F#, G#, A#

get_harmonic_minor_mode_notes - Returns the seven notes of a harmonic minor mode.
Input: root (note), mode (one of: harmonic-minor, phrygian-dominant)
Example: get_harmonic_minor_mode_notes("C", "phrygian-dominant") → C, C#, E, F, G, G#, A#

get_bebop_scale_notes - Returns the eight notes of a bebop scale variant - a diatonic scale plus one chromatic passing tone.
Input: root (note), type (one of: bebop-dominant, bebop-major, bebop-dorian)
Example: get_bebop_scale_notes("C", "bebop-dominant") → C, D, E, F, G, A, A#, B

Intervals

resolve_interval - Returns the from-note and to-note for a named interval within a root context.
Input: root (note), interval (interval ID, e.g. major_3rd, perfect_5th)
Example: resolve_interval("C", "major_3rd") → C to E (4 semitones)

get_semitone_distance - Returns the ascending semitone distance between two notes (0-11).
Input: from (note), to (note)
Example: get_semitone_distance("C", "E") → 4

Note Spelling

get_sharps - Respells a list of notes to canonical sharp spelling. Most tools accept flat-spelled input directly, but get_flats and get_enharmonic_labels require sharp-spelled input - use this to normalize flat-spelled notes before calling those two.
Input: notes (sharp or flat)
Example: get_sharps(["Db", "C#", "D"]) → C#, C#, D

get_flats - Respells a list of sharp-spelled notes as flats. Natural notes are unaffected.
Input: notes (must be sharp-spelled)
Example: get_flats(["C#", "D"]) → Db, D

get_enharmonic_labels - Returns combined sharp/flat display labels for a list of sharp-spelled notes. Natural notes are unaffected.
Input: notes (must be sharp-spelled)
Example: get_enharmonic_labels(["C#", "D"]) → Db/C#, D

get_root_letter - Resolves which letter (A-G) a root should be spelled as under a sharp or flat preference. Feeds spell_diatonic_scale.
Input: root (note), preference (sharp or flat)
Example: get_root_letter("F#", "flat") → G

spell_diatonic_scale - Re-spells a 7-note diatonic scale so each of the 7 letters A-G is used exactly once, covering spellings a plain note can't represent alone (B#, E#, Cb, Fb, double-sharps, double-flats).
Input: notes (7 notes in scale order), root_letter (from get_root_letter)
Example: spell_diatonic_scale(["F#","G#","A#","B","C#","D#","F"], "F") → F#, G#, A#, B, C#, D#, E#

get_spelled_accidental_count - Returns the sharp or flat count for a 7-note diatonic scale's correct spelling, including how many are double accidentals. Works on a major or natural minor scale interchangeably - a key and its relative minor share the same count.
Input: notes (7 notes in scale order), root_letter (from get_root_letter)
Example: get_spelled_accidental_count(["A#","C","D","D#","F","G","A"], "A") → 7 sharps (3 double sharps)

Chords

get_chord_notes - Returns the notes of a chord given a root and chord type.
Input: root (note), chord_type (one of the 22 chord types, e.g. major-triad, dominant-7th, major-13th)
Example: get_chord_notes("C", "major-triad") → C, E, G

get_diatonic_chords - Returns the 7 diatonic triads for a key/mode, one per scale degree, in degree order.
Input: root (note), mode (mode name, optional - defaults to ionian)
Example: get_diatonic_chords("C", "ionian") → C major-triad, D minor-triad, E minor-triad, F major-triad, G major-triad, A minor-triad, B diminished-triad

get_chord_by_degree - Returns the diatonic chord at a specific scale degree (1-7) for a key/mode.
Input: degree (integer 1-7), root (note), mode (mode name, optional - defaults to ionian)
Example: get_chord_by_degree(5, "C", "ionian") → G major-triad

get_available_inversions - Returns the valid inversion numbers for a chord type, based on its note count.
Input: chord_type
Example: get_available_inversions("major-9th") → 0, 1, 2, 3, 4

get_chord_inversion - Reorders a chord's notes so the given inversion's chord tone is lowest.
Input: root (note), chord_type, inversion (integer, valid range depends on chord type)
Example: get_chord_inversion("C", "major-triad", 1) → E, G, C

detect_chords - Identifies every chord (root, type) match for a set of notes, keyed by root.
Input: notes (array of notes, any order)
Example: detect_chords(["E", "C", "G"]) → { C: [major-triad] }

Progressions

get_progression_in_key - Renders a named catalog progression as chords in a given key, in order.
Input: progression_id (one of I-V-vi-IV, ii-V-I, I-IV-V, vi-IV-I-V, 12-bar-blues, I-vi-IV-V, I-vi-ii-V), root (note)
Example: get_progression_in_key("I-V-vi-IV", "C") → C major-triad, G major-triad, A minor-triad, F major-triad

get_roman_numeral - Returns the roman numeral for a scale degree in a mode - case and suffix reflect diatonic triad quality.
Input: degree (integer 1-7), mode (mode name, optional - defaults to ionian)
Example: get_roman_numeral(7, "ionian") → vii°

Transposition

transpose - Transposes a set of notes from one key to another by the semitone distance between the two roots.
Input: notes (array of notes), from_root (note), to_root (note)
Example: transpose(["C", "E", "G"], "C", "D") → D, F#, A

MIDI & Frequency

note_to_midi - Returns the MIDI note number for a note at a given octave, using scientific pitch notation (C4 = middle C = MIDI 60).
Input: note (note), octave (integer)
Example: note_to_midi("C", 4) → 60

midi_to_note - Returns the note and octave for a given MIDI note number - the inverse of note_to_midi.
Input: midi_number (integer 0-127)
Example: midi_to_note(69) → A4

note_to_frequency - Returns the frequency in Hz for a note at a given octave, equal temperament, A4 = 440Hz.
Input: note (note), octave (integer)
Example: note_to_frequency("A", 4) → 440 Hz

License

MIT

Source: packages/theory-mcp/README.md at commit 0df6759

Tools

0
SourceWeft has not started this package in its sandbox yet, so its tools are not known.

Version history

1
  1. v1.6.0LatestSep 16, 2026

Score

50% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts

    Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.

  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listed15 pts

    Answer tools/list without a credential, or ship a package that starts in a sandbox without one.

  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts