Manual · Part I · The engine
MCP and agents: putting the engine in the loop
What the Model Context Protocol server is, how its five tools map to the REST calls, why the agent has to be told to use them, what the hosted endpoint costs in milliseconds, and how a second server turns the harmony into sound.
Updated Oct 2, 2026
A language model is a good bandleader and a poor copyist. It knows what the harmony should do and cannot be trusted to spell the chord. The Model Context Protocol, MCP from here on, puts THIRI within the model’s reach: the model keeps the intent, the engine supplies the notes.
What the server is
MCP is the standard way to hand a tool to an AI client. The client lists the tools a server offers; the model picks one, sends arguments as JSON, JavaScript Object Notation, and reads JSON back.
THIRI’s server runs two ways.
Local. The npm package @bluesprincemedia/thiri-mcp speaks MCP over standard input and output. Claude Desktop, Claude Code and Cursor start it for you with npx. Your key never leaves your machine except as a bearer token to chords.thiri.ai. The shortest wiring is one line in Claude Code:
claude mcp add thiri --env THIRI_API_KEY=YOUR_KEY -- npx -y @bluesprincemedia/thiri-mcp
Hosted. For clients that cannot run a local process, such as Claude on the web and on mobile, the endpoint is https://mcp.thiri.ai/mcp. Add it as a custom connector with your key. It is JSON-RPC over HTTP, so only POST answers: a plain GET on the host returns 404 and a GET on /mcp returns 405. Listing the tools needs no key, checked today. Calling one spends the same quota the REST key has.
The registry has version 0.5.3, published 9 August 2026 under the PolyForm Noncommercial 1.0.0 licence, with three executables: thiri-mcp, thiri-conductor-mcp and thiri-composition-mcp. The hosted server introduces itself as “THIRI Chord Intelligence 0.4.0”, also checked today.
Five tools, five calls
The tools are the REST calls under other names. Arguments mirror the REST fields and the responses are the same JSON, so a golden file written against one surface checks the other.
| Tool | REST route | What it answers |
|---|---|---|
analyze_chord | POST /v2/analyze | What is this chord, and what is it doing in this key? |
resolve_chord | POST /v2/resolve | Which notes, MIDI numbers and frequencies? |
generate_voicing | POST /v2/voicing | How should an instrument play it after the last chord? |
reharmonize | POST /v2/reharmonize | What else could this progression be, and why? |
conduct_band | POST /v2/conduct | Turn a sentence into four lanes and a MIDI file. |
Fields are on the API page and the musician’s reading is in The five calls. One naming note: several June 2026 posts on this site call the fourth tool reharmonize_progression. The tool is reharmonize.
The model has to be told
A tool only helps if the model reaches for it. Left alone, a model asked to voice a C13 answers from memory, which is fluent where the arithmetic is not. The fix is a few lines of instruction, kept where the model reads them every time:
You have the THIRI tools. For any question that involves chords, keys,
scales, voicings, progressions or arrangements, call THIRI before answering
and base your answer on what it returns. Quote the notes THIRI gives you.
Do not spell chords from memory.
Put it in a system prompt, a Claude Project or a CLAUDE.md. In a chat the lightweight version is to begin the message with “Using THIRI,”. The failure it prevents is silent: a plausible wrong voicing looks right to anyone who does not play.
What the hosted server costs, measured
Six calls to each of two tools from a developer laptop, measured in September 2026: analyze_chord fastest 82.7 ms, median 106.1 ms; generate_voicing fastest 78.6 ms, median 105.0 ms. A figure of “under 40 ms” has circulated; it is plausibly server-side compute. A client sees about a tenth of a second. Scoring never notices; a live instrument cannot wait, which is why the plugin and the pedal compile the engine in rather than call it. Determinism is the claim. Speed is not.
The payload is richer than the note list. analyze_chord returns numeral, function, degree, diatonic and a scales array where each entry carries a character sentence. generate_voicing returns omitted, the tones it left out. From the same session:
analyze_chord chord "D7b9", key "Gm"
numeral "V7" function "dominant (harmonic minor)" degree 5 diatonic false
scales[0] name "dim_hw" character "Half-Whole. Symmetrical. b9 dominants."
generate_voicing chord "D7b9"
notes ["F#3","A3","C4","Eb4"] midi [54,57,60,63] omitted ["D"]
conduct_band takes a prompt and an optional durationSec. Asked for fifteen seconds it returned tempo 64, G minor, four bars, four lanes of note events, the lead sheet | Am7b5 | D13 | Gm9 | Gm9 | and a MIDI file in base64. It composes to a duration. It takes no cut list, and in a run on 1 October 2026 it ignored an explicit request for G Phrygian and returned a G major ii-V-I. Steer harmony with the other four tools; conduct_band makes a bed, not a chart.
Two traps. The hosted endpoint sits behind Cloudflare, which answers Python’s default urllib User-Agent with a 403; send an explicit User-Agent header. And the engine will not take a mode as a key: for B♭ Lydian pass keyContext F, the parent key, and name the chord you want.
Agents that show their reasoning
reharmonize is built for this. Each alternative carries a technique, the new progression, a changes list saying exactly which index moved from what to what, and a one-sentence explanation. For Gm7 C7 Fmaj7 in F the first alternative is tritone_sub, Gm7 Gb7 Fmaj7, explained as the dominant a tritone away sharing the guide tones with chromatic root motion into the target. The API page lists all eight techniques.
An agent that quotes these fields is one a musician can argue with. A decision log can read: D7♭9 at bar 8, V7, dominant function borrowed from harmonic minor, voiced F♯3 A3 C4 E♭4 with the root omitted because the bass covers it, scale half-whole diminished. Every musical fact in that sentence is engine output. Only the placement is the agent’s own, and it should say so.
One gap: Composer C, the Csound studio at composer.thiri.ai, fetches only generate_voicing for its songs and keeps the note list; the numeral, the function and the omitted tones arrive and go unused. Its score-to-picture module reads them, but that path runs in local mode only.
The dual-MCP Csound loop
The hosted server decides. It does not render. To hear it, run a second server beside it.
{
"mcpServers": {
"thiri": {
"command": "npx",
"args": ["-y", "@bluesprincemedia/thiri-mcp"],
"env": { "THIRI_API_KEY": "YOUR_KEY" }
},
"thiri-conductor": {
"command": "npx",
"args": ["-y", "-p", "@bluesprincemedia/thiri-mcp", "thiri-conductor-mcp"],
"env": { "THIRI_API_KEY": "YOUR_KEY" }
},
"thiri-composition": {
"command": "npx",
"args": ["-y", "-p", "@bluesprincemedia/thiri-mcp", "thiri-composition-mcp"]
}
}
}
This is the package README’s config with one change. The README omits -p. Whether npx then selects the companion bin from a package with three executables is unverified here, so the config above names the package with -p and the executable after it.
As of package 0.5.3, thiri-conductor-mcp offers four tools: conduct_band, render_audio, play_audio and search_corpus. render_audio posts a prompt or a prior conduct result to POST /v2/render, where Csound runs server-side, and can play the returned WAV locally. No Csound install is needed. thiri-composition-mcp offers ten tools over a composition intermediate representation behind POST /v2/compose, with a local play_composition preview through fluidsynth.
Here two sources disagree. The agent recipes page on this site, written in June 2026, still describes the companions as rendering Csound on your machine and says a local Csound install is required; the copy live at the time of writing also named the removed build_csound_score and render_csound_wav. The package changelog for 0.5.0, dated 23 July 2026, removed those tools and moved rendering behind the API; 0.5.3 renamed the corpus tool to search_corpus. Follow the changelog, the newer source.
The flagship loop is four prompts, pasted in order: analyse the progression with analyze_chord; arrange it with conduct_band; render it with render_audio; listen with play_audio, critique voice leading and register balance, and send one revision back through conduct_band. The API page marks /v2/render and /v2/compose as not yet stable for third parties; ask before building a product on them.
Composer C closes the loop in one process instead: its server holds the key, fetches voicings over the hosted MCP and renders with Csound 6.18. No second MCP, no key in the browser. The dual-MCP version runs tonight from a config file.
Still open
- The hosted server reports version 0.4.0 while the package is 0.5.3. Same five tools, two version lines.
conduct_bandtakes no cut list and ignores an explicit mode. Scored to picture worked around it with the other four tools.- The latency figures are six calls to each of two tools from one laptop, not a benchmark; measure from where your agent runs.
- Composer C’s song compiler ignores the reasoning payload it already receives.
Next
Chord vocabulary, spelling and the traps →
Which chord qualities the hosted API, the JavaScript engine and the C++ port agree on, how a symbol is parsed and spelled, what key accepts, and the one failure that is silent.