@williamzujkowski/live-coding-music-mcp 2.0.0 → 4.0.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.
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 | 77% test coverage | Published to npm | Actively developed
7
+ > **Status:** Beta | 86% 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,16 +13,16 @@
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-66-green.svg)]()
16
+ [![Tools](https://img.shields.io/badge/tools-26-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 and has 1470 passing tests covering 77% of statements. CI is hardened with OpenSSF Scorecard, SHA-pinned actions, CODEOWNERS, and Dependabot. Known coverage gaps exist (notably `AudioCaptureService` at 33% and `AudioAnalyzer` branch coverage at 48%) — see [open issues](https://github.com/williamzujkowski/live-coding-music-mcp/issues) for the full list.
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.
22
22
 
23
23
  **What "Beta" means here:**
24
24
  - Tool schemas are stable within minor versions; breaking changes require a major bump
25
- - Single-browser-session limitation (multi-session tracked in [#108](https://github.com/williamzujkowski/live-coding-music-mcp/issues/108))
25
+ - Multi-session is supported as of v3.0.0 ([#108](https://github.com/williamzujkowski/live-coding-music-mcp/issues/108)) — named sessions get isolated browser, history, and audio-capture state
26
26
  - Upstream `@strudel/*` dependencies pinned to known-good versions; Dependabot bumps gated on CI
27
27
  - Expect hands-on iteration for non-standard patterns — report rough edges, they get fixed
28
28
 
@@ -44,40 +44,39 @@ A Model Context Protocol (MCP) server that drives [Strudel.cc](https://strudel.c
44
44
 
45
45
  ## Features
46
46
 
47
- ### 🎹 Complete Music Control
48
- - **65 MCP Tools**: Comprehensive suite for music creation and manipulation
49
- - **Real Browser Automation**: Direct control of Strudel.cc through Playwright
50
- - **Live Audio Analysis**: Real-time frequency analysis via Web Audio API
51
- - **Pattern Generation**: AI-powered creation across 8+ music genres
52
- - **Music Theory Engine**: Scales, chords, progressions, euclidean rhythms
53
- - **Session Management**: Save, load, undo/redo with pattern storage
54
-
55
- ### 🔧 Testing & Development Status
56
- - ✅ **Test Suite**: Comprehensive test coverage across unit, integration, and validation tests
57
- - ✅ **Code Coverage**: Actively tracked via CI
58
- - ✅ **Browser Integration**: Works with live Strudel.cc website
59
- - ✅ **Audio Analysis**: Real-time FFT analysis functional
60
- - ✅ **Pattern Generation**: Core music generation features working
61
- - ✅ **OIDC Publishing**: Secure npm publishing with provenance attestation
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)).
49
+ - **4 MCP resources** for catalog browsing without burning tool calls: `strudel://examples`, `strudel://patterns`, `strudel://styles`, `strudel://docs/tools`.
50
+ - **Real browser automation** of Strudel.cc through Playwright.
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
+ - **Audio analysis** via Web Audio API (FFT spectrum, tempo detection, key detection, rhythm complexity).
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.
55
+ - **Pattern persistence**: JSON-backed save/load with tags + the in-memory edit history (undo/redo/restore/compare).
56
+ - **Result envelope** on every `tools/call`: clients branch on `{ ok, errorCategory, isRetryable }` instead of parsing free-text.
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).
62
+ - **OIDC trusted publishing** to npm with SLSA build provenance attestation on every release.
62
63
 
63
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.
64
65
 
65
- ### 🎼 Example Patterns
66
+ ### 🎼 Example patterns
66
67
 
67
- Explore 17 curated example patterns across 10 genres in [`patterns/examples/`](patterns/examples/):
68
+ 18 example patterns ship in [`patterns/examples/`](patterns/examples/), grouped by genre:
68
69
 
69
- - **Techno**: Hard techno, minimal techno
70
- - **House**: Deep house, tech house
71
- - **Drum & Bass**: Liquid, neurofunk
72
- - **Ambient**: Dark ambient, drone
73
- - **Trap**: Modern trap, cloud trap
74
- - **Jungle**: Classic jungle, ragga jungle
75
- - **Jazz**: Bebop, modal jazz
76
- - **Intelligent DnB**: Atmospheric, liquid, LTJ Bukem style
77
- - **Trip Hop**: Portishead, Massive Attack, Flying Lotus style
78
- - **Boom Bap**: DJ Premier, Alchemist, golden era hip hop
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
79
78
 
80
- Each example includes pattern code, BPM, key, and description. See [`patterns/examples/README.md`](patterns/examples/README.md) for details.
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.
81
80
 
82
81
  ## Migrating from `@williamzujkowski/strudel-mcp-server`
83
82
 
@@ -156,16 +155,21 @@ npm run build
156
155
 
157
156
  Common commands for immediate use:
158
157
 
159
- | Action | Command |
160
- |--------|---------|
158
+ | Action | Tool call |
159
+ |---|---|
161
160
  | Initialize browser | `init` |
162
- | Create techno beat | `generate_pattern` with `style: "techno"` |
163
- | Play pattern | `play` |
164
- | Stop playback | `stop` |
161
+ | Create a techno beat in one shot | `compose({ style: "techno" })` |
162
+ | Play pattern | `playback({ action: "play" })` |
163
+ | Stop playback | `playback({ action: "stop" })` |
165
164
  | Get current pattern | `get_pattern` |
166
- | Analyze audio | `analyze` |
167
- | Save pattern | `save` with `name: "my-pattern"` |
168
- | Undo last change | `undo` |
165
+ | Analyze audio (all features) | `analyze({ include: ["all"] })` |
166
+ | Detect tempo only | `analyze({ include: ["tempo"] })` |
167
+ | Save pattern | `pattern_store({ action: "save", name: "my-pattern" })` |
168
+ | Undo last edit | `history({ action: "undo" })` |
169
+ | Edit current pattern | `edit_pattern({ mode: "write", pattern: "..." })` |
170
+ | Create an isolated session | `session({ action: "create", session_id: "live-1" })` |
171
+
172
+ The legacy single-verb tools (`play`, `stop`, `save`, `undo`, `write`, `generate_pattern`, ...) were deprecated aliases during the `3.0.x` line and were removed in v4.0.0 ([#178](https://github.com/williamzujkowski/live-coding-music-mcp/issues/178)). Use the consolidated tools above.
169
173
 
170
174
  **One-shot workflow:**
171
175
  ```
@@ -197,7 +201,7 @@ Then ask Claude:
197
201
 
198
202
  <!-- TOOLS:START -->
199
203
 
200
- **66 tools** across 15 categories:
204
+ **26 tools** across 14 categories:
201
205
 
202
206
  <details><summary><strong>Setup</strong> (1)</summary>
203
207
 
@@ -207,127 +211,94 @@ Then ask Claude:
207
211
 
208
212
  </details>
209
213
 
210
- <details><summary><strong>Pattern Editing</strong> (5)</summary>
214
+ <details><summary><strong>Pattern Editing</strong> (2)</summary>
211
215
 
212
216
  | Tool | Description |
213
217
  |------|-------------|
214
- | `write` | Write pattern to editor with optional auto-play and validation |
215
- | `append` | Append code to current pattern |
216
- | `insert` | Insert code at specific line |
217
- | `replace` | Replace pattern section |
218
+ | `edit_pattern` | Mutate the current session pattern. |
218
219
  | `get_pattern` | Get current pattern code |
219
220
 
220
221
  </details>
221
222
 
222
- <details><summary><strong>Playback</strong> (6)</summary>
223
+ <details><summary><strong>Playback</strong> (2)</summary>
223
224
 
224
225
  | Tool | Description |
225
226
  |------|-------------|
226
- | `status` | Get current browser and playback status (quick state check) |
227
- | `clear` | Clear the editor |
228
- | `play` | Start playing pattern |
229
- | `pause` | Pause playback |
230
- | `stop` | Stop playback |
227
+ | `playback` | Control transport on the current session. |
231
228
  | `set_tempo` | Set BPM |
232
229
 
233
230
  </details>
234
231
 
235
- <details><summary><strong>Storage</strong> (3)</summary>
232
+ <details><summary><strong>Storage</strong> (1)</summary>
236
233
 
237
234
  | Tool | Description |
238
235
  |------|-------------|
239
- | `save` | Save pattern with metadata |
240
- | `load` | Load saved pattern |
241
- | `list` | List saved patterns |
236
+ | `pattern_store` | Persist patterns to disk and read them back. |
242
237
 
243
238
  </details>
244
239
 
245
- <details><summary><strong>History</strong> (4)</summary>
240
+ <details><summary><strong>History</strong> (1)</summary>
246
241
 
247
242
  | Tool | Description |
248
243
  |------|-------------|
249
- | `undo` | Undo last action |
250
- | `redo` | Redo action |
251
- | `list_history` | List recent pattern history with timestamps and previews |
252
- | `restore_history` | Restore a previous pattern from history by ID |
244
+ | `history` | Navigate or inspect the pattern edit history. |
253
245
 
254
246
  </details>
255
247
 
256
- <details><summary><strong>Generation</strong> (8)</summary>
248
+ <details><summary><strong>Generation</strong> (3)</summary>
257
249
 
258
250
  | Tool | Description |
259
251
  |------|-------------|
260
- | `compose` | Generate, write, and play a complete pattern in one step. Auto-initializes browser if needed. |
261
- | `generate_pattern` | Generate complete pattern from style with optional auto-play |
262
- | `generate_drums` | Generate drum pattern |
263
- | `generate_bassline` | Generate bassline |
264
- | `generate_melody` | Generate melody from scale |
265
- | `generate_polyrhythm` | Generate polyrhythm |
266
- | `generate_fill` | Generate drum fill |
267
- | `generate_variation` | Create pattern variations |
252
+ | `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. |
268
255
 
269
256
  </details>
270
257
 
271
- <details><summary><strong>Music Theory</strong> (4)</summary>
258
+ <details><summary><strong>Music Theory</strong> (1)</summary>
272
259
 
273
260
  | Tool | Description |
274
261
  |------|-------------|
275
- | `generate_scale` | Generate scale notes |
276
- | `generate_chord_progression` | Generate chord progression |
277
- | `generate_euclidean` | Generate Euclidean rhythm |
278
- | `apply_scale` | Apply scale to notes |
262
+ | `music_theory` | Music-theory queries. |
279
263
 
280
264
  </details>
281
265
 
282
- <details><summary><strong>Transform</strong> (9)</summary>
266
+ <details><summary><strong>Transform</strong> (3)</summary>
283
267
 
284
268
  | Tool | Description |
285
269
  |------|-------------|
286
- | `transpose` | Transpose notes by semitones |
287
- | `reverse` | Reverse pattern |
288
- | `stretch` | Time stretch pattern |
289
- | `quantize` | Quantize to grid |
290
- | `humanize` | Add human timing variation |
291
- | `add_effect` | Add effect to pattern |
292
- | `remove_effect` | Remove effect |
293
- | `add_swing` | Add swing to pattern |
294
- | `set_energy` | Adjust the overall energy level of the current pattern on a 0-10 scale. 0: minimal/ambient, 1-2: sparse, 3-4: light/relaxed, 5-6: normal/moderate, 7-8: driving/intense, 9-10: maximum. Auto-plays after applying energy level. |
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. |
295
273
 
296
274
  </details>
297
275
 
298
- <details><summary><strong>AI</strong> (4)</summary>
276
+ <details><summary><strong>AI</strong> (1)</summary>
299
277
 
300
278
  | Tool | Description |
301
279
  |------|-------------|
302
- | `get_pattern_feedback` | Get AI-powered creative feedback on the current pattern using Google Gemini. Analyzes pattern structure and optionally audio. |
303
- | `jam_with` | AI generates a complementary layer to jam with your pattern. Analyzes current pattern to detect tempo, key, and existing layers, then generates a matching layer that fits musically. |
304
- | `shift_mood` | Transform current pattern to match a different emotional mood by adjusting tempo, effects, and note choices. Moods: dark, euphoric, melancholic, aggressive, dreamy, peaceful, energetic. |
305
- | `refine` | Incrementally refine the current pattern with simple directional commands. Supports: faster/slower (tempo), louder/quieter (gain), brighter/darker (filter cutoff), "more reverb"/drier (reverb). Auto-plays after applying refinement. |
280
+ | `ai_assist` | Gemini-backed pattern assistance. |
306
281
 
307
282
  </details>
308
283
 
309
- <details><summary><strong>Analysis</strong> (7)</summary>
284
+ <details><summary><strong>Analysis</strong> (6)</summary>
310
285
 
311
286
  | Tool | Description |
312
287
  |------|-------------|
313
- | `analyze` | Complete audio analysis |
314
- | `analyze_spectrum` | FFT spectrum analysis |
315
- | `analyze_rhythm` | Rhythm analysis |
316
- | `detect_tempo` | BPM detection |
317
- | `detect_key` | Key detection |
288
+ | `analyze` | Audio analysis on the currently-playing pattern. |
318
289
  | `validate_pattern_runtime` | Validate pattern with runtime error checking (monitors Strudel console for errors) |
319
- | `compare_patterns` | Compare two patterns from history showing differences |
290
+ | `validate_pattern_local` | Validate pattern syntax against the in-process StrudelEngine (no browser required) |
291
+ | `analyze_pattern_local` | Static analysis (events/cycle, complexity, optional BPM) without browser playback |
292
+ | `query_pattern_events` | Enumerate events the pattern would emit between two cycle indices (max 16 cycles) |
293
+ | `transpile_pattern` | Transpile pattern source via StrudelEngine; returns transpiled code or syntax error |
320
294
 
321
295
  </details>
322
296
 
323
- <details><summary><strong>Session</strong> (4)</summary>
297
+ <details><summary><strong>Session</strong> (1)</summary>
324
298
 
325
299
  | Tool | Description |
326
300
  |------|-------------|
327
- | `create_session` | Create a new isolated Strudel browser session. Sessions share one browser but have isolated contexts. |
328
- | `destroy_session` | Close and destroy a Strudel session, releasing its resources. |
329
- | `list_sessions` | List all active Strudel sessions with their metadata. |
330
- | `switch_session` | Change the default session used by other tools. |
301
+ | `session` | Manage isolated Strudel browser sessions (multi-session, #108). |
331
302
 
332
303
  </details>
333
304
 
@@ -336,41 +307,27 @@ Then ask Claude:
336
307
  | Tool | Description |
337
308
  |------|-------------|
338
309
  | `export_midi` | Export current pattern to MIDI file. Parses note(), n(), and chord() functions. |
339
- | `screenshot` | Take a screenshot of the current Strudel editor state |
340
-
341
- </details>
342
-
343
- <details><summary><strong>Audio</strong> (3)</summary>
344
-
345
- | Tool | Description |
346
- |------|-------------|
347
- | `start_audio_capture` | Start capturing audio from Strudel output. Audio must be playing for capture to work. |
348
- | `stop_audio_capture` | Stop audio capture and return the recorded audio as base64-encoded data. |
349
- | `capture_audio_sample` | Capture a fixed-duration audio sample from Strudel output. Audio must be playing. |
310
+ | `browser_window` | Interact with the visible Strudel browser window. |
350
311
 
351
312
  </details>
352
313
 
353
- <details><summary><strong>Debug</strong> (5)</summary>
314
+ <details><summary><strong>Audio</strong> (1)</summary>
354
315
 
355
316
  | Tool | Description |
356
317
  |------|-------------|
357
- | `show_browser` | Bring browser window to foreground for visual feedback |
358
- | `performance_report` | Get performance metrics and bottlenecks |
359
- | `memory_usage` | Get current memory usage statistics |
360
- | `diagnostics` | Get detailed browser diagnostics including cache, errors, and performance |
361
- | `show_errors` | Display captured console errors and warnings from Strudel |
318
+ | `audio_capture` | Record audio output from the live Strudel session. |
362
319
 
363
320
  </details>
364
321
 
365
- <details><summary><strong>Other</strong> (1)</summary>
322
+ <details><summary><strong>Debug</strong> (1)</summary>
366
323
 
367
324
  | Tool | Description |
368
325
  |------|-------------|
369
- | `suggest_pattern_from_audio` | Analyze the currently playing audio and suggest a complementary Strudel pattern using Gemini AI. Extracts tempo, key, and spectral features locally, then uses AI to generate a matching pattern. Returns pattern text (not auto-executed). |
326
+ | `diagnostics` | Inspect server and browser state. |
370
327
 
371
328
  </details>
372
329
 
373
- _Auto-generated from source. 66 tools registered._
330
+ _Auto-generated from source. 26 tools registered._
374
331
 
375
332
  <!-- TOOLS:END -->
376
333
 
@@ -657,14 +614,15 @@ The Strudel MCP Server is built with a modular architecture that separates conce
657
614
 
658
615
  ### Core Components
659
616
 
660
- #### 1. **StrudelMCPServer** (`src/server/server.ts`)
617
+ #### 1. **StrudelMCPServer** (`src/server/server.ts`, ~510 lines)
661
618
 
662
- Main MCP server implementation handling:
663
- - **65 Tool Definitions**: Complete API surface for music control
664
- - **Request Routing**: Directs tool calls to appropriate handlers
665
- - **State Management**: Tracks initialization, undo/redo stacks, pattern cache
666
- - **Error Handling**: Graceful degradation and informative error messages
667
- - **Lazy Initialization**: Browser starts only when needed
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
668
626
 
669
627
  Key Features:
670
628
  ```typescript
@@ -769,28 +727,42 @@ Persistent pattern storage:
769
727
  live-coding-music-mcp/
770
728
  ├── src/
771
729
  │ ├── server/
772
- │ │ └── server.ts # MCP 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
773
737
  │ ├── services/
774
- │ │ ├── MusicTheory.ts # Theory engine
775
- │ │ └── PatternGenerator.ts # Pattern creation
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)
776
746
  │ ├── utils/
777
- │ │ └── Logger.ts # Logging utility
778
- │ ├── types/
779
- │ │ └── index.ts # TypeScript types
780
- │ ├── StrudelController.ts # Browser automation
781
- │ ├── AudioAnalyzer.ts # Audio analysis
782
- │ ├── PatternStore.ts # Pattern persistence
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
783
755
  │ └── index.ts # Entry point
784
- ├── tests/
785
- │ ├── browser-test.js # Browser integration
786
- │ ├── integration.test.js # Integration tests
787
- │ ├── manual-test.js # Manual testing
788
- │ ├── mcp-tools.test.ts # MCP tool tests
789
- │ └── strudel-integration.js # Full integration
790
- ├── patterns/ # Saved patterns
791
- ├── config.json # Server configuration
792
- ├── package.json # Dependencies
793
- └── tsconfig.json # TypeScript config
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
794
766
  ```
795
767
 
796
768
  ### Data Flow
@@ -956,102 +928,49 @@ gh release create v$(node -p "require('./package.json').version") --generate-not
956
928
 
957
929
  The package uses OIDC trusted publishing with provenance attestation for supply chain security.
958
930
 
959
- ### Project Structure
960
-
961
- ```
962
- src/
963
- ├── server/
964
- │ └── server.ts # MCP server
965
- │
966
- ├── services/
967
- │ ├── MusicTheory.ts # Music theory engine
968
- │ │ - 15+ scales (major, minor, modes, etc.)
969
- │ │ - Chord progressions (jazz, pop, blues, etc.)
970
- │ │ - Euclidean rhythm generation
971
- │ │ - Arpeggio generation
972
- │ │
973
- │ └── PatternGenerator.ts # Pattern creation service
974
- │ - Genre-specific drum patterns
975
- │ - Bassline generation
976
- │ - Melody composition
977
- │ - Pattern variations
978
- │ - Complete track generation
979
- │
980
- ├── utils/
981
- │ ├── Logger.ts # Logging utility
982
- │ ├── PerformanceMonitor.ts # Performance tracking
983
- │ ├── PatternValidator.ts # Pattern syntax validation
984
- │ └── ErrorRecovery.ts # Error handling & recovery
985
- │
986
- ├── types/
987
- │ └── index.ts # TypeScript type definitions
988
- │
989
- ├── StrudelController.ts # Browser automation
990
- │ - Chromium management via Playwright
991
- │ - CodeMirror editor manipulation
992
- │ - Playback control
993
- │ - Pattern validation
994
- │ - Error recovery
995
- │
996
- ├── AudioAnalyzer.ts # Real-time audio analysis
997
- │ - Web Audio API injection
998
- │ - FFT spectral analysis
999
- │ - Frequency band detection
1000
- │ - Playing state monitoring
1001
- │
1002
- ├── PatternStore.ts # Pattern persistence
1003
- │ - JSON-based storage
1004
- │ - Tag-based organization
1005
- │ - Metadata tracking
1006
- │ - List caching
1007
- │
1008
- └── index.ts # Application entry point
1009
- ```
1010
-
1011
- ### Adding New Tools
1012
-
1013
- To add a new MCP tool:
1014
-
1015
- 1. **Define the tool** in `getTools()` method:
1016
- ```typescript
1017
- {
1018
- name: 'my_new_tool',
1019
- description: 'Description of what it does',
1020
- inputSchema: {
1021
- type: 'object',
1022
- properties: {
1023
- param1: { type: 'string', description: 'Parameter description' },
1024
- param2: { type: 'number', description: 'Numeric parameter' }
1025
- },
1026
- required: ['param1']
1027
- }
1028
- }
1029
- ```
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
+ ```
1030
954
 
1031
- 2. **Implement the handler** in `executeTool()` switch statement:
1032
- ```typescript
1033
- case 'my_new_tool':
1034
- // Your implementation here
1035
- return await this.someService.doSomething(args.param1, args.param2);
1036
- ```
955
+ 2. **Add the case** to the module's `execute()` switch:
1037
956
 
1038
- 3. **Add necessary service methods** if needed:
1039
- ```typescript
1040
- // In appropriate service file
1041
- async doSomething(param1: string, param2?: number): Promise<string> {
1042
- // Implementation
1043
- return `Result: ${param1}`;
1044
- }
1045
- ```
957
+ ```typescript
958
+ case 'my_new_tool':
959
+ return await ctx.getController(args.session_id).doSomething(args.param1);
960
+ ```
1046
961
 
1047
- 4. **Test the tool**:
1048
- ```bash
1049
- # Build
1050
- npm run build
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.
1051
963
 
1052
- # Test via MCP
1053
- echo '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"my_new_tool","arguments":{"param1":"test"}},"id":2}' | node dist/index.js
1054
- ```
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
+ ```
1055
974
 
1056
975
  ### Testing Strategy
1057
976
 
@@ -1074,7 +993,7 @@ npm run test:integration
1074
993
  # - Pattern generation
1075
994
  # - Audio analysis
1076
995
  # - Pattern storage
1077
- # - All 65 tools
996
+ # - All 84 registered tools
1078
997
  ```
1079
998
 
1080
999
  #### 3. Manual Testing
@@ -1289,12 +1208,19 @@ SMOOTHING=0.8
1289
1208
 
1290
1209
  ## Performance
1291
1210
 
1292
- - **Pattern Generation**: <100ms
1293
- - **Browser Initialization**: ~3 seconds
1294
- - **Pattern Writing**: Instant
1295
- - **Playback Start**: ~500ms
1296
- - **Audio Analysis**: Real-time
1297
- - **Memory Usage**: <150MB
1211
+ Measured against the current `StrudelController` cache + Strudel.cc on a developer machine:
1212
+
1213
+ | Operation | Latency |
1214
+ |---|---|
1215
+ | Browser initialization | 1.5–2 s (with resource blocking) |
1216
+ | Pattern write | 50–80 ms (cached CodeMirror editor access) |
1217
+ | Pattern read (cached) | 10–15 ms |
1218
+ | Play / pause / stop | 100–150 ms |
1219
+ | 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) |
1222
+ | Pattern generation | <100 ms (template-based) |
1223
+ | Process resident memory | ~120–150 MB |
1298
1224
 
1299
1225
  ## Advanced Usage
1300
1226
 
@@ -1555,7 +1481,7 @@ npm run build
1555
1481
  # Check if server responds
1556
1482
  echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node dist/index.js
1557
1483
 
1558
- # Should return JSON with 65 tools
1484
+ # Should return JSON with 26 tools
1559
1485
 
1560
1486
  # Reinstall MCP server in Claude
1561
1487
  claude mcp remove strudel
@@ -1734,6 +1660,6 @@ Earlier versions of this package (including `@williamzujkowski/strudel-mcp-serve
1734
1660
 
1735
1661
  ---
1736
1662
 
1737
- **v2.4.0** - Open Source | Experimental | [Report Issues](https://github.com/williamzujkowski/live-coding-music-mcp/issues) | [Contribute](https://github.com/williamzujkowski/live-coding-music-mcp/pulls)
1663
+ **v4.0.0** — Open source, AGPL-3.0-or-later, experimental | [Report issues](https://github.com/williamzujkowski/live-coding-music-mcp/issues) | [Contribute](https://github.com/williamzujkowski/live-coding-music-mcp/pulls)
1738
1664
 
1739
1665
  *This project is under active development. Core features work, but expect bugs and breaking changes. Not recommended for production use.*
@@ -625,7 +625,6 @@ export class AudioAnalyzer {
625
625
  return 0;
626
626
  let syncopationScore = 0;
627
627
  for (let i = 1; i < onsets.length; i++) {
628
- const interval = onsets[i] - onsets[i - 1];
629
628
  const phase = (onsets[i] % (meanInterval * 4)) / meanInterval;
630
629
  // Check if onset is on an off-beat (not on 0, 1, 2, 3)
631
630
  const nearestBeat = Math.round(phase);
@@ -99,7 +99,6 @@ export class PatternStore {
99
99
  }
100
100
  try {
101
101
  const files = await fs.readdir(this.basePath);
102
- const patterns = [];
103
102
  // Parallel file reading for better performance
104
103
  const readPromises = files
105
104
  .filter(file => file.endsWith('.json'))
package/dist/index.js CHANGED
File without changes