@williamzujkowski/live-coding-music-mcp 3.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.
- package/README.md +212 -780
- package/dist/AudioAnalyzer.js +1294 -91
- package/dist/PatternStore.js +276 -23
- package/dist/StrudelController.js +388 -56
- package/dist/server/resources.js +27 -20
- package/dist/server/server.js +391 -83
- package/dist/server/tools/ai.js +129 -152
- package/dist/server/tools/analysis.js +170 -91
- package/dist/server/tools/capture.js +128 -55
- package/dist/server/tools/compose.js +28 -42
- package/dist/server/tools/diagnostics.js +23 -53
- package/dist/server/tools/editor.js +63 -72
- package/dist/server/tools/generate.js +45 -167
- package/dist/server/tools/history.js +35 -66
- package/dist/server/tools/playback.js +7 -22
- package/dist/server/tools/session.js +41 -47
- package/dist/server/tools/storage.js +173 -50
- package/dist/server/tools/transform.js +136 -199
- package/dist/server/tools/types.js +209 -14
- package/dist/services/AudioCaptureService.js +302 -33
- package/dist/services/AudioExportService.js +318 -0
- package/dist/services/BrowserOnlyFunctions.js +149 -0
- package/dist/services/EventDensityProbe.js +324 -0
- package/dist/services/GeminiService.js +221 -36
- package/dist/services/IsolatedEngineRunner.js +308 -0
- package/dist/services/IsolatedStrudelEngine.js +135 -0
- package/dist/services/LocalPatternEngine.js +16 -0
- package/dist/services/MIDIExportService.js +765 -71
- package/dist/services/MIDIImportService.js +474 -0
- package/dist/services/MusicTheory.js +85 -13
- package/dist/services/PatternGenerator.js +168 -85
- package/dist/services/PatternSandbox.js +359 -0
- package/dist/services/SessionManager.js +338 -65
- package/dist/services/StrudelEngine.js +218 -12
- package/dist/services/StrudelEngineHelpers.js +24 -8
- package/dist/services/StyleRegistry.js +204 -0
- package/dist/services/Transferable.js +114 -0
- package/dist/services/ai/AiTransport.js +56 -0
- package/dist/services/ai/AudioMeasurements.js +155 -0
- package/dist/services/ai/CliTransport.js +256 -0
- package/dist/services/engineChild.js +83 -0
- package/dist/services/engineChildPath.js +28 -0
- package/dist/utils/CategorisedError.js +59 -0
- package/dist/utils/ErrorRecovery.js +130 -110
- package/dist/utils/InputValidator.js +55 -7
- package/dist/utils/PatternValidator.js +136 -17
- package/dist/utils/SafePath.js +112 -0
- package/dist/utils/ServerConfig.js +248 -0
- package/dist/utils/TableLookup.js +41 -0
- package/dist/utils/Tempo.js +143 -0
- package/package.json +17 -5
- package/dist/services/__mocks__/StrudelEngine.js +0 -157
- 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 |
|
|
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
|
[](https://github.com/williamzujkowski/live-coding-music-mcp/actions)
|
|
14
14
|
[](https://www.npmjs.com/package/@williamzujkowski/live-coding-music-mcp)
|
|
15
15
|
[](https://nerq.ai/kya/live-coding-music-mcp)
|
|
16
|
-
[]()
|
|
17
17
|
[](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 →
|
|
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
|
-
###
|
|
48
|
-
- **
|
|
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**:
|
|
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
|
-
###
|
|
59
|
-
-
|
|
60
|
-
|
|
61
|
-
- **
|
|
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 [
|
|
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
|
-
###
|
|
68
|
+
### Example patterns
|
|
67
69
|
|
|
68
|
-
|
|
70
|
+
7 example patterns ship in [`patterns/examples/`](patterns/examples/), grouped by genre:
|
|
69
71
|
|
|
70
|
-
- **
|
|
71
|
-
- **
|
|
72
|
-
- **
|
|
73
|
-
- **
|
|
74
|
-
- **
|
|
75
|
-
- **
|
|
76
|
-
- **
|
|
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
|
|
234
|
+
Common operations as one-line tool calls:
|
|
157
235
|
|
|
158
236
|
| Action | Tool call |
|
|
159
237
|
|---|---|
|
|
@@ -169,39 +247,18 @@ Common commands for immediate use:
|
|
|
169
247
|
| Edit current pattern | `edit_pattern({ mode: "write", pattern: "..." })` |
|
|
170
248
|
| Create an isolated session | `session({ action: "create", session_id: "live-1" })` |
|
|
171
249
|
|
|
172
|
-
The legacy single-verb tools (`play`, `stop`, `save`, `undo`, `write`, `generate_pattern`, ...)
|
|
250
|
+
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.
|
|
173
251
|
|
|
174
252
|
**One-shot workflow:**
|
|
175
253
|
```
|
|
176
|
-
compose with style: "dnb", key: "Am",
|
|
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
|
-
**
|
|
261
|
+
**28 tools** across 15 categories:
|
|
205
262
|
|
|
206
263
|
<details><summary><strong>Setup</strong> (1)</summary>
|
|
207
264
|
|
|
@@ -211,127 +268,95 @@ Then ask Claude:
|
|
|
211
268
|
|
|
212
269
|
</details>
|
|
213
270
|
|
|
214
|
-
<details><summary><strong>Pattern Editing</strong> (
|
|
271
|
+
<details><summary><strong>Pattern Editing</strong> (2)</summary>
|
|
215
272
|
|
|
216
273
|
| Tool | Description |
|
|
217
274
|
|------|-------------|
|
|
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. |
|
|
218
276
|
| `get_pattern` | Get current pattern code |
|
|
219
|
-
| `write` | [DEPRECATED — use edit_pattern({ mode: "write" }) instead] Write pattern to editor with optional auto-play and validation |
|
|
220
|
-
| `append` | [DEPRECATED — use edit_pattern({ mode: "append" }) instead] Append code to current pattern |
|
|
221
|
-
| `insert` | [DEPRECATED — use edit_pattern({ mode: "insert" }) instead] Insert code at specific line |
|
|
222
|
-
| `replace` | [DEPRECATED — use edit_pattern({ mode: "replace" }) instead] Replace pattern section |
|
|
223
277
|
|
|
224
278
|
</details>
|
|
225
279
|
|
|
226
|
-
<details><summary><strong>Playback</strong> (
|
|
280
|
+
<details><summary><strong>Playback</strong> (2)</summary>
|
|
227
281
|
|
|
228
282
|
| Tool | Description |
|
|
229
283
|
|------|-------------|
|
|
230
|
-
| `
|
|
231
|
-
| `
|
|
232
|
-
| `play` | [DEPRECATED — use playback({ action: "play" }) instead] Start playing pattern |
|
|
233
|
-
| `pause` | [DEPRECATED — use playback({ action: "pause" }) instead] Pause playback |
|
|
234
|
-
| `stop` | [DEPRECATED — use playback({ action: "stop" }) instead] Stop playback |
|
|
235
|
-
| `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. |
|
|
236
286
|
|
|
237
287
|
</details>
|
|
238
288
|
|
|
239
|
-
<details><summary><strong>Storage</strong> (
|
|
289
|
+
<details><summary><strong>Storage</strong> (2)</summary>
|
|
240
290
|
|
|
241
291
|
| Tool | Description |
|
|
242
292
|
|------|-------------|
|
|
243
|
-
| `
|
|
244
|
-
| `
|
|
245
|
-
| `list` | [DEPRECATED — use pattern_store({ action: "list" }) instead] List saved patterns |
|
|
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. |
|
|
246
295
|
|
|
247
296
|
</details>
|
|
248
297
|
|
|
249
|
-
<details><summary><strong>History</strong> (
|
|
298
|
+
<details><summary><strong>History</strong> (1)</summary>
|
|
250
299
|
|
|
251
300
|
| Tool | Description |
|
|
252
301
|
|------|-------------|
|
|
253
|
-
| `
|
|
254
|
-
| `redo` | [DEPRECATED — use history({ action: "redo" }) instead] Redo action |
|
|
255
|
-
| `list_history` | [DEPRECATED — use history({ action: "list" }) instead] List recent pattern history with timestamps and previews |
|
|
256
|
-
| `restore_history` | [DEPRECATED — use history({ action: "restore" }) instead] Restore a previous pattern from history by ID |
|
|
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. |
|
|
257
303
|
|
|
258
304
|
</details>
|
|
259
305
|
|
|
260
|
-
<details><summary><strong>Generation</strong> (
|
|
306
|
+
<details><summary><strong>Generation</strong> (3)</summary>
|
|
261
307
|
|
|
262
308
|
| Tool | Description |
|
|
263
309
|
|------|-------------|
|
|
264
310
|
| `compose` | Generate, write, and play a complete pattern in one step. Auto-initializes default browser if needed. |
|
|
265
|
-
| `
|
|
266
|
-
| `
|
|
267
|
-
| `generate_bassline` | [DEPRECATED — use generate_part({ role: "bass" }) instead] Generate bassline |
|
|
268
|
-
| `generate_melody` | [DEPRECATED — use generate_part({ role: "melody" }) instead] Generate melody from scale |
|
|
269
|
-
| `generate_polyrhythm` | [DEPRECATED — use generate_rhythm({ type: "polyrhythm" }) instead] Generate polyrhythm |
|
|
270
|
-
| `generate_fill` | [DEPRECATED — use generate_part({ role: "fill" }) instead] Generate drum fill |
|
|
271
|
-
| `generate_variation` | [DEPRECATED — use transform({ op: "vary" }) instead] Create pattern variations (mis-named today; it transforms, not generates) |
|
|
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. |
|
|
272
313
|
|
|
273
314
|
</details>
|
|
274
315
|
|
|
275
|
-
<details><summary><strong>Music Theory</strong> (
|
|
316
|
+
<details><summary><strong>Music Theory</strong> (1)</summary>
|
|
276
317
|
|
|
277
318
|
| Tool | Description |
|
|
278
319
|
|------|-------------|
|
|
279
|
-
| `
|
|
280
|
-
| `generate_chord_progression` | [DEPRECATED — use music_theory({ query: "chord_progression" }) instead] Generate chord progression |
|
|
281
|
-
| `generate_euclidean` | [DEPRECATED — use generate_rhythm({ type: "euclidean" }) instead] Generate Euclidean rhythm |
|
|
282
|
-
| `apply_scale` | [DEPRECATED — use transform({ op: "scale" }) instead] Apply scale to notes |
|
|
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. |
|
|
283
321
|
|
|
284
322
|
</details>
|
|
285
323
|
|
|
286
|
-
<details><summary><strong>Transform</strong> (
|
|
324
|
+
<details><summary><strong>Transform</strong> (3)</summary>
|
|
287
325
|
|
|
288
326
|
| Tool | Description |
|
|
289
327
|
|------|-------------|
|
|
290
|
-
| `
|
|
291
|
-
| `
|
|
292
|
-
| `
|
|
293
|
-
| `quantize` | [DEPRECATED — use transform({ op: "quantize" }) instead] Quantize to grid |
|
|
294
|
-
| `humanize` | [DEPRECATED — use transform({ op: "humanize" }) instead] Add human timing variation |
|
|
295
|
-
| `add_effect` | [DEPRECATED — use effect({ action: "add" }) instead] Add effect to pattern |
|
|
296
|
-
| `remove_effect` | [DEPRECATED — use effect({ action: "remove" }) instead] Remove effect |
|
|
297
|
-
| `add_swing` | [DEPRECATED — use transform({ op: "swing" }) instead] Add swing to pattern |
|
|
298
|
-
| `set_energy` | [DEPRECATED — use shape({ dimension: "energy" }) instead] Adjust energy level 0-10. Auto-plays after applying. |
|
|
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. |
|
|
299
331
|
|
|
300
332
|
</details>
|
|
301
333
|
|
|
302
|
-
<details><summary><strong>AI</strong> (
|
|
334
|
+
<details><summary><strong>AI</strong> (1)</summary>
|
|
303
335
|
|
|
304
336
|
| Tool | Description |
|
|
305
337
|
|------|-------------|
|
|
306
|
-
| `
|
|
307
|
-
| `jam_with` | [DEPRECATED — use ai_assist({ task: "jam" }) instead] AI generates a complementary layer to jam with your pattern. |
|
|
308
|
-
| `shift_mood` | [DEPRECATED — use shape({ dimension: "mood" }) instead] Transform current pattern to match a different emotional mood. Moods: dark, euphoric, melancholic, aggressive, dreamy, peaceful, energetic. |
|
|
309
|
-
| `refine` | [DEPRECATED — use shape({ dimension: "refine" }) instead] Incrementally refine current pattern: faster/slower/louder/quieter/brighter/darker/"more reverb"/drier. |
|
|
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. |
|
|
310
339
|
|
|
311
340
|
</details>
|
|
312
341
|
|
|
313
|
-
<details><summary><strong>Analysis</strong> (
|
|
342
|
+
<details><summary><strong>Analysis</strong> (6)</summary>
|
|
314
343
|
|
|
315
344
|
| Tool | Description |
|
|
316
345
|
|------|-------------|
|
|
317
|
-
| `analyze` | Audio analysis on the currently-playing pattern.
|
|
318
|
-
| `analyze_spectrum` | [DEPRECATED — use analyze({ include: ["spectrum"] }) instead] FFT spectrum analysis |
|
|
319
|
-
| `analyze_rhythm` | [DEPRECATED — use analyze({ include: ["rhythm"] }) instead] Rhythm analysis |
|
|
320
|
-
| `detect_tempo` | [DEPRECATED — use analyze({ include: ["tempo"] }) instead] BPM detection |
|
|
321
|
-
| `detect_key` | [DEPRECATED — use analyze({ include: ["key"] }) instead] Key detection |
|
|
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. |
|
|
322
347
|
| `validate_pattern_runtime` | Validate pattern with runtime error checking (monitors Strudel console for errors) |
|
|
323
|
-
| `
|
|
348
|
+
| `validate_pattern_local` | Validate pattern syntax against the local StrudelEngine, which runs in a sandboxed child process (no browser required) |
|
|
349
|
+
| `analyze_pattern_local` | Static analysis (events/cycle, complexity, optional BPM) without browser playback |
|
|
350
|
+
| `query_pattern_events` | Enumerate events the pattern would emit between two cycle indices (max 16 cycles) |
|
|
351
|
+
| `transpile_pattern` | Transpile pattern source via StrudelEngine; returns transpiled code or syntax error |
|
|
324
352
|
|
|
325
353
|
</details>
|
|
326
354
|
|
|
327
|
-
<details><summary><strong>Session</strong> (
|
|
355
|
+
<details><summary><strong>Session</strong> (1)</summary>
|
|
328
356
|
|
|
329
357
|
| Tool | Description |
|
|
330
358
|
|------|-------------|
|
|
331
|
-
| `
|
|
332
|
-
| `destroy_session` | [DEPRECATED — use session({ action: "destroy" }) instead] Close and destroy a Strudel session. |
|
|
333
|
-
| `list_sessions` | [DEPRECATED — use session({ action: "list" }) instead] List all active Strudel sessions. |
|
|
334
|
-
| `switch_session` | [DEPRECATED — use session({ action: "switch" }) instead] Change the default session. |
|
|
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. |
|
|
335
360
|
|
|
336
361
|
</details>
|
|
337
362
|
|
|
@@ -340,59 +365,35 @@ Then ask Claude:
|
|
|
340
365
|
| Tool | Description |
|
|
341
366
|
|------|-------------|
|
|
342
367
|
| `export_midi` | Export current pattern to MIDI file. Parses note(), n(), and chord() functions. |
|
|
343
|
-
| `
|
|
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. |
|
|
344
369
|
|
|
345
370
|
</details>
|
|
346
371
|
|
|
347
|
-
<details><summary><strong>Audio</strong> (
|
|
372
|
+
<details><summary><strong>Audio</strong> (1)</summary>
|
|
348
373
|
|
|
349
374
|
| Tool | Description |
|
|
350
375
|
|------|-------------|
|
|
351
|
-
| `
|
|
352
|
-
| `stop_audio_capture` | [DEPRECATED — use audio_capture({ action: "stop" }) instead] Stop audio capture and return base64-encoded audio. |
|
|
353
|
-
| `capture_audio_sample` | [DEPRECATED — use audio_capture({ action: "sample" }) instead] Capture a fixed-duration audio sample. |
|
|
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). |
|
|
354
377
|
|
|
355
378
|
</details>
|
|
356
379
|
|
|
357
|
-
<details><summary><strong>Debug</strong> (
|
|
380
|
+
<details><summary><strong>Debug</strong> (1)</summary>
|
|
358
381
|
|
|
359
382
|
| Tool | Description |
|
|
360
383
|
|------|-------------|
|
|
361
|
-
| `
|
|
362
|
-
| `diagnostics` | Inspect server and browser state. |
|
|
363
|
-
| `show_errors` | [DEPRECATED — use diagnostics({ level: "errors" }) instead] Display captured console errors and warnings from Strudel |
|
|
364
|
-
| `performance_report` | [DEPRECATED — use diagnostics({ level: "perf" }) instead] Get performance metrics and bottlenecks |
|
|
365
|
-
| `memory_usage` | [DEPRECATED — use diagnostics({ level: "memory" }) instead] Get current memory usage statistics |
|
|
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. |
|
|
366
385
|
|
|
367
386
|
</details>
|
|
368
387
|
|
|
369
|
-
<details><summary><strong>Other</strong> (
|
|
388
|
+
<details><summary><strong>Other</strong> (1)</summary>
|
|
370
389
|
|
|
371
390
|
| Tool | Description |
|
|
372
391
|
|------|-------------|
|
|
373
|
-
| `
|
|
374
|
-
| `suggest_pattern_from_audio` | [DEPRECATED — use ai_assist({ task: "suggest" }) instead] Analyze playing audio and suggest a complementary Strudel pattern. |
|
|
375
|
-
| `validate_pattern_local` | Validate pattern syntax against the in-process StrudelEngine (no browser required) |
|
|
376
|
-
| `analyze_pattern_local` | Static analysis (events/cycle, complexity, optional BPM) without browser playback |
|
|
377
|
-
| `query_pattern_events` | Enumerate events the pattern would emit between two cycle indices (max 16 cycles) |
|
|
378
|
-
| `transpile_pattern` | Transpile pattern source via StrudelEngine; returns transpiled code or syntax error |
|
|
379
|
-
| `audio_capture` | Record audio output from the live Strudel session. |
|
|
380
|
-
| `browser_window` | Interact with the visible Strudel browser window. |
|
|
381
|
-
| `edit_pattern` | Mutate the current session pattern. |
|
|
382
|
-
| `generate_part` | Generate a single instrumental layer and append it to the current session pattern. |
|
|
383
|
-
| `music_theory` | Music-theory queries. |
|
|
384
|
-
| `generate_rhythm` | Generate a rhythmic pattern and append it to the current session. |
|
|
385
|
-
| `history` | Navigate or inspect the pattern edit history. |
|
|
386
|
-
| `playback` | Control transport on the current session. |
|
|
387
|
-
| `session` | Manage isolated Strudel browser sessions (multi-session, #108). |
|
|
388
|
-
| `pattern_store` | Persist patterns to disk and read them back. |
|
|
389
|
-
| `transform` | Apply a single transform op to the current session pattern. |
|
|
390
|
-
| `effect` | Add or remove a Strudel effect on the current session pattern. |
|
|
391
|
-
| `shape` | Shape the current pattern along one of three high-level dimensions. |
|
|
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" }). |
|
|
392
393
|
|
|
393
394
|
</details>
|
|
394
395
|
|
|
395
|
-
_Auto-generated from source.
|
|
396
|
+
_Auto-generated from source. 28 tools registered._
|
|
396
397
|
|
|
397
398
|
<!-- TOOLS:END -->
|
|
398
399
|
|
|
@@ -409,7 +410,7 @@ Claude: [Initializes browser]
|
|
|
409
410
|
[Starts playback]
|
|
410
411
|
|
|
411
412
|
Pattern created:
|
|
412
|
-
setcpm(130)
|
|
413
|
+
setcpm(130/4)
|
|
413
414
|
stack(
|
|
414
415
|
s("bd*4"),
|
|
415
416
|
s("~ cp ~ cp"),
|
|
@@ -449,7 +450,7 @@ You: Generate a complete drum & bass track at 174 BPM
|
|
|
449
450
|
Claude: [Creates multi-layer pattern with drums, bass, and pads]
|
|
450
451
|
|
|
451
452
|
// dnb pattern in C at 174 BPM
|
|
452
|
-
setcpm(174)
|
|
453
|
+
setcpm(174/4)
|
|
453
454
|
stack(
|
|
454
455
|
// Drums
|
|
455
456
|
s("bd ~ ~ [bd bd] ~ ~ bd ~, ~ ~ cp ~ ~ cp ~ ~").fast(2),
|
|
@@ -504,7 +505,7 @@ You: Create an ambient soundscape with multiple layers
|
|
|
504
505
|
|
|
505
506
|
Claude: [Generates complex multi-layer pattern]
|
|
506
507
|
|
|
507
|
-
setcpm(90)
|
|
508
|
+
setcpm(90/4)
|
|
508
509
|
stack(
|
|
509
510
|
// Deep bass drone
|
|
510
511
|
note("c1").s("sine").attack(4).release(8).gain(0.5),
|
|
@@ -600,7 +601,7 @@ note("c4 eb4 g4 bb4 c5").struct("1 1 1 1 1 1 1 1")
|
|
|
600
601
|
|
|
601
602
|
## Testing
|
|
602
603
|
|
|
603
|
-
|
|
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:
|
|
604
605
|
|
|
605
606
|
```bash
|
|
606
607
|
# Run integration tests
|
|
@@ -620,273 +621,46 @@ node tests/strudel-integration.js
|
|
|
620
621
|
"headless": false, // Set true for background operation
|
|
621
622
|
"strudel_url": "https://strudel.cc/",
|
|
622
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
|
|
623
627
|
"audio_analysis": {
|
|
624
|
-
"fft_size": 2048,
|
|
625
|
-
"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
|
|
626
630
|
}
|
|
627
631
|
}
|
|
628
632
|
```
|
|
629
633
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
The Strudel MCP Server is built with a modular architecture that separates concerns and enables robust music generation:
|
|
635
|
-
|
|
636
|
-
```
|
|
637
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
638
|
-
│ Claude AI │
|
|
639
|
-
│ (MCP Client) │
|
|
640
|
-
└───────────────────────┬─────────────────────────────────────┘
|
|
641
|
-
│ MCP Protocol (stdio)
|
|
642
|
-
│
|
|
643
|
-
┌───────────────────────▼─────────────────────────────────────┐
|
|
644
|
-
│ StrudelMCPServer │
|
|
645
|
-
│ ┌────────────────────────────────────────────────────────┐ │
|
|
646
|
-
│ │ Tool Request Handler │ │
|
|
647
|
-
│ │ - Validates inputs │ │
|
|
648
|
-
│ │ - Routes to appropriate service │ │
|
|
649
|
-
│ │ - Handles errors gracefully │ │
|
|
650
|
-
│ └────────────────────────────────────────────────────────┘ │
|
|
651
|
-
└───────┬────────────┬────────────┬───────────┬──────────────┘
|
|
652
|
-
│ │ │ │
|
|
653
|
-
┌────▼────┐ ┌───▼────┐ ┌───▼────┐ ┌──▼──────┐
|
|
654
|
-
│ Strudel │ │ Music │ │Pattern │ │ Pattern │
|
|
655
|
-
│Controller│ │ Theory │ │Generator│ │ Store │
|
|
656
|
-
└────┬────┘ └────────┘ └────────┘ └─────────┘
|
|
657
|
-
│
|
|
658
|
-
┌────▼────────────────────────────┐
|
|
659
|
-
│ Playwright Browser │
|
|
660
|
-
│ ┌──────────────────────────┐ │
|
|
661
|
-
│ │ Strudel.cc Website │ │
|
|
662
|
-
│ │ ┌────────────────────┐ │ │
|
|
663
|
-
│ │ │ CodeMirror Editor │ │ │
|
|
664
|
-
│ │ └────────────────────┘ │ │
|
|
665
|
-
│ │ ┌────────────────────┐ │ │
|
|
666
|
-
│ │ │ Audio Context │ │ │
|
|
667
|
-
│ │ │ + Web Audio API │ │ │
|
|
668
|
-
│ │ └────────┬───────────┘ │ │
|
|
669
|
-
│ └───────────┼──────────────┘ │
|
|
670
|
-
└──────────────┼──────────────────┘
|
|
671
|
-
│
|
|
672
|
-
┌───────▼────────┐
|
|
673
|
-
│ Audio Analyzer │
|
|
674
|
-
│ - FFT Analysis│
|
|
675
|
-
│ - Frequency │
|
|
676
|
-
│ - Spectral │
|
|
677
|
-
└────────────────┘
|
|
678
|
-
```
|
|
679
|
-
|
|
680
|
-
### Core Components
|
|
681
|
-
|
|
682
|
-
#### 1. **StrudelMCPServer** (`src/server/server.ts`, ~510 lines)
|
|
683
|
-
|
|
684
|
-
Thin MCP dispatcher that:
|
|
685
|
-
- Aggregates 84 tool definitions from the per-domain modules in `src/server/tools/` (84 = 26 consolidated tools + 58 deprecated aliases; -58 once #178 lands)
|
|
686
|
-
- Routes `tools/call` requests to the right module's `execute()`
|
|
687
|
-
- Wraps every response in the discriminated result envelope (`{ ok, errorCategory, isRetryable, ... }`)
|
|
688
|
-
- Tracks initialization, per-session history bundles, per-session audio capture services
|
|
689
|
-
- Advertises and serves MCP resources (`strudel://examples`, etc.)
|
|
690
|
-
- Lazy-initializes the default browser controller on first browser-touching call
|
|
691
|
-
|
|
692
|
-
Key Features:
|
|
693
|
-
```typescript
|
|
694
|
-
- Pattern caching before browser init
|
|
695
|
-
- Undo/redo stack management
|
|
696
|
-
- Session history tracking
|
|
697
|
-
- Generated pattern storage
|
|
698
|
-
- Safe fallback mechanisms
|
|
699
|
-
```
|
|
700
|
-
|
|
701
|
-
#### 2. **StrudelController** (`src/StrudelController.ts`)
|
|
702
|
-
|
|
703
|
-
Browser automation layer using Playwright:
|
|
704
|
-
- **Browser Management**: Chromium instance lifecycle
|
|
705
|
-
- **Editor Control**: CodeMirror manipulation via DOM
|
|
706
|
-
- **Playback Control**: Keyboard shortcuts for play/stop
|
|
707
|
-
- **Performance Optimizations**:
|
|
708
|
-
- Editor content caching (100ms TTL)
|
|
709
|
-
- Direct CodeMirror API access
|
|
710
|
-
- Resource blocking (images, fonts)
|
|
711
|
-
- Fast DOM content loading
|
|
712
|
-
|
|
713
|
-
```typescript
|
|
714
|
-
// Example: Optimized pattern writing
|
|
715
|
-
async writePattern(pattern: string) {
|
|
716
|
-
await this.page.evaluate((newPattern) => {
|
|
717
|
-
const editor = document.querySelector('.cm-content');
|
|
718
|
-
const view = editor.__view;
|
|
719
|
-
view.dispatch({
|
|
720
|
-
changes: { from: 0, to: view.state.doc.length, insert: newPattern }
|
|
721
|
-
});
|
|
722
|
-
}, pattern);
|
|
723
|
-
}
|
|
724
|
-
```
|
|
725
|
-
|
|
726
|
-
#### 3. **AudioAnalyzer** (`src/AudioAnalyzer.ts`)
|
|
727
|
-
|
|
728
|
-
Real-time audio analysis via Web Audio API injection:
|
|
729
|
-
- **FFT Analysis**: 1024-point FFT for spectral data
|
|
730
|
-
- **Frequency Bands**: Bass, low-mid, mid, high-mid, treble
|
|
731
|
-
- **Analysis Caching**: 50ms TTL for performance
|
|
732
|
-
- **Features Extracted**:
|
|
733
|
-
- Average amplitude
|
|
734
|
-
- Peak frequency
|
|
735
|
-
- Spectral centroid
|
|
736
|
-
- Playing state detection
|
|
737
|
-
- Frequency distribution
|
|
738
|
-
|
|
739
|
-
```typescript
|
|
740
|
-
Features provided:
|
|
741
|
-
- average: Overall amplitude (0-255)
|
|
742
|
-
- peak: Maximum amplitude
|
|
743
|
-
- peakFrequency: Dominant frequency in Hz
|
|
744
|
-
- bass/mid/treble: Band-specific amplitudes
|
|
745
|
-
- brightness: Timbral classification
|
|
746
|
-
- isPlaying: Boolean playback state
|
|
747
|
-
```
|
|
748
|
-
|
|
749
|
-
#### 4. **MusicTheory** (`src/services/MusicTheory.ts`)
|
|
750
|
-
|
|
751
|
-
Music theory engine providing:
|
|
752
|
-
- **15+ Scales**: Major, minor, modes, pentatonic, blues, whole-tone
|
|
753
|
-
- **Chord Progressions**: Pop, jazz, blues, rock, folk, EDM
|
|
754
|
-
- **Euclidean Rhythms**: Mathematical rhythm generation
|
|
755
|
-
- **Arpeggio Generation**: Multiple patterns (up, down, random)
|
|
756
|
-
- **Note Transposition**: Semitone-based pitch shifting
|
|
757
|
-
|
|
758
|
-
Supported scales:
|
|
759
|
-
```typescript
|
|
760
|
-
major, minor, dorian, phrygian, lydian, mixolydian,
|
|
761
|
-
aeolian, locrian, pentatonic, blues, chromatic,
|
|
762
|
-
wholetone, harmonic_minor, melodic_minor
|
|
763
|
-
```
|
|
764
|
-
|
|
765
|
-
#### 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.
|
|
766
637
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
- **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.
|
|
774
644
|
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
→ Multi-layer pattern with drums, bass, chords, melody
|
|
779
|
-
```
|
|
780
|
-
|
|
781
|
-
#### 6. **PatternStore** (`src/PatternStore.ts`)
|
|
782
|
-
|
|
783
|
-
Persistent pattern storage:
|
|
784
|
-
- **JSON-based**: Simple file storage
|
|
785
|
-
- **Metadata**: Name, tags, timestamp, audio features
|
|
786
|
-
- **Tag Filtering**: Organize by genre, mood, project
|
|
787
|
-
- **Sorted Retrieval**: Most recent first
|
|
788
|
-
|
|
789
|
-
### Directory Structure
|
|
790
|
-
|
|
791
|
-
```
|
|
792
|
-
live-coding-music-mcp/
|
|
793
|
-
├── src/
|
|
794
|
-
│ ├── server/
|
|
795
|
-
│ │ ├── server.ts # MCP dispatcher (~510 lines)
|
|
796
|
-
│ │ ├── resources.ts # MCP resources (#131)
|
|
797
|
-
│ │ └── tools/
|
|
798
|
-
│ │ ├── ai.ts, analysis.ts, capture.ts, compose.ts,
|
|
799
|
-
│ │ ├── diagnostics.ts, editor.ts, generate.ts, history.ts,
|
|
800
|
-
│ │ ├── playback.ts, session.ts, storage.ts, transform.ts,
|
|
801
|
-
│ │ └── types.ts # ToolContext, Envelope, helpers
|
|
802
|
-
│ ├── services/
|
|
803
|
-
│ │ ├── MusicTheory.ts # Scale/chord/euclidean helpers
|
|
804
|
-
│ │ ├── PatternGenerator.ts # Template-based generation
|
|
805
|
-
│ │ ├── SessionManager.ts # Multi-session lifecycle (#108)
|
|
806
|
-
│ │ ├── AudioCaptureService.ts # Audio recording
|
|
807
|
-
│ │ ├── MIDIExportService.ts # MIDI export
|
|
808
|
-
│ │ ├── GeminiService.ts # Gemini API client (ai_assist)
|
|
809
|
-
│ │ ├── StrudelEngine.ts # @strudel/* wrapper
|
|
810
|
-
│ │ └── StrudelEngineHelpers.ts # Pure helpers (#107)
|
|
811
|
-
│ ├── utils/
|
|
812
|
-
│ │ ├── Logger.ts
|
|
813
|
-
│ │ ├── PatternValidator.ts # Syntax + safety checks
|
|
814
|
-
│ │ ├── ErrorRecovery.ts # Retry / backoff
|
|
815
|
-
│ │ ├── PerformanceMonitor.ts
|
|
816
|
-
│ │ └── InputValidator.ts # Input bound checks
|
|
817
|
-
│ ├── StrudelController.ts # Browser automation (~800 lines)
|
|
818
|
-
│ ├── AudioAnalyzer.ts # Audio analysis (~800 lines)
|
|
819
|
-
│ ├── PatternStore.ts # On-disk pattern persistence
|
|
820
|
-
│ └── index.ts # Entry point
|
|
821
|
-
├── src/__tests__/ # Jest suites (unit + integration + browser)
|
|
822
|
-
├── patterns/
|
|
823
|
-
│ ├── examples/ # 18 bundled example patterns
|
|
824
|
-
│ └── *.json # Saved patterns at runtime
|
|
825
|
-
├── scripts/
|
|
826
|
-
│ ├── generate-tool-docs.ts # README tool-table generator
|
|
827
|
-
│ └── generate-changelog.ts
|
|
828
|
-
├── config.json # Local config (gitignored)
|
|
829
|
-
├── package.json
|
|
830
|
-
└── tsconfig.json
|
|
831
|
-
```
|
|
832
|
-
|
|
833
|
-
### Data Flow
|
|
834
|
-
|
|
835
|
-
1. **Tool Invocation**
|
|
836
|
-
```
|
|
837
|
-
Claude → MCP Protocol → StrudelMCPServer
|
|
838
|
-
```
|
|
839
|
-
|
|
840
|
-
2. **Pattern Generation** (without browser)
|
|
841
|
-
```
|
|
842
|
-
Server → PatternGenerator → MusicTheory → Pattern String
|
|
843
|
-
```
|
|
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.
|
|
844
648
|
|
|
845
|
-
|
|
846
|
-
```
|
|
847
|
-
Server → StrudelController → Playwright → Strudel.cc
|
|
848
|
-
```
|
|
649
|
+
Unknown top-level keys are logged as warnings at startup rather than silently ignored.
|
|
849
650
|
|
|
850
|
-
|
|
851
|
-
```
|
|
852
|
-
Strudel.cc → Web Audio API → AudioAnalyzer → Feature Data
|
|
853
|
-
```
|
|
854
|
-
|
|
855
|
-
### Performance Characteristics
|
|
856
|
-
|
|
857
|
-
| Operation | Latency | Notes |
|
|
858
|
-
|-----------|---------|-------|
|
|
859
|
-
| Pattern Generation | <100ms | Pure computation |
|
|
860
|
-
| Browser Init | ~3s | One-time cost |
|
|
861
|
-
| Pattern Write | ~50ms | With caching |
|
|
862
|
-
| Play/Stop | ~100ms | Keyboard shortcuts |
|
|
863
|
-
| Audio Analysis | ~20ms | With 50ms cache |
|
|
864
|
-
| Pattern Save | ~10ms | File I/O |
|
|
865
|
-
|
|
866
|
-
### Optimization Strategies
|
|
867
|
-
|
|
868
|
-
1. **Caching**
|
|
869
|
-
- Editor content: 100ms TTL
|
|
870
|
-
- Audio analysis: 50ms TTL
|
|
871
|
-
- 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.
|
|
872
652
|
|
|
873
|
-
|
|
874
|
-
- Images, fonts, media blocked
|
|
875
|
-
- Only load essential JavaScript/CSS
|
|
653
|
+
## Architecture
|
|
876
654
|
|
|
877
|
-
|
|
878
|
-
- CodeMirror view manipulation
|
|
879
|
-
- 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.
|
|
880
656
|
|
|
881
|
-
|
|
882
|
-
- Browser starts only when needed
|
|
883
|
-
- 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)**.
|
|
884
658
|
|
|
885
659
|
## Pattern Examples
|
|
886
660
|
|
|
887
661
|
### Minimal Techno (Verified Working)
|
|
888
662
|
```javascript
|
|
889
|
-
setcpm(130)
|
|
663
|
+
setcpm(130/4)
|
|
890
664
|
stack(
|
|
891
665
|
s("bd*4").gain(0.9),
|
|
892
666
|
s("~ cp ~ cp").room(0.2),
|
|
@@ -897,7 +671,7 @@ stack(
|
|
|
897
671
|
|
|
898
672
|
### Drum & Bass (Verified Working)
|
|
899
673
|
```javascript
|
|
900
|
-
setcpm(174)
|
|
674
|
+
setcpm(174/4)
|
|
901
675
|
stack(
|
|
902
676
|
s("bd ~ ~ [bd bd] ~ ~ bd ~, ~ ~ sn:3 ~ ~ sn:3 ~ ~").fast(2),
|
|
903
677
|
s("hh*16").gain(0.5),
|
|
@@ -929,347 +703,15 @@ docker-compose up
|
|
|
929
703
|
|
|
930
704
|
## Development
|
|
931
705
|
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
```bash
|
|
935
|
-
# Clone the repository
|
|
936
|
-
git clone https://github.com/williamzujkowski/live-coding-music-mcp.git
|
|
937
|
-
cd live-coding-music-mcp
|
|
938
|
-
|
|
939
|
-
# Install dependencies
|
|
940
|
-
npm install
|
|
941
|
-
|
|
942
|
-
# Install Playwright browsers
|
|
943
|
-
npx playwright install chromium
|
|
944
|
-
|
|
945
|
-
# Build the project
|
|
946
|
-
npm run build
|
|
947
|
-
```
|
|
948
|
-
|
|
949
|
-
### Available Scripts
|
|
706
|
+
For development setup, scripts, debugging, adding new tools, and the release process, see **[DEVELOPMENT.md](DEVELOPMENT.md)**.
|
|
950
707
|
|
|
951
|
-
|
|
952
|
-
#
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
#
|
|
956
|
-
npm run build
|
|
957
|
-
|
|
958
|
-
# Start production server
|
|
959
|
-
npm start
|
|
960
|
-
|
|
961
|
-
# Run all tests
|
|
962
|
-
npm test
|
|
963
|
-
|
|
964
|
-
# Run integration tests with real browser
|
|
965
|
-
npm run test:integration
|
|
966
|
-
|
|
967
|
-
# Run browser-specific tests
|
|
968
|
-
npm run test:browser
|
|
969
|
-
|
|
970
|
-
# Validate MCP protocol compliance
|
|
971
|
-
npm run validate
|
|
972
|
-
|
|
973
|
-
# Lint code
|
|
974
|
-
npm run lint
|
|
975
|
-
|
|
976
|
-
# Format code
|
|
977
|
-
npm run format
|
|
978
|
-
|
|
979
|
-
# Clean build artifacts
|
|
980
|
-
npm clean
|
|
981
|
-
```
|
|
982
|
-
|
|
983
|
-
### Publishing to npm
|
|
984
|
-
|
|
985
|
-
See [NPM_PUBLISHING.md](NPM_PUBLISHING.md) for complete publishing instructions.
|
|
986
|
-
|
|
987
|
-
**Quick publish via GitHub Release:**
|
|
988
|
-
```bash
|
|
989
|
-
npm version patch # or minor, major
|
|
990
|
-
git push && git push --tags
|
|
991
|
-
gh release create v$(node -p "require('./package.json').version") --generate-notes
|
|
992
|
-
```
|
|
993
|
-
|
|
994
|
-
The package uses OIDC trusted publishing with provenance attestation for supply chain security.
|
|
995
|
-
|
|
996
|
-
### Adding new tools
|
|
997
|
-
|
|
998
|
-
Tools live in per-domain modules under `src/server/tools/<domain>.ts`. `server.ts` just dispatches. To add a tool:
|
|
999
|
-
|
|
1000
|
-
1. **Pick the right domain module** (or add a new one). Add the tool definition to that module's `tools` array:
|
|
1001
|
-
|
|
1002
|
-
```typescript
|
|
1003
|
-
export const tools: Tool[] = [
|
|
1004
|
-
// ...
|
|
1005
|
-
{
|
|
1006
|
-
name: 'my_new_tool',
|
|
1007
|
-
description: 'One-line description; agents read this to pick between adjacent tools',
|
|
1008
|
-
inputSchema: {
|
|
1009
|
-
type: 'object',
|
|
1010
|
-
properties: {
|
|
1011
|
-
param1: { type: 'string', description: 'What it is' },
|
|
1012
|
-
session_id: { type: 'string', description: 'Optional session ID (#108)' },
|
|
1013
|
-
},
|
|
1014
|
-
required: ['param1'],
|
|
1015
|
-
},
|
|
1016
|
-
},
|
|
1017
|
-
];
|
|
1018
|
-
```
|
|
1019
|
-
|
|
1020
|
-
2. **Add the case** to the module's `execute()` switch:
|
|
1021
|
-
|
|
1022
|
-
```typescript
|
|
1023
|
-
case 'my_new_tool':
|
|
1024
|
-
return await ctx.getController(args.session_id).doSomething(args.param1);
|
|
1025
|
-
```
|
|
1026
|
-
|
|
1027
|
-
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.
|
|
1028
|
-
|
|
1029
|
-
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.
|
|
1030
|
-
|
|
1031
|
-
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.
|
|
1032
|
-
|
|
1033
|
-
6. **Build and test**:
|
|
1034
|
-
|
|
1035
|
-
```bash
|
|
1036
|
-
npm run build
|
|
1037
|
-
echo '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"my_new_tool","arguments":{"param1":"test"}},"id":2}' | node dist/index.js
|
|
1038
|
-
```
|
|
1039
|
-
|
|
1040
|
-
### Testing Strategy
|
|
1041
|
-
|
|
1042
|
-
#### 1. Unit Tests
|
|
1043
|
-
```bash
|
|
1044
|
-
# Run with Jest
|
|
1045
|
-
npm test
|
|
1046
|
-
|
|
1047
|
-
# Watch mode
|
|
1048
|
-
npm run test:watch
|
|
1049
|
-
```
|
|
1050
|
-
|
|
1051
|
-
#### 2. Integration Tests
|
|
1052
|
-
```bash
|
|
1053
|
-
# Full integration with real browser
|
|
1054
|
-
npm run test:integration
|
|
1055
|
-
|
|
1056
|
-
# This tests:
|
|
1057
|
-
# - Browser initialization
|
|
1058
|
-
# - Pattern generation
|
|
1059
|
-
# - Audio analysis
|
|
1060
|
-
# - Pattern storage
|
|
1061
|
-
# - All 84 registered tools
|
|
1062
|
-
```
|
|
1063
|
-
|
|
1064
|
-
#### 3. Manual Testing
|
|
1065
|
-
```bash
|
|
1066
|
-
# Development mode
|
|
1067
|
-
npm run dev
|
|
1068
|
-
|
|
1069
|
-
# In another terminal
|
|
1070
|
-
claude mcp add strudel-dev node $(pwd)/dist/index.js
|
|
1071
|
-
claude chat
|
|
1072
|
-
|
|
1073
|
-
# Then interact with Claude
|
|
1074
|
-
```
|
|
1075
|
-
|
|
1076
|
-
### Code Quality
|
|
1077
|
-
|
|
1078
|
-
**TypeScript Configuration**
|
|
1079
|
-
```json
|
|
1080
|
-
// tsconfig.json
|
|
1081
|
-
{
|
|
1082
|
-
"compilerOptions": {
|
|
1083
|
-
"strict": true, // Strict type checking
|
|
1084
|
-
"esModuleInterop": true, // Better module compatibility
|
|
1085
|
-
"target": "ES2020", // Modern JavaScript
|
|
1086
|
-
"module": "ES2020", // ES modules
|
|
1087
|
-
"moduleResolution": "node"
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
```
|
|
1091
|
-
|
|
1092
|
-
**Linting & Formatting**
|
|
1093
|
-
```bash
|
|
1094
|
-
# ESLint
|
|
1095
|
-
npm run lint
|
|
1096
|
-
|
|
1097
|
-
# Prettier
|
|
1098
|
-
npm run format
|
|
1099
|
-
|
|
1100
|
-
# Pre-commit hooks recommended
|
|
1101
|
-
```
|
|
1102
|
-
|
|
1103
|
-
### Debugging
|
|
1104
|
-
|
|
1105
|
-
**Enable Debug Logging**
|
|
1106
|
-
```bash
|
|
1107
|
-
# Set DEBUG environment variable
|
|
1108
|
-
DEBUG=strudel:* npm start
|
|
1109
|
-
|
|
1110
|
-
# Or specific modules
|
|
1111
|
-
DEBUG=strudel:controller npm start
|
|
1112
|
-
DEBUG=strudel:audio npm start
|
|
1113
|
-
```
|
|
1114
|
-
|
|
1115
|
-
**VS Code Launch Configuration**
|
|
1116
|
-
```json
|
|
1117
|
-
{
|
|
1118
|
-
"type": "node",
|
|
1119
|
-
"request": "launch",
|
|
1120
|
-
"name": "Debug MCP Server",
|
|
1121
|
-
"program": "${workspaceFolder}/dist/index.js",
|
|
1122
|
-
"preLaunchTask": "npm: build",
|
|
1123
|
-
"console": "integratedTerminal",
|
|
1124
|
-
"env": {
|
|
1125
|
-
"DEBUG": "strudel:*"
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1128
|
-
```
|
|
1129
|
-
|
|
1130
|
-
**Playwright Debugging**
|
|
1131
|
-
```typescript
|
|
1132
|
-
// In StrudelController.ts
|
|
1133
|
-
this.browser = await chromium.launch({
|
|
1134
|
-
headless: false, // See the browser
|
|
1135
|
-
devtools: true, // Open DevTools
|
|
1136
|
-
slowMo: 100 // Slow down actions
|
|
1137
|
-
});
|
|
1138
|
-
```
|
|
1139
|
-
|
|
1140
|
-
### Performance Monitoring
|
|
1141
|
-
|
|
1142
|
-
The server includes built-in performance monitoring:
|
|
1143
|
-
|
|
1144
|
-
```typescript
|
|
1145
|
-
// Access performance metrics
|
|
1146
|
-
You: Show me performance metrics
|
|
1147
|
-
|
|
1148
|
-
Claude: Performance Report:
|
|
1149
|
-
{
|
|
1150
|
-
"averageLatency": {
|
|
1151
|
-
"init": "3.2s",
|
|
1152
|
-
"write": "52ms",
|
|
1153
|
-
"play": "105ms",
|
|
1154
|
-
"analyze": "18ms"
|
|
1155
|
-
},
|
|
1156
|
-
"cacheHitRate": "85%",
|
|
1157
|
-
"totalOperations": 1247,
|
|
1158
|
-
"bottlenecks": [
|
|
1159
|
-
{"tool": "init", "avgTime": 3200, "calls": 1},
|
|
1160
|
-
{"tool": "write", "avgTime": 52, "calls": 156}
|
|
1161
|
-
]
|
|
1162
|
-
}
|
|
1163
|
-
```
|
|
1164
|
-
|
|
1165
|
-
### Contributing Guidelines
|
|
1166
|
-
|
|
1167
|
-
1. **Fork the repository**
|
|
1168
|
-
```bash
|
|
1169
|
-
git clone https://github.com/YOUR_USERNAME/live-coding-music-mcp.git
|
|
1170
|
-
```
|
|
1171
|
-
|
|
1172
|
-
2. **Create a feature branch**
|
|
1173
|
-
```bash
|
|
1174
|
-
git checkout -b feature/my-new-feature
|
|
1175
|
-
```
|
|
1176
|
-
|
|
1177
|
-
3. **Make your changes**
|
|
1178
|
-
- Follow existing code style
|
|
1179
|
-
- Add tests for new features
|
|
1180
|
-
- Update documentation
|
|
1181
|
-
- Ensure all tests pass
|
|
1182
|
-
|
|
1183
|
-
4. **Commit with meaningful messages**
|
|
1184
|
-
```bash
|
|
1185
|
-
git commit -m "feat: Add support for custom scale generation"
|
|
1186
|
-
```
|
|
1187
|
-
|
|
1188
|
-
Follow [Conventional Commits](https://www.conventionalcommits.org/):
|
|
1189
|
-
- `feat:` New feature
|
|
1190
|
-
- `fix:` Bug fix
|
|
1191
|
-
- `docs:` Documentation changes
|
|
1192
|
-
- `refactor:` Code refactoring
|
|
1193
|
-
- `test:` Adding tests
|
|
1194
|
-
- `chore:` Maintenance tasks
|
|
1195
|
-
|
|
1196
|
-
5. **Push and create PR**
|
|
1197
|
-
```bash
|
|
1198
|
-
git push origin feature/my-new-feature
|
|
1199
|
-
```
|
|
1200
|
-
|
|
1201
|
-
Then create a Pull Request on GitHub with:
|
|
1202
|
-
- Clear description of changes
|
|
1203
|
-
- Link to related issues
|
|
1204
|
-
- Screenshots/examples if relevant
|
|
1205
|
-
|
|
1206
|
-
### 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
|
|
1207
713
|
|
|
1208
|
-
|
|
1209
|
-
# 1. Update version in package.json
|
|
1210
|
-
npm version patch # or minor/major
|
|
1211
|
-
|
|
1212
|
-
# 2. Update CHANGELOG.md
|
|
1213
|
-
# Add entry for new version
|
|
1214
|
-
|
|
1215
|
-
# 3. Build and test
|
|
1216
|
-
npm run build
|
|
1217
|
-
npm test
|
|
1218
|
-
npm run test:integration
|
|
1219
|
-
|
|
1220
|
-
# 4. Commit version bump
|
|
1221
|
-
git add .
|
|
1222
|
-
git commit -m "chore: Bump version to X.Y.Z"
|
|
1223
|
-
|
|
1224
|
-
# 5. Create git tag
|
|
1225
|
-
git tag vX.Y.Z
|
|
1226
|
-
|
|
1227
|
-
# 6. Push to GitHub
|
|
1228
|
-
git push origin main --tags
|
|
1229
|
-
|
|
1230
|
-
# 7. Publish to npm (if you have access)
|
|
1231
|
-
npm publish --access public
|
|
1232
|
-
|
|
1233
|
-
# 8. Create GitHub release
|
|
1234
|
-
gh release create vX.Y.Z --generate-notes
|
|
1235
|
-
```
|
|
1236
|
-
|
|
1237
|
-
### Docker Development
|
|
1238
|
-
|
|
1239
|
-
```bash
|
|
1240
|
-
# Build development image
|
|
1241
|
-
docker build -t live-coding-music-mcp:dev .
|
|
1242
|
-
|
|
1243
|
-
# Run with volume mount for hot reload
|
|
1244
|
-
docker run -it --rm \
|
|
1245
|
-
-v $(pwd)/src:/app/src \
|
|
1246
|
-
-v $(pwd)/patterns:/app/patterns \
|
|
1247
|
-
live-coding-music-mcp:dev
|
|
1248
|
-
|
|
1249
|
-
# Run tests in container
|
|
1250
|
-
docker run -it --rm live-coding-music-mcp:dev npm test
|
|
1251
|
-
```
|
|
1252
|
-
|
|
1253
|
-
### Environment Variables
|
|
1254
|
-
|
|
1255
|
-
```bash
|
|
1256
|
-
# Logging level
|
|
1257
|
-
LOG_LEVEL=debug # debug, info, warn, error
|
|
1258
|
-
|
|
1259
|
-
# Performance monitoring
|
|
1260
|
-
ENABLE_PERF_MONITORING=true
|
|
1261
|
-
|
|
1262
|
-
# Pattern storage
|
|
1263
|
-
PATTERNS_DIR=./patterns
|
|
1264
|
-
|
|
1265
|
-
# Browser configuration
|
|
1266
|
-
HEADLESS=false
|
|
1267
|
-
BROWSER_TIMEOUT=15000
|
|
1268
|
-
|
|
1269
|
-
# Audio analysis
|
|
1270
|
-
FFT_SIZE=1024
|
|
1271
|
-
SMOOTHING=0.8
|
|
1272
|
-
```
|
|
714
|
+
The [Configuration](#configuration) section above covers runtime config (`config.json`). [ARCHITECTURE.md](ARCHITECTURE.md) covers the system design.
|
|
1273
715
|
|
|
1274
716
|
## Performance
|
|
1275
717
|
|
|
@@ -1282,8 +724,8 @@ Measured against the current `StrudelController` cache + Strudel.cc on a develop
|
|
|
1282
724
|
| Pattern read (cached) | 10–15 ms |
|
|
1283
725
|
| Play / pause / stop | 100–150 ms |
|
|
1284
726
|
| Audio analysis (single FFT) | 10–15 ms |
|
|
1285
|
-
| Tempo detection | <100 ms (onset-based;
|
|
1286
|
-
| 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`) |
|
|
1287
729
|
| Pattern generation | <100 ms (template-based) |
|
|
1288
730
|
| Process resident memory | ~120–150 MB |
|
|
1289
731
|
|
|
@@ -1454,7 +896,7 @@ s("bd*4")
|
|
|
1454
896
|
.every(8, x => x.sometimes(y => y.fast(2)))
|
|
1455
897
|
```
|
|
1456
898
|
|
|
1457
|
-
##
|
|
899
|
+
## Security
|
|
1458
900
|
|
|
1459
901
|
### Pattern Validation
|
|
1460
902
|
|
|
@@ -1463,11 +905,23 @@ All patterns are validated before execution:
|
|
|
1463
905
|
- **Eval blocks** are rejected
|
|
1464
906
|
- **Path traversal** attacks are blocked in PatternStore
|
|
1465
907
|
|
|
1466
|
-
### Browser
|
|
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.
|
|
1467
922
|
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
- 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.
|
|
1471
925
|
|
|
1472
926
|
### Known Limitations
|
|
1473
927
|
|
|
@@ -1479,7 +933,7 @@ All patterns are validated before execution:
|
|
|
1479
933
|
|
|
1480
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.
|
|
1481
935
|
|
|
1482
|
-
##
|
|
936
|
+
## Troubleshooting
|
|
1483
937
|
|
|
1484
938
|
### Common Issues
|
|
1485
939
|
|
|
@@ -1546,7 +1000,7 @@ npm run build
|
|
|
1546
1000
|
# Check if server responds
|
|
1547
1001
|
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node dist/index.js
|
|
1548
1002
|
|
|
1549
|
-
# Should return JSON with
|
|
1003
|
+
# Should return JSON with 28 tools
|
|
1550
1004
|
|
|
1551
1005
|
# Reinstall MCP server in Claude
|
|
1552
1006
|
claude mcp remove strudel
|
|
@@ -1587,7 +1041,7 @@ claude chat
|
|
|
1587
1041
|
- Use resource blocking (enabled by default)
|
|
1588
1042
|
|
|
1589
1043
|
#### Patterns not saving
|
|
1590
|
-
**Symptom**: `save`
|
|
1044
|
+
**Symptom**: `pattern_store({ action: "save" })` fails or patterns don't persist
|
|
1591
1045
|
|
|
1592
1046
|
**Solutions**:
|
|
1593
1047
|
```bash
|
|
@@ -1655,7 +1109,7 @@ Claude: Browser state:
|
|
|
1655
1109
|
- Initialized: true
|
|
1656
1110
|
- Cached patterns: 2
|
|
1657
1111
|
- Undo stack depth: 5
|
|
1658
|
-
- Last operation:
|
|
1112
|
+
- Last operation: edit_pattern (2.5s ago)
|
|
1659
1113
|
```
|
|
1660
1114
|
|
|
1661
1115
|
**Validate Pattern Syntax**
|
|
@@ -1678,53 +1132,31 @@ If you encounter issues not covered here:
|
|
|
1678
1132
|
4. **Consult Strudel docs**: [Strudel.cc documentation](https://strudel.cc/learn)
|
|
1679
1133
|
5. **Create new issue**: Include error messages, OS, Node version, and steps to reproduce
|
|
1680
1134
|
|
|
1681
|
-
##
|
|
1682
|
-
|
|
1683
|
-
**We need your help!** This project is actively developed and welcomes contributions of all kinds:
|
|
1684
|
-
|
|
1685
|
-
### Ways to Contribute
|
|
1686
|
-
- **Report Bugs**: Found an issue? [Open a bug report](https://github.com/williamzujkowski/live-coding-music-mcp/issues/new)
|
|
1687
|
-
- **Suggest Features**: Have ideas? [Create a feature request](https://github.com/williamzujkowski/live-coding-music-mcp/issues/new)
|
|
1688
|
-
- **Improve Docs**: Fix typos, add examples, clarify confusing sections
|
|
1689
|
-
- **Write Tests**: Help us improve test coverage
|
|
1690
|
-
- **Fix Issues**: Check [open issues](https://github.com/williamzujkowski/live-coding-music-mcp/issues) for bugs to fix
|
|
1691
|
-
- **Add Features**: Implement new tools or improve existing ones
|
|
1692
|
-
|
|
1693
|
-
### Quick Start for Contributors
|
|
1694
|
-
1. Fork the repository
|
|
1695
|
-
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
1696
|
-
3. Make your changes and add tests
|
|
1697
|
-
4. Ensure tests pass (`npm test`)
|
|
1698
|
-
5. Commit with clear messages (`git commit -m 'fix: resolve audio analysis bug'`)
|
|
1699
|
-
6. Push to your fork (`git push origin feature/amazing-feature`)
|
|
1700
|
-
7. Open a Pull Request
|
|
1135
|
+
## Contributing
|
|
1701
1136
|
|
|
1702
|
-
|
|
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.
|
|
1703
1138
|
|
|
1704
|
-
|
|
1705
|
-
- Questions? Open a [Discussion](https://github.com/williamzujkowski/live-coding-music-mcp/discussions)
|
|
1706
|
-
- Found something confusing? Tell us!
|
|
1707
|
-
- 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.
|
|
1708
1140
|
|
|
1709
|
-
|
|
1141
|
+
[GitHub Discussions](https://github.com/williamzujkowski/live-coding-music-mcp/discussions) are open for use-case questions and design conversations.
|
|
1710
1142
|
|
|
1711
|
-
##
|
|
1143
|
+
## License
|
|
1712
1144
|
|
|
1713
1145
|
**AGPL-3.0-or-later** — see [LICENSE](LICENSE) for the full text.
|
|
1714
1146
|
|
|
1715
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).
|
|
1716
1148
|
|
|
1717
|
-
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).
|
|
1718
1150
|
|
|
1719
|
-
##
|
|
1151
|
+
## Acknowledgments
|
|
1720
1152
|
|
|
1721
|
-
- [Strudel.cc](https://strudel.cc) -
|
|
1722
|
-
- [TidalCycles](https://tidalcycles.org)
|
|
1723
|
-
- [Anthropic](https://anthropic.com)
|
|
1724
|
-
- [Playwright](https://playwright.dev)
|
|
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
|
|
1725
1157
|
|
|
1726
1158
|
---
|
|
1727
1159
|
|
|
1728
|
-
**
|
|
1160
|
+
**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)
|
|
1729
1161
|
|
|
1730
1162
|
*This project is under active development. Core features work, but expect bugs and breaking changes. Not recommended for production use.*
|