@williamzujkowski/live-coding-music-mcp 4.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +202 -705
  2. package/dist/AudioAnalyzer.js +1294 -91
  3. package/dist/PatternStore.js +276 -23
  4. package/dist/StrudelController.js +388 -56
  5. package/dist/server/resources.js +27 -20
  6. package/dist/server/server.js +384 -76
  7. package/dist/server/tools/ai.js +124 -91
  8. package/dist/server/tools/analysis.js +168 -59
  9. package/dist/server/tools/capture.js +135 -24
  10. package/dist/server/tools/compose.js +26 -26
  11. package/dist/server/tools/diagnostics.js +20 -3
  12. package/dist/server/tools/editor.js +60 -6
  13. package/dist/server/tools/generate.js +38 -15
  14. package/dist/server/tools/history.js +30 -8
  15. package/dist/server/tools/playback.js +2 -1
  16. package/dist/server/tools/session.js +38 -6
  17. package/dist/server/tools/storage.js +179 -8
  18. package/dist/server/tools/transform.js +127 -43
  19. package/dist/server/tools/types.js +209 -14
  20. package/dist/services/AudioCaptureService.js +302 -33
  21. package/dist/services/AudioExportService.js +318 -0
  22. package/dist/services/BrowserOnlyFunctions.js +149 -0
  23. package/dist/services/EventDensityProbe.js +324 -0
  24. package/dist/services/GeminiService.js +221 -36
  25. package/dist/services/IsolatedEngineRunner.js +308 -0
  26. package/dist/services/IsolatedStrudelEngine.js +135 -0
  27. package/dist/services/LocalPatternEngine.js +16 -0
  28. package/dist/services/MIDIExportService.js +765 -71
  29. package/dist/services/MIDIImportService.js +474 -0
  30. package/dist/services/MusicTheory.js +85 -13
  31. package/dist/services/PatternGenerator.js +168 -85
  32. package/dist/services/PatternSandbox.js +359 -0
  33. package/dist/services/SessionManager.js +338 -65
  34. package/dist/services/StrudelEngine.js +218 -12
  35. package/dist/services/StrudelEngineHelpers.js +24 -8
  36. package/dist/services/StyleRegistry.js +204 -0
  37. package/dist/services/Transferable.js +114 -0
  38. package/dist/services/ai/AiTransport.js +56 -0
  39. package/dist/services/ai/AudioMeasurements.js +155 -0
  40. package/dist/services/ai/CliTransport.js +256 -0
  41. package/dist/services/engineChild.js +83 -0
  42. package/dist/services/engineChildPath.js +28 -0
  43. package/dist/utils/CategorisedError.js +59 -0
  44. package/dist/utils/ErrorRecovery.js +130 -110
  45. package/dist/utils/InputValidator.js +55 -7
  46. package/dist/utils/PatternValidator.js +136 -17
  47. package/dist/utils/SafePath.js +112 -0
  48. package/dist/utils/ServerConfig.js +248 -0
  49. package/dist/utils/TableLookup.js +41 -0
  50. package/dist/utils/Tempo.js +143 -0
  51. package/package.json +17 -5
  52. package/dist/services/__mocks__/StrudelEngine.js +0 -157
  53. package/dist/types/index.js +0 -1
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  >
5
5
  > **Unofficial fan project.** Not affiliated with, or endorsed by, the [Strudel project](https://codeberg.org/uzu/strudel). This adapter exists to make live-coding music accessible to beginners who want to try pattern-based music without learning the whole ecosystem first.
6
6
  >
7
- > **Status:** Beta | 86% statement coverage | Published to npm | Actively developed
7
+ > **Status:** Beta | 88% statement coverage | Published to npm | Actively developed
8
8
 
9
9
  <a href="https://glama.ai/mcp/servers/@williamzujkowski/live-coding-music-mcp">
10
10
  <img width="380" height="200" src="https://glama.ai/mcp/servers/@williamzujkowski/live-coding-music-mcp/badge" alt="live-coding-music-mcp server" />
@@ -13,12 +13,12 @@
13
13
  [![CI](https://github.com/williamzujkowski/live-coding-music-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/williamzujkowski/live-coding-music-mcp/actions)
14
14
  [![npm version](https://img.shields.io/npm/v/@williamzujkowski/live-coding-music-mcp.svg)](https://www.npmjs.com/package/@williamzujkowski/live-coding-music-mcp)
15
15
  [![Nerq Trust](https://nerq.ai/badge/live-coding-music-mcp)](https://nerq.ai/kya/live-coding-music-mcp)
16
- [![Tools](https://img.shields.io/badge/tools-26-green.svg)]()
16
+ [![Tools](https://img.shields.io/badge/tools-28-green.svg)]()
17
17
  [![License](https://img.shields.io/badge/license-AGPL--3.0--or--later-blue.svg)](LICENSE)
18
18
 
19
19
  A Model Context Protocol (MCP) server that drives [Strudel.cc](https://strudel.cc/) from Claude for AI-assisted live-coding music, pattern generation, and algorithmic composition.
20
20
 
21
- **Current State: Beta.** The core workflow (init → generate → write → play → analyze) works reliably with real audio output. 1771 tests pass, 86.76% statement coverage / 77.32% branch coverage. CI is hardened with OpenSSF Scorecard, SHA-pinned actions, CODEOWNERS, Dependabot, and lint as a blocking gate.
21
+ **Current State: Beta.** The core workflow (init → compose → playback → analyze) works reliably with real audio output. `npm test` reports ~3060 passing tests, <!-- COVERAGE:START -->88.99% statement coverage / 79.99% branch coverage<!-- COVERAGE:END -->. CI is hardened with OpenSSF Scorecard, SHA-pinned actions, CODEOWNERS, Dependabot, and lint as a blocking gate.
22
22
 
23
23
  **What "Beta" means here:**
24
24
  - Tool schemas are stable within minor versions; breaking changes require a major bump
@@ -30,8 +30,8 @@ A Model Context Protocol (MCP) server that drives [Strudel.cc](https://strudel.c
30
30
 
31
31
  - [Features](#features)
32
32
  - [Installation](#installation)
33
- - [Quick Reference](#quick-reference)
34
33
  - [Quick Start](#quick-start)
34
+ - [Quick Reference](#quick-reference)
35
35
  - [Available Tools](#available-tools)
36
36
  - [Usage Examples](#usage-examples)
37
37
  - [Architecture](#architecture)
@@ -44,39 +44,40 @@ A Model Context Protocol (MCP) server that drives [Strudel.cc](https://strudel.c
44
44
 
45
45
  ## Features
46
46
 
47
- ### 🎹 Music control
48
- - **84 MCP tools** covering pattern editing, playback, audio analysis, generation, history, sessions, and Gemini-backed assists. 26 are the canonical consolidated tools (`pattern_store`, `edit_pattern`, `transform`, `analyze`, `history`, `playback`, `effect`, `shape`, `audio_capture`, `browser_window`, `generate_part`, `generate_rhythm`, `music_theory`, `session`, `ai_assist`, ...); the rest are deprecated aliases kept for one release ([#178](https://github.com/williamzujkowski/live-coding-music-mcp/issues/178)).
47
+ ### Music control
48
+ - **28 MCP tools** covering pattern editing, playback, audio analysis, generation, history, sessions, MIDI import/export, and Gemini-backed assists. Each tool is enum-parameterized to keep the protocol surface small: `pattern_store({ action })`, `edit_pattern({ mode })`, `transform({ op })`, `analyze({ include })`, `history({ action })`, `playback({ action })`, `effect({ action })`, `shape({ dimension })`, `audio_capture({ action })`, `browser_window({ action })`, `generate_part({ role })`, `generate_rhythm({ type })`, `music_theory({ query })`, `session({ action })`, `ai_assist({ task })`, ... The 58 legacy single-verb aliases that forwarded to these were removed in v4.0.0 ([#178](https://github.com/williamzujkowski/live-coding-music-mcp/issues/178)).
49
49
  - **4 MCP resources** for catalog browsing without burning tool calls: `strudel://examples`, `strudel://patterns`, `strudel://styles`, `strudel://docs/tools`.
50
50
  - **Real browser automation** of Strudel.cc through Playwright.
51
51
  - **Multi-session support** — every browser-touching tool accepts an optional `session_id`; sessions have isolated browser pages, undo/redo/history stacks, and audio-capture services.
52
52
  - **Audio analysis** via Web Audio API (FFT spectrum, tempo detection, key detection, rhythm complexity).
53
53
  - **Template-based pattern generation** across 8 genres (techno, house, dnb, ambient, trap, jungle, jazz, experimental); optional Gemini-backed `ai_assist` for feedback, suggestions, and jamming.
54
- - **Music theory helpers**: 15+ scales, 8+ chord progression styles, euclidean and polyrhythm generation.
54
+ - **Music theory helpers**: 14 scales, 8 chord progression styles, euclidean and polyrhythm generation.
55
55
  - **Pattern persistence**: JSON-backed save/load with tags + the in-memory edit history (undo/redo/restore/compare).
56
56
  - **Result envelope** on every `tools/call`: clients branch on `{ ok, errorCategory, isRetryable }` instead of parsing free-text.
57
57
 
58
- ### 🔧 Testing & CI status
59
- - **1771 passing tests** across unit, integration, and example-validation suites.
60
- - **86.76% statement coverage / 77.32% branch coverage**.
61
- - **Lint blocking in CI**: 0 errors, ~163 warnings (mostly `any` in test mocks).
58
+ ### Testing & CI status
59
+ - **~3060 passing tests**: `npm test` runs ~3020 unit/integration/example tests in parallel, then 36 browser-validation tests serially against real Chromium. The coverage figure below is from the first tier, which is the one CI also runs — the browser tier adds ~0.2 points and CI does not execute it, so counting it would document coverage nothing verifies.
60
+ <!-- COVERAGE:START -->
61
+ - **88.99% statement coverage / 79.99% branch coverage** (90.5% functions, 89.75% lines), checked against `coverage/coverage-summary.json` by a drift guard.
62
+ <!-- COVERAGE:END -->
63
+ - **Lint blocking in CI**: 0 errors, ~195 warnings (mostly `any` in test mocks).
62
64
  - **OIDC trusted publishing** to npm with SLSA build provenance attestation on every release.
63
65
 
64
- **Not Production-Ready:** This is experimental software under active development. Use for exploration and experimentation. Expect breaking changes, bugs, and incomplete features. See [CONTRIBUTING.md](CONTRIBUTING.md) to help improve it.
66
+ **Not Production-Ready:** This is experimental software under active development. Use for exploration and experimentation. Expect breaking changes, bugs, and incomplete features. See [the Contributing section](#contributing) to help improve it.
65
67
 
66
- ### 🎼 Example patterns
68
+ ### Example patterns
67
69
 
68
- 18 example patterns ship in [`patterns/examples/`](patterns/examples/), grouped by genre:
70
+ 7 example patterns ship in [`patterns/examples/`](patterns/examples/), grouped by genre:
69
71
 
70
- - **Techno**: hard-techno, minimal-techno
71
- - **House**: deep-house, tech-house
72
- - **Drum & Bass**: liquid-dnb, neurofunk
73
- - **Ambient**: dark-ambient, drone
74
- - **Trap**: modern-trap, cloud-trap
75
- - **Jungle**: classic-jungle, ragga-jungle
76
- - **Jazz**: bebop, modal-jazz
77
- - **Longform** (multi-minute pieces): dark-ambient-journey, driving-techno, liquid-dnb-roller, nu-jazz-session
72
+ - **Ambient**: ambient-pad (70 BPM)
73
+ - **Dnb**: dnb-classic (174 BPM)
74
+ - **House**: house-classic (125 BPM)
75
+ - **Jazz**: jazz-ii-v-i (120 BPM)
76
+ - **Jungle**: amen-break (165 BPM)
77
+ - **Techno**: techno-driving (130 BPM)
78
+ - **Trap**: trap-modern (140 BPM)
78
79
 
79
- Each example is a JSON file with pattern code, BPM, key, and a description. See [`patterns/examples/README.md`](patterns/examples/README.md) for details. Agents can also list these via the `strudel://examples` MCP resource without making any tool calls.
80
+ Each example is a JSON file with pattern code, BPM, key, and a description, and each sets the tempo it declares (#367). See [`patterns/examples/README.md`](patterns/examples/README.md) for details. Agents can also list these via the `strudel://examples` MCP resource without making any tool calls.
80
81
 
81
82
  ## Migrating from `@williamzujkowski/strudel-mcp-server`
82
83
 
@@ -151,9 +152,86 @@ npx playwright install chromium
151
152
  npm run build
152
153
  ```
153
154
 
155
+ ## Quick Start
156
+
157
+ Get from install to your first generated pattern in under two minutes.
158
+
159
+ ### 1. Install
160
+
161
+ ```bash
162
+ npm install -g @williamzujkowski/live-coding-music-mcp
163
+ npx playwright install chromium # one-time
164
+ ```
165
+
166
+ Building from source instead? See [Installation → From Source](#from-source).
167
+
168
+ ### 2. Configure your MCP client
169
+
170
+ #### Claude Desktop
171
+
172
+ Edit your Claude Desktop config file:
173
+
174
+ | OS | Config path |
175
+ |---|---|
176
+ | macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
177
+ | Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
178
+ | Linux | `~/.config/Claude/claude_desktop_config.json` |
179
+
180
+ Add the server:
181
+
182
+ ```json
183
+ {
184
+ "mcpServers": {
185
+ "live-coding-music": {
186
+ "command": "live-coding-music-mcp"
187
+ }
188
+ }
189
+ }
190
+ ```
191
+
192
+ Restart Claude Desktop. The server appears under the 🔌 plug icon.
193
+
194
+ #### Claude Code (CLI)
195
+
196
+ ```bash
197
+ # If installed globally
198
+ claude mcp add strudel live-coding-music-mcp
199
+
200
+ # If built from source
201
+ claude mcp add strudel node /path/to/live-coding-music-mcp/dist/index.js
202
+ ```
203
+
204
+ ### 3. Verify the server responds
205
+
206
+ ```bash
207
+ # From a global install
208
+ echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | live-coding-music-mcp
209
+
210
+ # From source
211
+ npm run validate
212
+ ```
213
+
214
+ You should see a JSON response listing **28 tools**. If you see fewer, the build is out of date — run `npm run build`.
215
+
216
+ ### 4. Make your first sound
217
+
218
+ In Claude, ask:
219
+
220
+ > Initialize Strudel and compose a techno beat.
221
+
222
+ **What you'll see:** A Chromium window opens (visibly — this is the live editor, not a hidden process) and lands on strudel.cc. Claude calls `init`, then `compose({ style: "techno" })`. A 4-on-the-floor pattern appears in the CodeMirror editor and starts playing through your speakers.
223
+
224
+ Prefer headless mode (no browser window)? Set `"headless": true` in `config.json` before the first `init` call — see [Configuration](#configuration). Note that tempo detection currently reflects how often the agent polls rather than the audio itself (#322), in headed or headless mode alike.
225
+
226
+ ### 5. Where to go next
227
+
228
+ - [Quick Reference](#quick-reference) below: tool cheat sheet for common operations.
229
+ - [Usage Examples](#usage-examples): multi-step workflows (composition, audio analysis, AI-assisted jamming).
230
+ - [`patterns/examples/`](patterns/examples/): 18 ready-to-play patterns across 7 genres plus 4 longform pieces. Agents can browse them via the `strudel://examples` MCP resource without burning tool calls.
231
+
154
232
  ## Quick Reference
155
233
 
156
- Common commands for immediate use:
234
+ Common operations as one-line tool calls:
157
235
 
158
236
  | Action | Tool call |
159
237
  |---|---|
@@ -173,35 +251,14 @@ The legacy single-verb tools (`play`, `stop`, `save`, `undo`, `write`, `generate
173
251
 
174
252
  **One-shot workflow:**
175
253
  ```
176
- compose with style: "dnb", key: "Am", bpm: 174, auto_play: true
177
- ```
178
-
179
- ## Quick Start
180
-
181
- ### 1. Add to Claude
182
- ```bash
183
- # If installed globally
184
- claude mcp add strudel live-coding-music-mcp
185
-
186
- # If built from source
187
- claude mcp add strudel node /path/to/live-coding-music-mcp/dist/index.js
188
- ```
189
-
190
- ### 2. Start Using
191
- ```bash
192
- claude chat
254
+ compose with style: "dnb", key: "Am", tempo: 174, auto_play: true
193
255
  ```
194
256
 
195
- Then ask Claude:
196
- - "Initialize Strudel and create a techno beat"
197
- - "Generate a jazz chord progression in F major"
198
- - "Create a drum & bass pattern at 174 BPM"
199
-
200
257
  ## Available Tools
201
258
 
202
259
  <!-- TOOLS:START -->
203
260
 
204
- **26 tools** across 14 categories:
261
+ **28 tools** across 15 categories:
205
262
 
206
263
  <details><summary><strong>Setup</strong> (1)</summary>
207
264
 
@@ -215,7 +272,7 @@ Then ask Claude:
215
272
 
216
273
  | Tool | Description |
217
274
  |------|-------------|
218
- | `edit_pattern` | Mutate the current session pattern. |
275
+ | `edit_pattern` | Mutate the current session pattern. mode=write replaces the editor contents (default; mirrors the old write tool exactly, including optional pattern validation and auto_play). mode=append concatenates `code` after the current pattern with a newline. mode=insert places `code` at the given line `position`. mode=replace substitutes `search` with `replace` — the first occurrence only, unless replace_all is true. The response reports how many occurrences matched, were replaced, and remain. mode=clear empties the editor. Example: edit_pattern({ mode: "write", pattern: "s(\"bd\")", auto_play: true }). For reading the editor without mutating it use get_pattern; for the on-disk pattern catalog use pattern_store. |
219
276
  | `get_pattern` | Get current pattern code |
220
277
 
221
278
  </details>
@@ -224,16 +281,17 @@ Then ask Claude:
224
281
 
225
282
  | Tool | Description |
226
283
  |------|-------------|
227
- | `playback` | Control transport on the current session. |
228
- | `set_tempo` | Set BPM |
284
+ | `playback` | Control transport on the current session. action=play starts the editor pattern. action=pause halts the clock where it is, so play resumes mid-cycle. action=stop ends playback. Example: playback({ action: "play" }). For pattern editing use edit_pattern; for tempo use set_tempo. |
285
+ | `set_tempo` | Set BPM. Writes setcpm(bpm/4), assuming one bar of 4/4 per cycle. |
229
286
 
230
287
  </details>
231
288
 
232
- <details><summary><strong>Storage</strong> (1)</summary>
289
+ <details><summary><strong>Storage</strong> (2)</summary>
233
290
 
234
291
  | Tool | Description |
235
292
  |------|-------------|
236
- | `pattern_store` | Persist patterns to disk and read them back. |
293
+ | `pattern_store` | Persist patterns to disk and read them back. Use action=save to write the current session pattern under a name; action=load to restore a named pattern into the current session; action=list to enumerate the on-disk catalog (optionally filtered by tag). Example: pattern_store({ action: "save", name: "my-jam", tags: ["techno"] }). For session lifecycle (create/destroy/list active sessions) use the session tool — pattern_store deals with on-disk patterns, not runtime sessions. |
294
+ | `import_midi` | Convert a .mid file into a playable Strudel pattern (Phase 1: literal transcription, #201). Use source="base64" with data=<base64 string> for inline bytes, or source="path" with data=<basename> to read from the patterns/midi/ directory (path traversal blocked). Drum tracks (MIDI channel 10) emit one s() lane per sample so simultaneous kicks/hats do not collide. Pitched tracks emit note("...").s("piano") with simultaneous notes merged into [a,b,c] chord tokens. Phase 2+ (structural compression, voice separation, LLM idiomatic pass) tracked in separate issues. Example: import_midi({ source: "path", data: "drumloop.mid", steps_per_cycle: 16 }). For the reverse direction (Strudel → MIDI) use the export_midi tool. |
237
295
 
238
296
  </details>
239
297
 
@@ -241,7 +299,7 @@ Then ask Claude:
241
299
 
242
300
  | Tool | Description |
243
301
  |------|-------------|
244
- | `history` | Navigate or inspect the pattern edit history. |
302
+ | `history` | Navigate or inspect the pattern edit history. action=undo reverts the last edit on the targeted session. action=redo replays a previously-undone edit. action=list returns recent entries with timestamps and previews (limit defaults to 10). action=restore jumps the editor to a specific entry by id (current pattern goes on the undo stack). action=compare diffs two entries by id (or one entry vs current pattern). Example: history({ action: "list", limit: 5 }) — recent edits, newest first. For on-disk saved patterns use pattern_store — history deals with the in-memory edit timeline of the current session. |
245
303
 
246
304
  </details>
247
305
 
@@ -250,8 +308,8 @@ Then ask Claude:
250
308
  | Tool | Description |
251
309
  |------|-------------|
252
310
  | `compose` | Generate, write, and play a complete pattern in one step. Auto-initializes default browser if needed. |
253
- | `generate_part` | Generate a single instrumental layer and append it to the current session pattern. |
254
- | `generate_rhythm` | Generate a rhythmic pattern and append it to the current session. |
311
+ | `generate_part` | Generate a single instrumental layer and append it to the current session pattern. role=drums takes `style` (e.g. "techno"/"house") and optional `complexity` 0-1. role=bass takes `key` (e.g. "C") + `style`. role=melody takes `root`/`scale` (e.g. C/minor) and optional `length` (notes). role=fill takes `style` and optional `bars`. Example: generate_part({ role: "drums", style: "techno", complexity: 0.7 }). For full compositions use compose; for rhythmic patterns use generate_rhythm; for music-theory queries use music_theory. |
312
+ | `generate_rhythm` | Generate a rhythmic pattern and append it to the current session. type=euclidean produces a Euclidean rhythm with `hits` evenly distributed across `steps` (optional `sound` param, default "bd"). type=polyrhythm overlays multiple sound layers with given pattern numbers. Example: generate_rhythm({ type: "euclidean", hits: 3, steps: 8, sound: "hh" }). For complete patterns (drums/bass/melody) use generate_part; for whole compositions use compose. |
255
313
 
256
314
  </details>
257
315
 
@@ -259,7 +317,7 @@ Then ask Claude:
259
317
 
260
318
  | Tool | Description |
261
319
  |------|-------------|
262
- | `music_theory` | Music-theory queries. |
320
+ | `music_theory` | Music-theory queries. query=scale returns the notes of a scale (e.g. "C major scale: C, D, E, F, G, A, B"). query=chord_progression returns a chord progression for the key/style AND writes the resulting chord pattern into the current session. Example: music_theory({ query: "scale", root: "C", scale: "major" }). For pattern generation (drums/bass/melody) use generate_part; for rhythmic patterns use generate_rhythm. |
263
321
 
264
322
  </details>
265
323
 
@@ -267,9 +325,9 @@ Then ask Claude:
267
325
 
268
326
  | Tool | Description |
269
327
  |------|-------------|
270
- | `transform` | Apply a single transform op to the current session pattern. |
271
- | `effect` | Add or remove a Strudel effect on the current session pattern. |
272
- | `shape` | Shape the current pattern along one of three high-level dimensions. |
328
+ | `transform` | Apply a single transform op to the current session pattern. op=transpose shifts notes by `semitones`. op=reverse appends `.rev` to the pattern. op=stretch slows by `factor` (>1 slower, <1 faster). op=quantize snaps to the `grid` (e.g. "1/16"). op=humanize adds rand-nudge timing of `amount` (0-1). op=swing applies `.swing(amount)`. op=scale applies a `root`/`scale` filter to notes. op=vary returns a variation of `type` (subtle/moderate/extreme/glitch/evolving). Example: transform({ op: "transpose", semitones: 7 }). For effects (add/remove) use effect; for mood/energy/refine use shape; for tempo use set_tempo. |
329
+ | `effect` | Add or remove a Strudel effect on the current session pattern. action=add appends `.<effect>(<params>)`. action=remove strips EVERY `.<effect>(...)` call from the pattern, not just the last. Example: effect({ action: "add", effect: "lpf", params: "1000" }). For higher-level effect bundles (mood/energy/refine) use shape; for raw transforms use transform. |
330
+ | `shape` | Shape the current pattern along one of three high-level dimensions. dimension=mood applies a mood profile (dark/euphoric/melancholic/aggressive/dreamy/peaceful/energetic) with optional intensity 0-1. dimension=energy applies an energy level (integer 0-10). dimension=refine applies a directional refinement: faster/slower/louder/quieter/brighter/darker/"more reverb"/drier. All three auto-play by default. Example: shape({ dimension: "mood", target_mood: "dark", intensity: 0.8 }). For raw transform ops use transform; for explicit effects use effect. |
273
331
 
274
332
  </details>
275
333
 
@@ -277,7 +335,7 @@ Then ask Claude:
277
335
 
278
336
  | Tool | Description |
279
337
  |------|-------------|
280
- | `ai_assist` | Gemini-backed pattern assistance. |
338
+ | `ai_assist` | Gemini-backed pattern assistance. task=feedback returns creative critique on the current pattern (optionally with audio analysis). task=suggest analyzes the currently playing audio and suggests a complementary Strudel pattern as text (not auto-executed). task=jam generates a fresh layer (drums/bass/melody/pad/texture) and merges it into the current pattern, then auto-plays. All three share Gemini auth + rate limiting. Example: ai_assist({ task: "jam", layer: "bass" }). Needs GEMINI_API_KEY, or a logged-in claude/agy/codex CLI on PATH (#252). For non-AI pattern generation use generate_part; for full compositions use compose. |
281
339
 
282
340
  </details>
283
341
 
@@ -285,9 +343,9 @@ Then ask Claude:
285
343
 
286
344
  | Tool | Description |
287
345
  |------|-------------|
288
- | `analyze` | Audio analysis on the currently-playing pattern. |
346
+ | `analyze` | Audio analysis on the currently-playing pattern. include=["all"] (default) returns the full spectrum + features object, matching the pre-consolidation behaviour. include=["tempo"] returns only BPM with confidence. include=["key"] returns detected key + scale + confidence. include=["spectrum"] returns FFT features (bass, mid, treble, brightness, etc.). include=["rhythm"] returns rhythm-only analysis (complexity, density, syncopation). Combining values returns an object keyed by category, e.g. analyze({ include: ["tempo", "key"] }) → { tempo: {...}, key: {...} }. Example: analyze({ include: ["tempo"] }) to cheaply re-check BPM during a session. For static pattern analysis (no browser) use analyze_pattern_local; for runtime validation use validate_pattern_runtime. |
289
347
  | `validate_pattern_runtime` | Validate pattern with runtime error checking (monitors Strudel console for errors) |
290
- | `validate_pattern_local` | Validate pattern syntax against the in-process StrudelEngine (no browser required) |
348
+ | `validate_pattern_local` | Validate pattern syntax against the local StrudelEngine, which runs in a sandboxed child process (no browser required) |
291
349
  | `analyze_pattern_local` | Static analysis (events/cycle, complexity, optional BPM) without browser playback |
292
350
  | `query_pattern_events` | Enumerate events the pattern would emit between two cycle indices (max 16 cycles) |
293
351
  | `transpile_pattern` | Transpile pattern source via StrudelEngine; returns transpiled code or syntax error |
@@ -298,7 +356,7 @@ Then ask Claude:
298
356
 
299
357
  | Tool | Description |
300
358
  |------|-------------|
301
- | `session` | Manage isolated Strudel browser sessions (multi-session, #108). |
359
+ | `session` | Manage isolated Strudel browser sessions (multi-session, #108). action=create starts a new named session (sessions share one browser but isolated contexts). action=destroy closes a named session and releases its resources. action=list returns metadata for all active sessions (id, created, last_activity, is_playing, is_default). action=switch changes the default session that subsequent tool calls route to when no session_id is passed. Example: session({ action: "create", session_id: "live-set-1" }). For the on-disk pattern catalog use pattern_store(action=list) — session(action=list) lists *runtime* sessions, not saved patterns. |
302
360
 
303
361
  </details>
304
362
 
@@ -307,7 +365,7 @@ Then ask Claude:
307
365
  | Tool | Description |
308
366
  |------|-------------|
309
367
  | `export_midi` | Export current pattern to MIDI file. Parses note(), n(), and chord() functions. |
310
- | `browser_window` | Interact with the visible Strudel browser window. |
368
+ | `browser_window` | Interact with the visible Strudel browser window. action=show brings the window to the foreground. action=screenshot captures the current editor view to disk (optional `filename`). Example: browser_window({ action: "screenshot", filename: "demo.png" }). For diagnostics (status/errors/perf) use diagnostics; for the editor itself use edit_pattern. |
311
369
 
312
370
  </details>
313
371
 
@@ -315,7 +373,7 @@ Then ask Claude:
315
373
 
316
374
  | Tool | Description |
317
375
  |------|-------------|
318
- | `audio_capture` | Record audio output from the live Strudel session. |
376
+ | `audio_capture` | Record audio output from the live Strudel session. action=start begins streaming capture (optional `format` webm/opus, default webm). action=stop ends the stream and returns base64-encoded audio. action=sample captures a fixed-`duration` window in one call (100-60000ms, default 5000ms). Example: audio_capture({ action: "sample", duration: 3000 }). Audio must be playing for capture to record meaningful data. For MIDI export use export_midi; for runtime diagnostics use diagnostics. Each session has its own recorder, so captures in different sessions do not interfere (#180). |
319
377
 
320
378
  </details>
321
379
 
@@ -323,11 +381,19 @@ Then ask Claude:
323
381
 
324
382
  | Tool | Description |
325
383
  |------|-------------|
326
- | `diagnostics` | Inspect server and browser state. |
384
+ | `diagnostics` | Inspect server and browser state. level=status returns a quick state snapshot (cache read, <15ms SLA), plus which config.json was read and any warnings from it. level=full returns detailed browser diagnostics including caches, errors, and performance. level=perf returns server-side timing metrics + top bottlenecks. level=memory returns process memory usage. level=errors returns captured console errors and warnings from Strudel. Default level=full preserves the pre-consolidation behaviour. Example: diagnostics({ level: "status" }) — millisecond-cheap. For screenshots use browser_window; for tool listings use the strudel://docs/tools resource. |
327
385
 
328
386
  </details>
329
387
 
330
- _Auto-generated from source. 26 tools registered._
388
+ <details><summary><strong>Other</strong> (1)</summary>
389
+
390
+ | Tool | Description |
391
+ |------|-------------|
392
+ | `export_audio` | Record a window of live Strudel audio and write it to a file. Returns a path plus what was actually recorded, not a wall of base64 — prefer this over audio_capture when you want the audio to exist somewhere. format=wav (default) decodes to 16-bit PCM a DAW will open; format=webm writes the raw Opus recording. Reports silent captures instead of writing a silent file and claiming success. Audio must already be playing: call playback({ action: "play" }) first. Example: export_audio({ duration: 4000, filename: "take-01" }). |
393
+
394
+ </details>
395
+
396
+ _Auto-generated from source. 28 tools registered._
331
397
 
332
398
  <!-- TOOLS:END -->
333
399
 
@@ -344,7 +410,7 @@ Claude: [Initializes browser]
344
410
  [Starts playback]
345
411
 
346
412
  Pattern created:
347
- setcpm(130)
413
+ setcpm(130/4)
348
414
  stack(
349
415
  s("bd*4"),
350
416
  s("~ cp ~ cp"),
@@ -384,7 +450,7 @@ You: Generate a complete drum & bass track at 174 BPM
384
450
  Claude: [Creates multi-layer pattern with drums, bass, and pads]
385
451
 
386
452
  // dnb pattern in C at 174 BPM
387
- setcpm(174)
453
+ setcpm(174/4)
388
454
  stack(
389
455
  // Drums
390
456
  s("bd ~ ~ [bd bd] ~ ~ bd ~, ~ ~ cp ~ ~ cp ~ ~").fast(2),
@@ -439,7 +505,7 @@ You: Create an ambient soundscape with multiple layers
439
505
 
440
506
  Claude: [Generates complex multi-layer pattern]
441
507
 
442
- setcpm(90)
508
+ setcpm(90/4)
443
509
  stack(
444
510
  // Deep bass drone
445
511
  note("c1").s("sine").attack(4).release(8).gain(0.5),
@@ -535,7 +601,7 @@ note("c4 eb4 g4 bb4 c5").struct("1 1 1 1 1 1 1 1")
535
601
 
536
602
  ## Testing
537
603
 
538
- All tools have been tested with real Strudel.cc interaction:
604
+ Tools are exercised against real Strudel.cc interaction through the browser test suite; those are skipped in CI (require Playwright + audio) but run locally:
539
605
 
540
606
  ```bash
541
607
  # Run integration tests
@@ -555,273 +621,46 @@ node tests/strudel-integration.js
555
621
  "headless": false, // Set true for background operation
556
622
  "strudel_url": "https://strudel.cc/",
557
623
  "patterns_dir": "./patterns",
624
+ "exports_dir": "./exports",
625
+ "viewport": { "width": 1280, "height": 720 }, // or null to track the window size (#514)
626
+ "block_resources": ["image", "font", "media"], // resource types the page route aborts
558
627
  "audio_analysis": {
559
- "fft_size": 2048,
560
- "smoothing": 0.8
628
+ "fft_size": 2048, // power of 2 in [32, 32768]; code default is 1024
629
+ "smoothing": 0.8 // number in [0, 1]; default 0.8
561
630
  }
562
631
  }
563
632
  ```
564
633
 
565
- ## Architecture
566
-
567
- ### System Overview
568
-
569
- The Strudel MCP Server is built with a modular architecture that separates concerns and enables robust music generation:
570
-
571
- ```
572
- ┌─────────────────────────────────────────────────────────────┐
573
- │ Claude AI │
574
- │ (MCP Client) │
575
- └───────────────────────┬─────────────────────────────────────┘
576
- │ MCP Protocol (stdio)
577
- │
578
- ┌───────────────────────▼─────────────────────────────────────┐
579
- │ StrudelMCPServer │
580
- │ ┌────────────────────────────────────────────────────────┐ │
581
- │ │ Tool Request Handler │ │
582
- │ │ - Validates inputs │ │
583
- │ │ - Routes to appropriate service │ │
584
- │ │ - Handles errors gracefully │ │
585
- │ └────────────────────────────────────────────────────────┘ │
586
- └───────┬────────────┬────────────┬───────────┬──────────────┘
587
- │ │ │ │
588
- ┌────▼────┐ ┌───▼────┐ ┌───▼────┐ ┌──▼──────┐
589
- │ Strudel │ │ Music │ │Pattern │ │ Pattern │
590
- │Controller│ │ Theory │ │Generator│ │ Store │
591
- └────┬────┘ └────────┘ └────────┘ └─────────┘
592
- │
593
- ┌────▼────────────────────────────┐
594
- │ Playwright Browser │
595
- │ ┌──────────────────────────┐ │
596
- │ │ Strudel.cc Website │ │
597
- │ │ ┌────────────────────┐ │ │
598
- │ │ │ CodeMirror Editor │ │ │
599
- │ │ └────────────────────┘ │ │
600
- │ │ ┌────────────────────┐ │ │
601
- │ │ │ Audio Context │ │ │
602
- │ │ │ + Web Audio API │ │ │
603
- │ │ └────────┬───────────┘ │ │
604
- │ └───────────┼──────────────┘ │
605
- └──────────────┼──────────────────┘
606
- │
607
- ┌───────▼────────┐
608
- │ Audio Analyzer │
609
- │ - FFT Analysis│
610
- │ - Frequency │
611
- │ - Spectral │
612
- └────────────────┘
613
- ```
614
-
615
- ### Core Components
616
-
617
- #### 1. **StrudelMCPServer** (`src/server/server.ts`, ~510 lines)
618
-
619
- Thin MCP dispatcher that:
620
- - Aggregates 26 tool definitions from the per-domain modules in `src/server/tools/`
621
- - Routes `tools/call` requests to the right module's `execute()`
622
- - Wraps every response in the discriminated result envelope (`{ ok, errorCategory, isRetryable, ... }`)
623
- - Tracks initialization, per-session history bundles, per-session audio capture services
624
- - Advertises and serves MCP resources (`strudel://examples`, etc.)
625
- - Lazy-initializes the default browser controller on first browser-touching call
626
-
627
- Key Features:
628
- ```typescript
629
- - Pattern caching before browser init
630
- - Undo/redo stack management
631
- - Session history tracking
632
- - Generated pattern storage
633
- - Safe fallback mechanisms
634
- ```
635
-
636
- #### 2. **StrudelController** (`src/StrudelController.ts`)
637
-
638
- Browser automation layer using Playwright:
639
- - **Browser Management**: Chromium instance lifecycle
640
- - **Editor Control**: CodeMirror manipulation via DOM
641
- - **Playback Control**: Keyboard shortcuts for play/stop
642
- - **Performance Optimizations**:
643
- - Editor content caching (100ms TTL)
644
- - Direct CodeMirror API access
645
- - Resource blocking (images, fonts)
646
- - Fast DOM content loading
647
-
648
- ```typescript
649
- // Example: Optimized pattern writing
650
- async writePattern(pattern: string) {
651
- await this.page.evaluate((newPattern) => {
652
- const editor = document.querySelector('.cm-content');
653
- const view = editor.__view;
654
- view.dispatch({
655
- changes: { from: 0, to: view.state.doc.length, insert: newPattern }
656
- });
657
- }, pattern);
658
- }
659
- ```
660
-
661
- #### 3. **AudioAnalyzer** (`src/AudioAnalyzer.ts`)
662
-
663
- Real-time audio analysis via Web Audio API injection:
664
- - **FFT Analysis**: 1024-point FFT for spectral data
665
- - **Frequency Bands**: Bass, low-mid, mid, high-mid, treble
666
- - **Analysis Caching**: 50ms TTL for performance
667
- - **Features Extracted**:
668
- - Average amplitude
669
- - Peak frequency
670
- - Spectral centroid
671
- - Playing state detection
672
- - Frequency distribution
673
-
674
- ```typescript
675
- Features provided:
676
- - average: Overall amplitude (0-255)
677
- - peak: Maximum amplitude
678
- - peakFrequency: Dominant frequency in Hz
679
- - bass/mid/treble: Band-specific amplitudes
680
- - brightness: Timbral classification
681
- - isPlaying: Boolean playback state
682
- ```
683
-
684
- #### 4. **MusicTheory** (`src/services/MusicTheory.ts`)
685
-
686
- Music theory engine providing:
687
- - **15+ Scales**: Major, minor, modes, pentatonic, blues, whole-tone
688
- - **Chord Progressions**: Pop, jazz, blues, rock, folk, EDM
689
- - **Euclidean Rhythms**: Mathematical rhythm generation
690
- - **Arpeggio Generation**: Multiple patterns (up, down, random)
691
- - **Note Transposition**: Semitone-based pitch shifting
692
-
693
- Supported scales:
694
- ```typescript
695
- major, minor, dorian, phrygian, lydian, mixolydian,
696
- aeolian, locrian, pentatonic, blues, chromatic,
697
- wholetone, harmonic_minor, melodic_minor
698
- ```
699
-
700
- #### 5. **PatternGenerator** (`src/services/PatternGenerator.ts`)
634
+ `strudel_url` is the REPL the browser is pointed at — set it to run against a self-hosted or
635
+ pinned Strudel build. Only `http`/`https` are accepted; anything else falls back to the default
636
+ with a logged warning. `patterns_dir` is where `pattern_store` reads and writes.
701
637
 
702
- AI-powered pattern creation:
703
- - **Genre Templates**: Techno, house, DnB, trap, ambient, jazz, intelligent_dnb, trip_hop, boom_bap
704
- - **Drum Patterns**: 4 complexity levels per genre
705
- - **Basslines**: 8 different styles
706
- - **Melody Generation**: Scale-based with musical intervals
707
- - **Variations**: Subtle, moderate, extreme, glitch, evolving
708
- - **Fills**: 1-4 bar drum fills
638
+ `viewport` pins the Playwright page layout. Set it to `null` in a headed window so dragging the
639
+ window resizes the page and strudel's canvases follow (#514). `block_resources` lists the
640
+ resource types the page route aborts to speed up load; the default blocks `image`, `font`, and
641
+ `media`, which suits headless CI but degrades the live editor (fallback-font button metrics,
642
+ canvases that ignore window resizes). A live-coding setup wants `"block_resources": ["media"]`.
643
+ Both keys fall back to the defaults with a logged warning when invalid.
709
644
 
710
- Example generation:
711
- ```typescript
712
- generateCompletePattern('techno', 'C', 130)
713
- → Multi-layer pattern with drums, bass, chords, melody
714
- ```
715
-
716
- #### 6. **PatternStore** (`src/PatternStore.ts`)
717
-
718
- Persistent pattern storage:
719
- - **JSON-based**: Simple file storage
720
- - **Metadata**: Name, tags, timestamp, audio features
721
- - **Tag Filtering**: Organize by genre, mood, project
722
- - **Sorted Retrieval**: Most recent first
723
-
724
- ### Directory Structure
725
-
726
- ```
727
- live-coding-music-mcp/
728
- ├── src/
729
- │ ├── server/
730
- │ │ ├── server.ts # MCP dispatcher (~510 lines)
731
- │ │ ├── resources.ts # MCP resources (#131)
732
- │ │ └── tools/
733
- │ │ ├── ai.ts, analysis.ts, capture.ts, compose.ts,
734
- │ │ ├── diagnostics.ts, editor.ts, generate.ts, history.ts,
735
- │ │ ├── playback.ts, session.ts, storage.ts, transform.ts,
736
- │ │ └── types.ts # ToolContext, Envelope, helpers
737
- │ ├── services/
738
- │ │ ├── MusicTheory.ts # Scale/chord/euclidean helpers
739
- │ │ ├── PatternGenerator.ts # Template-based generation
740
- │ │ ├── SessionManager.ts # Multi-session lifecycle (#108)
741
- │ │ ├── AudioCaptureService.ts # Audio recording
742
- │ │ ├── MIDIExportService.ts # MIDI export
743
- │ │ ├── GeminiService.ts # Gemini API client (ai_assist)
744
- │ │ ├── StrudelEngine.ts # @strudel/* wrapper
745
- │ │ └── StrudelEngineHelpers.ts # Pure helpers (#107)
746
- │ ├── utils/
747
- │ │ ├── Logger.ts
748
- │ │ ├── PatternValidator.ts # Syntax + safety checks
749
- │ │ ├── ErrorRecovery.ts # Retry / backoff
750
- │ │ ├── PerformanceMonitor.ts
751
- │ │ └── InputValidator.ts # Input bound checks
752
- │ ├── StrudelController.ts # Browser automation (~800 lines)
753
- │ ├── AudioAnalyzer.ts # Audio analysis (~800 lines)
754
- │ ├── PatternStore.ts # On-disk pattern persistence
755
- │ └── index.ts # Entry point
756
- ├── src/__tests__/ # Jest suites (unit + integration + browser)
757
- ├── patterns/
758
- │ ├── examples/ # 18 bundled example patterns
759
- │ └── *.json # Saved patterns at runtime
760
- ├── scripts/
761
- │ ├── generate-tool-docs.ts # README tool-table generator
762
- │ └── generate-changelog.ts
763
- ├── config.json # Local config (gitignored)
764
- ├── package.json
765
- └── tsconfig.json
766
- ```
767
-
768
- ### Data Flow
769
-
770
- 1. **Tool Invocation**
771
- ```
772
- Claude → MCP Protocol → StrudelMCPServer
773
- ```
774
-
775
- 2. **Pattern Generation** (without browser)
776
- ```
777
- Server → PatternGenerator → MusicTheory → Pattern String
778
- ```
645
+ `exports_dir` is where `export_midi({format:"file"})` writes. Exported filenames are reduced to a
646
+ basename and confined to this directory — a name containing path separators is sanitized rather
647
+ than honoured, and the response reports the path actually written.
779
648
 
780
- 3. **Pattern Execution** (with browser)
781
- ```
782
- Server → StrudelController → Playwright → Strudel.cc
783
- ```
649
+ Unknown top-level keys are logged as warnings at startup rather than silently ignored.
784
650
 
785
- 4. **Audio Analysis**
786
- ```
787
- Strudel.cc → Web Audio API → AudioAnalyzer → Feature Data
788
- ```
789
-
790
- ### Performance Characteristics
791
-
792
- | Operation | Latency | Notes |
793
- |-----------|---------|-------|
794
- | Pattern Generation | <100ms | Pure computation |
795
- | Browser Init | ~3s | One-time cost |
796
- | Pattern Write | ~50ms | With caching |
797
- | Play/Stop | ~100ms | Keyboard shortcuts |
798
- | Audio Analysis | ~20ms | With 50ms cache |
799
- | Pattern Save | ~10ms | File I/O |
800
-
801
- ### Optimization Strategies
802
-
803
- 1. **Caching**
804
- - Editor content: 100ms TTL
805
- - Audio analysis: 50ms TTL
806
- - Generated patterns: Until browser init
651
+ `audio_analysis.fft_size` tunes the FFT bin count on the `AnalyserNode` attached to Strudel's audio graph — larger = better frequency resolution at higher CPU cost. `smoothing` is the analyser's `smoothingTimeConstant` (higher = steadier spectrum, more lag). Invalid values fall back to defaults with a warning; the frequency-band boundaries inside `analyze` rescale automatically so band Hz coverage stays consistent across FFT sizes.
807
652
 
808
- 2. **Resource Blocking**
809
- - Images, fonts, media blocked
810
- - Only load essential JavaScript/CSS
653
+ ## Architecture
811
654
 
812
- 3. **Direct API Access**
813
- - CodeMirror view manipulation
814
- - Keyboard shortcuts over button clicks
655
+ The server is a thin MCP dispatcher (`src/server/server.ts`, ~520 lines) over twelve per-domain tool modules (`src/server/tools/*.ts`), ten services (MusicTheory, PatternGenerator, SessionManager, AudioCaptureService, AudioExportService, GeminiService, MIDIExportService, MIDIImportService, StrudelEngine, PatternSandbox) plus a provider-agnostic AI transport layer (`src/services/ai/`), two controllers (StrudelController for Playwright, AudioAnalyzer for Web Audio API), and a JSON-on-disk PatternStore. Browser automation drives the editor on strudel.cc through `window.strudelMirror.editor.dispatch(...)` rather than keyboard simulation — about 80% faster.
815
656
 
816
- 4. **Lazy Loading**
817
- - Browser starts only when needed
818
- - Services initialized on-demand
657
+ For the full breakdown — component diagram, per-component responsibilities, directory layout, data flow, and optimization strategies — see **[ARCHITECTURE.md](ARCHITECTURE.md)**.
819
658
 
820
659
  ## Pattern Examples
821
660
 
822
661
  ### Minimal Techno (Verified Working)
823
662
  ```javascript
824
- setcpm(130)
663
+ setcpm(130/4)
825
664
  stack(
826
665
  s("bd*4").gain(0.9),
827
666
  s("~ cp ~ cp").room(0.2),
@@ -832,7 +671,7 @@ stack(
832
671
 
833
672
  ### Drum & Bass (Verified Working)
834
673
  ```javascript
835
- setcpm(174)
674
+ setcpm(174/4)
836
675
  stack(
837
676
  s("bd ~ ~ [bd bd] ~ ~ bd ~, ~ ~ sn:3 ~ ~ sn:3 ~ ~").fast(2),
838
677
  s("hh*16").gain(0.5),
@@ -864,347 +703,15 @@ docker-compose up
864
703
 
865
704
  ## Development
866
705
 
867
- ### Setup Development Environment
868
-
869
- ```bash
870
- # Clone the repository
871
- git clone https://github.com/williamzujkowski/live-coding-music-mcp.git
872
- cd live-coding-music-mcp
873
-
874
- # Install dependencies
875
- npm install
876
-
877
- # Install Playwright browsers
878
- npx playwright install chromium
879
-
880
- # Build the project
881
- npm run build
882
- ```
883
-
884
- ### Available Scripts
706
+ For development setup, scripts, debugging, adding new tools, and the release process, see **[DEVELOPMENT.md](DEVELOPMENT.md)**.
885
707
 
886
- ```bash
887
- # Development mode with hot reload
888
- npm run dev
889
-
890
- # Build TypeScript to dist/
891
- npm run build
892
-
893
- # Start production server
894
- npm start
895
-
896
- # Run all tests
897
- npm test
898
-
899
- # Run integration tests with real browser
900
- npm run test:integration
901
-
902
- # Run browser-specific tests
903
- npm run test:browser
904
-
905
- # Validate MCP protocol compliance
906
- npm run validate
907
-
908
- # Lint code
909
- npm run lint
910
-
911
- # Format code
912
- npm run format
913
-
914
- # Clean build artifacts
915
- npm clean
916
- ```
917
-
918
- ### Publishing to npm
919
-
920
- See [NPM_PUBLISHING.md](NPM_PUBLISHING.md) for complete publishing instructions.
921
-
922
- **Quick publish via GitHub Release:**
923
- ```bash
924
- npm version patch # or minor, major
925
- git push && git push --tags
926
- gh release create v$(node -p "require('./package.json').version") --generate-notes
927
- ```
928
-
929
- The package uses OIDC trusted publishing with provenance attestation for supply chain security.
930
-
931
- ### Adding new tools
932
-
933
- Tools live in per-domain modules under `src/server/tools/<domain>.ts`. `server.ts` just dispatches. To add a tool:
934
-
935
- 1. **Pick the right domain module** (or add a new one). Add the tool definition to that module's `tools` array:
936
-
937
- ```typescript
938
- export const tools: Tool[] = [
939
- // ...
940
- {
941
- name: 'my_new_tool',
942
- description: 'One-line description; agents read this to pick between adjacent tools',
943
- inputSchema: {
944
- type: 'object',
945
- properties: {
946
- param1: { type: 'string', description: 'What it is' },
947
- session_id: { type: 'string', description: 'Optional session ID (#108)' },
948
- },
949
- required: ['param1'],
950
- },
951
- },
952
- ];
953
- ```
954
-
955
- 2. **Add the case** to the module's `execute()` switch:
956
-
957
- ```typescript
958
- case 'my_new_tool':
959
- return await ctx.getController(args.session_id).doSomething(args.param1);
960
- ```
961
-
962
- 3. **Add a service method** if needed (`MusicTheory`, `PatternGenerator`, etc.) and surface it through `ToolContext` (`src/server/tools/types.ts`) if other modules need it.
963
-
964
- 4. **Don't hand-edit the README tool table.** It auto-generates via `npm run build` → `scripts/generate-tool-docs.ts`. A Jest test plus a CI step guard against drift.
965
-
966
- 5. **Use the envelope helpers** for returns: `ok(data)`, `empty(data)`, `err('validation', 'message')` from `src/server/tools/types.ts`. Raw returns still work — the dispatcher normalises them — but native envelope construction is clearer.
967
-
968
- 6. **Build and test**:
969
-
970
- ```bash
971
- npm run build
972
- echo '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"my_new_tool","arguments":{"param1":"test"}},"id":2}' | node dist/index.js
973
- ```
974
-
975
- ### Testing Strategy
976
-
977
- #### 1. Unit Tests
978
- ```bash
979
- # Run with Jest
980
- npm test
981
-
982
- # Watch mode
983
- npm run test:watch
984
- ```
985
-
986
- #### 2. Integration Tests
987
- ```bash
988
- # Full integration with real browser
989
- npm run test:integration
990
-
991
- # This tests:
992
- # - Browser initialization
993
- # - Pattern generation
994
- # - Audio analysis
995
- # - Pattern storage
996
- # - All 84 registered tools
997
- ```
998
-
999
- #### 3. Manual Testing
1000
- ```bash
1001
- # Development mode
1002
- npm run dev
1003
-
1004
- # In another terminal
1005
- claude mcp add strudel-dev node $(pwd)/dist/index.js
1006
- claude chat
1007
-
1008
- # Then interact with Claude
1009
- ```
1010
-
1011
- ### Code Quality
1012
-
1013
- **TypeScript Configuration**
1014
- ```json
1015
- // tsconfig.json
1016
- {
1017
- "compilerOptions": {
1018
- "strict": true, // Strict type checking
1019
- "esModuleInterop": true, // Better module compatibility
1020
- "target": "ES2020", // Modern JavaScript
1021
- "module": "ES2020", // ES modules
1022
- "moduleResolution": "node"
1023
- }
1024
- }
1025
- ```
1026
-
1027
- **Linting & Formatting**
1028
- ```bash
1029
- # ESLint
1030
- npm run lint
1031
-
1032
- # Prettier
1033
- npm run format
1034
-
1035
- # Pre-commit hooks recommended
1036
- ```
1037
-
1038
- ### Debugging
1039
-
1040
- **Enable Debug Logging**
1041
- ```bash
1042
- # Set DEBUG environment variable
1043
- DEBUG=strudel:* npm start
1044
-
1045
- # Or specific modules
1046
- DEBUG=strudel:controller npm start
1047
- DEBUG=strudel:audio npm start
1048
- ```
1049
-
1050
- **VS Code Launch Configuration**
1051
- ```json
1052
- {
1053
- "type": "node",
1054
- "request": "launch",
1055
- "name": "Debug MCP Server",
1056
- "program": "${workspaceFolder}/dist/index.js",
1057
- "preLaunchTask": "npm: build",
1058
- "console": "integratedTerminal",
1059
- "env": {
1060
- "DEBUG": "strudel:*"
1061
- }
1062
- }
1063
- ```
1064
-
1065
- **Playwright Debugging**
1066
- ```typescript
1067
- // In StrudelController.ts
1068
- this.browser = await chromium.launch({
1069
- headless: false, // See the browser
1070
- devtools: true, // Open DevTools
1071
- slowMo: 100 // Slow down actions
1072
- });
1073
- ```
1074
-
1075
- ### Performance Monitoring
1076
-
1077
- The server includes built-in performance monitoring:
1078
-
1079
- ```typescript
1080
- // Access performance metrics
1081
- You: Show me performance metrics
1082
-
1083
- Claude: Performance Report:
1084
- {
1085
- "averageLatency": {
1086
- "init": "3.2s",
1087
- "write": "52ms",
1088
- "play": "105ms",
1089
- "analyze": "18ms"
1090
- },
1091
- "cacheHitRate": "85%",
1092
- "totalOperations": 1247,
1093
- "bottlenecks": [
1094
- {"tool": "init", "avgTime": 3200, "calls": 1},
1095
- {"tool": "write", "avgTime": 52, "calls": 156}
1096
- ]
1097
- }
1098
- ```
1099
-
1100
- ### Contributing Guidelines
1101
-
1102
- 1. **Fork the repository**
1103
- ```bash
1104
- git clone https://github.com/YOUR_USERNAME/live-coding-music-mcp.git
1105
- ```
1106
-
1107
- 2. **Create a feature branch**
1108
- ```bash
1109
- git checkout -b feature/my-new-feature
1110
- ```
1111
-
1112
- 3. **Make your changes**
1113
- - Follow existing code style
1114
- - Add tests for new features
1115
- - Update documentation
1116
- - Ensure all tests pass
1117
-
1118
- 4. **Commit with meaningful messages**
1119
- ```bash
1120
- git commit -m "feat: Add support for custom scale generation"
1121
- ```
1122
-
1123
- Follow [Conventional Commits](https://www.conventionalcommits.org/):
1124
- - `feat:` New feature
1125
- - `fix:` Bug fix
1126
- - `docs:` Documentation changes
1127
- - `refactor:` Code refactoring
1128
- - `test:` Adding tests
1129
- - `chore:` Maintenance tasks
1130
-
1131
- 5. **Push and create PR**
1132
- ```bash
1133
- git push origin feature/my-new-feature
1134
- ```
1135
-
1136
- Then create a Pull Request on GitHub with:
1137
- - Clear description of changes
1138
- - Link to related issues
1139
- - Screenshots/examples if relevant
1140
-
1141
- ### Release Process
708
+ Quick links:
709
+ - [Setup](DEVELOPMENT.md#setup) — `git clone` to `npm test`
710
+ - [Adding new tools](DEVELOPMENT.md#adding-new-tools) — module pattern + envelope helpers
711
+ - [Release process](DEVELOPMENT.md#release-process) — `gh release create` triggers the publish workflow
712
+ - [Contributing](DEVELOPMENT.md#contributing) — commit conventions and PR flow
1142
713
 
1143
- ```bash
1144
- # 1. Update version in package.json
1145
- npm version patch # or minor/major
1146
-
1147
- # 2. Update CHANGELOG.md
1148
- # Add entry for new version
1149
-
1150
- # 3. Build and test
1151
- npm run build
1152
- npm test
1153
- npm run test:integration
1154
-
1155
- # 4. Commit version bump
1156
- git add .
1157
- git commit -m "chore: Bump version to X.Y.Z"
1158
-
1159
- # 5. Create git tag
1160
- git tag vX.Y.Z
1161
-
1162
- # 6. Push to GitHub
1163
- git push origin main --tags
1164
-
1165
- # 7. Publish to npm (if you have access)
1166
- npm publish --access public
1167
-
1168
- # 8. Create GitHub release
1169
- gh release create vX.Y.Z --generate-notes
1170
- ```
1171
-
1172
- ### Docker Development
1173
-
1174
- ```bash
1175
- # Build development image
1176
- docker build -t live-coding-music-mcp:dev .
1177
-
1178
- # Run with volume mount for hot reload
1179
- docker run -it --rm \
1180
- -v $(pwd)/src:/app/src \
1181
- -v $(pwd)/patterns:/app/patterns \
1182
- live-coding-music-mcp:dev
1183
-
1184
- # Run tests in container
1185
- docker run -it --rm live-coding-music-mcp:dev npm test
1186
- ```
1187
-
1188
- ### Environment Variables
1189
-
1190
- ```bash
1191
- # Logging level
1192
- LOG_LEVEL=debug # debug, info, warn, error
1193
-
1194
- # Performance monitoring
1195
- ENABLE_PERF_MONITORING=true
1196
-
1197
- # Pattern storage
1198
- PATTERNS_DIR=./patterns
1199
-
1200
- # Browser configuration
1201
- HEADLESS=false
1202
- BROWSER_TIMEOUT=15000
1203
-
1204
- # Audio analysis
1205
- FFT_SIZE=1024
1206
- SMOOTHING=0.8
1207
- ```
714
+ The [Configuration](#configuration) section above covers runtime config (`config.json`). [ARCHITECTURE.md](ARCHITECTURE.md) covers the system design.
1208
715
 
1209
716
  ## Performance
1210
717
 
@@ -1217,8 +724,8 @@ Measured against the current `StrudelController` cache + Strudel.cc on a develop
1217
724
  | Pattern read (cached) | 10–15 ms |
1218
725
  | Play / pause / stop | 100–150 ms |
1219
726
  | Audio analysis (single FFT) | 10–15 ms |
1220
- | Tempo detection | <100 ms (onset-based; degraded under headless audio) |
1221
- | Key detection | <100 ms (Krumhansl-Schmuckler) |
727
+ | Tempo detection | <100 ms (onset-based; reports poll cadence, not tempo — #322) |
728
+ | Key detection | <100 ms (Krumhansl-Schmuckler, Pearson; bass-register accuracy depends on `fft_size`) |
1222
729
  | Pattern generation | <100 ms (template-based) |
1223
730
  | Process resident memory | ~120–150 MB |
1224
731
 
@@ -1389,7 +896,7 @@ s("bd*4")
1389
896
  .every(8, x => x.sometimes(y => y.fast(2)))
1390
897
  ```
1391
898
 
1392
- ## 🔒 Security
899
+ ## Security
1393
900
 
1394
901
  ### Pattern Validation
1395
902
 
@@ -1398,11 +905,23 @@ All patterns are validated before execution:
1398
905
  - **Eval blocks** are rejected
1399
906
  - **Path traversal** attacks are blocked in PatternStore
1400
907
 
1401
- ### Browser Sandboxing
908
+ ### Browser Isolation
909
+
910
+ Be precise about what this does and does not give you:
911
+
912
+ - **The OS-level Chrome sandbox is disabled.** Chromium is launched with `--no-sandbox` and
913
+ `--disable-setuid-sandbox` ([`src/StrudelController.ts`](src/StrudelController.ts)) for headless
914
+ and container compatibility, where the sandbox otherwise needs `CAP_SYS_ADMIN` or user namespaces.
915
+ This is a deliberate trade-off, not a security feature.
916
+ - **The browser context is a fresh, non-persistent Playwright context** — no profile on disk, no
917
+ cookies or storage carried over between runs, and no `file://` navigation is ever performed.
918
+ - **Resource blocking is a performance optimization, not a security boundary.** Images, fonts, and
919
+ media are aborted to speed up page load; scripts, stylesheets, and network requests from
920
+ strudel.cc are allowed through as normal.
921
+ - **Patterns are validated before execution** (see above), which is the actual pre-execution control.
1402
922
 
1403
- - Playwright runs Chromium in sandbox mode
1404
- - No access to local filesystem from browser context
1405
- - Resource blocking prevents loading external content
923
+ If you need real isolation, run the whole MCP server inside a locked-down container or VM. The
924
+ server does not sandbox itself.
1406
925
 
1407
926
  ### Known Limitations
1408
927
 
@@ -1414,7 +933,7 @@ All patterns are validated before execution:
1414
933
 
1415
934
  Found a vulnerability? Please [open a security issue](https://github.com/williamzujkowski/live-coding-music-mcp/security/advisories/new) or email the maintainer directly. Do not disclose publicly until patched.
1416
935
 
1417
- ## 🐛 Troubleshooting
936
+ ## Troubleshooting
1418
937
 
1419
938
  ### Common Issues
1420
939
 
@@ -1481,7 +1000,7 @@ npm run build
1481
1000
  # Check if server responds
1482
1001
  echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node dist/index.js
1483
1002
 
1484
- # Should return JSON with 26 tools
1003
+ # Should return JSON with 28 tools
1485
1004
 
1486
1005
  # Reinstall MCP server in Claude
1487
1006
  claude mcp remove strudel
@@ -1522,7 +1041,7 @@ claude chat
1522
1041
  - Use resource blocking (enabled by default)
1523
1042
 
1524
1043
  #### Patterns not saving
1525
- **Symptom**: `save` command fails or patterns don't persist
1044
+ **Symptom**: `pattern_store({ action: "save" })` fails or patterns don't persist
1526
1045
 
1527
1046
  **Solutions**:
1528
1047
  ```bash
@@ -1590,7 +1109,7 @@ Claude: Browser state:
1590
1109
  - Initialized: true
1591
1110
  - Cached patterns: 2
1592
1111
  - Undo stack depth: 5
1593
- - Last operation: write_pattern (2.5s ago)
1112
+ - Last operation: edit_pattern (2.5s ago)
1594
1113
  ```
1595
1114
 
1596
1115
  **Validate Pattern Syntax**
@@ -1613,50 +1132,28 @@ If you encounter issues not covered here:
1613
1132
  4. **Consult Strudel docs**: [Strudel.cc documentation](https://strudel.cc/learn)
1614
1133
  5. **Create new issue**: Include error messages, OS, Node version, and steps to reproduce
1615
1134
 
1616
- ## 🤝 Contributing
1617
-
1618
- **We need your help!** This project is actively developed and welcomes contributions of all kinds:
1619
-
1620
- ### Ways to Contribute
1621
- - **Report Bugs**: Found an issue? [Open a bug report](https://github.com/williamzujkowski/live-coding-music-mcp/issues/new)
1622
- - **Suggest Features**: Have ideas? [Create a feature request](https://github.com/williamzujkowski/live-coding-music-mcp/issues/new)
1623
- - **Improve Docs**: Fix typos, add examples, clarify confusing sections
1624
- - **Write Tests**: Help us improve test coverage
1625
- - **Fix Issues**: Check [open issues](https://github.com/williamzujkowski/live-coding-music-mcp/issues) for bugs to fix
1626
- - **Add Features**: Implement new tools or improve existing ones
1627
-
1628
- ### Quick Start for Contributors
1629
- 1. Fork the repository
1630
- 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
1631
- 3. Make your changes and add tests
1632
- 4. Ensure tests pass (`npm test`)
1633
- 5. Commit with clear messages (`git commit -m 'fix: resolve audio analysis bug'`)
1634
- 6. Push to your fork (`git push origin feature/amazing-feature`)
1635
- 7. Open a Pull Request
1135
+ ## Contributing
1636
1136
 
1637
- **First time contributor?** Look for issues labeled `good-first-issue` or `help-wanted`.
1137
+ PRs welcome — bug fixes, docs, tests, new tools. See **[CONTRIBUTING.md](CONTRIBUTING.md)** for the contribution guide and **[DEVELOPMENT.md](DEVELOPMENT.md)** for setup and workflow.
1638
1138
 
1639
- ### Feedback Welcome
1640
- - Questions? Open a [Discussion](https://github.com/williamzujkowski/live-coding-music-mcp/discussions)
1641
- - Found something confusing? Tell us!
1642
- - Have a use case we haven't considered? Share it!
1139
+ For non-trivial work, open a GitHub issue first ([issue policy in CLAUDE.md](CLAUDE.md#github-issues-workflow)). For typos and small fixes, a PR directly is fine.
1643
1140
 
1644
- We review PRs promptly and welcome contributors of all skill levels. See [DEVELOPMENT.md](DEVELOPMENT.md) for detailed setup instructions.
1141
+ [GitHub Discussions](https://github.com/williamzujkowski/live-coding-music-mcp/discussions) are open for use-case questions and design conversations.
1645
1142
 
1646
- ## 📄 License
1143
+ ## License
1647
1144
 
1648
1145
  **AGPL-3.0-or-later** — see [LICENSE](LICENSE) for the full text.
1649
1146
 
1650
1147
  This project depends on `@strudel/core`, `@strudel/mini`, `@strudel/tonal`, and `@strudel/transpiler`, which are AGPL-3.0 licensed by the upstream [Strudel project](https://codeberg.org/uzu/strudel). Since we `import` from those packages and redistribute the combined work via npm, this project must be distributed under the same copyleft terms. If you fork or redistribute, you must keep the AGPL license and provide source access to any network-accessible users (AGPL §13).
1651
1148
 
1652
- Earlier versions of this package (including `@williamzujkowski/strudel-mcp-server` prior to deprecation) shipped with an MIT declaration — that was incorrect given the AGPL dependencies. v2.0.0 of `@williamzujkowski/live-coding-music-mcp` corrects the license to AGPL-3.0-or-later. v1.0.0 of this package is deprecated; install v2.0.0 or later.
1149
+ Earlier versions of this package (including `@williamzujkowski/strudel-mcp-server` prior to deprecation) shipped with an MIT declaration — that was incorrect given the AGPL dependencies. v2.0.0 of `@williamzujkowski/live-coding-music-mcp` corrects the license to AGPL-3.0-or-later. v1.0.0 of this package is deprecated; install v2.0.0 or later (current: v4.0.0).
1653
1150
 
1654
- ## 🙏 Acknowledgments
1151
+ ## Acknowledgments
1655
1152
 
1656
- - [Strudel.cc](https://strudel.cc) - Amazing live coding environment
1657
- - [TidalCycles](https://tidalcycles.org) - Pattern language inspiration
1658
- - [Anthropic](https://anthropic.com) - Claude AI and MCP protocol
1659
- - [Playwright](https://playwright.dev) - Reliable browser automation
1153
+ - [Strudel.cc](https://strudel.cc) — pattern-based live coding environment (this project is a fan adapter, not affiliated)
1154
+ - [TidalCycles](https://tidalcycles.org) — original pattern language Strudel descends from
1155
+ - [Anthropic](https://anthropic.com) — Claude and the MCP protocol
1156
+ - [Playwright](https://playwright.dev) — browser automation
1660
1157
 
1661
1158
  ---
1662
1159