livemcp 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. livemcp-1.1.0/.claude/skills/README.md +9 -0
  2. livemcp-1.1.0/.claude/skills/publish.md +45 -0
  3. livemcp-1.1.0/.claude/skills/restart-ableton.md +58 -0
  4. livemcp-1.1.0/.claude/skills/verify.md +49 -0
  5. livemcp-1.1.0/.gitignore +13 -0
  6. livemcp-1.1.0/CLAUDE.md +210 -0
  7. livemcp-1.1.0/LICENSE +21 -0
  8. livemcp-1.1.0/PKG-INFO +348 -0
  9. livemcp-1.1.0/README.md +323 -0
  10. livemcp-1.1.0/pyproject.toml +42 -0
  11. livemcp-1.1.0/remote_script/LiveMCP/__init__.py +30 -0
  12. livemcp-1.1.0/remote_script/LiveMCP/browser.py +317 -0
  13. livemcp-1.1.0/remote_script/LiveMCP/handlers/__init__.py +33 -0
  14. livemcp-1.1.0/remote_script/LiveMCP/handlers/arrangement.py +179 -0
  15. livemcp-1.1.0/remote_script/LiveMCP/handlers/clips.py +1122 -0
  16. livemcp-1.1.0/remote_script/LiveMCP/handlers/devices.py +627 -0
  17. livemcp-1.1.0/remote_script/LiveMCP/handlers/grooves.py +121 -0
  18. livemcp-1.1.0/remote_script/LiveMCP/handlers/mixer.py +255 -0
  19. livemcp-1.1.0/remote_script/LiveMCP/handlers/session.py +765 -0
  20. livemcp-1.1.0/remote_script/LiveMCP/handlers/tracks.py +712 -0
  21. livemcp-1.1.0/remote_script/LiveMCP/server.py +146 -0
  22. livemcp-1.1.0/scripts/install.py +122 -0
  23. livemcp-1.1.0/scripts/install.sh +57 -0
  24. livemcp-1.1.0/scripts/restart_ableton.sh +92 -0
  25. livemcp-1.1.0/scripts/uninstall.py +74 -0
  26. livemcp-1.1.0/scripts/uninstall.sh +18 -0
  27. livemcp-1.1.0/src/livemcp/__init__.py +3 -0
  28. livemcp-1.1.0/src/livemcp/__main__.py +5 -0
  29. livemcp-1.1.0/src/livemcp/connection.py +100 -0
  30. livemcp-1.1.0/src/livemcp/installer.py +155 -0
  31. livemcp-1.1.0/src/livemcp/remote_script/__init__.py +30 -0
  32. livemcp-1.1.0/src/livemcp/remote_script/browser.py +317 -0
  33. livemcp-1.1.0/src/livemcp/remote_script/handlers/__init__.py +33 -0
  34. livemcp-1.1.0/src/livemcp/remote_script/handlers/arrangement.py +179 -0
  35. livemcp-1.1.0/src/livemcp/remote_script/handlers/clips.py +1122 -0
  36. livemcp-1.1.0/src/livemcp/remote_script/handlers/devices.py +627 -0
  37. livemcp-1.1.0/src/livemcp/remote_script/handlers/grooves.py +121 -0
  38. livemcp-1.1.0/src/livemcp/remote_script/handlers/mixer.py +255 -0
  39. livemcp-1.1.0/src/livemcp/remote_script/handlers/session.py +765 -0
  40. livemcp-1.1.0/src/livemcp/remote_script/handlers/tracks.py +712 -0
  41. livemcp-1.1.0/src/livemcp/remote_script/server.py +146 -0
  42. livemcp-1.1.0/src/livemcp/server.py +35 -0
  43. livemcp-1.1.0/src/livemcp/tools/__init__.py +1 -0
  44. livemcp-1.1.0/src/livemcp/tools/arrangement.py +135 -0
  45. livemcp-1.1.0/src/livemcp/tools/clips.py +858 -0
  46. livemcp-1.1.0/src/livemcp/tools/devices.py +402 -0
  47. livemcp-1.1.0/src/livemcp/tools/grooves.py +89 -0
  48. livemcp-1.1.0/src/livemcp/tools/mixer.py +200 -0
  49. livemcp-1.1.0/src/livemcp/tools/session.py +589 -0
  50. livemcp-1.1.0/src/livemcp/tools/tracks.py +425 -0
  51. livemcp-1.1.0/uv.lock +826 -0
@@ -0,0 +1,9 @@
1
+ # LiveMCP Claude Skills
2
+
3
+ Project-specific skills for Ableton Live MCP development.
4
+
5
+ | Skill | When to use |
6
+ |-------|-------------|
7
+ | `/verify` | Before every commit — tests, tool count check |
8
+ | `/restart-ableton` | After modifying remote script files |
9
+ | `/publish` | Publish new version to PyPI |
@@ -0,0 +1,45 @@
1
+ # /publish — Publish to PyPI
2
+
3
+ Release a new version of livemcp.
4
+
5
+ ## Pre-flight
6
+
7
+ 1. Run `/verify` first
8
+ 2. Test with Ableton Live (run `/restart-ableton` + verify all 171 tools work)
9
+ 3. Update version in `pyproject.toml`
10
+ 4. Update CHANGELOG or README with new features/fixes
11
+ 5. Commit: `git commit -m "Bump version to X.Y.Z"`
12
+ 6. Tag: `git tag vX.Y.Z`
13
+ 7. Push: `git push && git push --tags`
14
+
15
+ ## Build and Publish
16
+
17
+ ```bash
18
+ # Clean previous builds
19
+ rm -rf dist/
20
+
21
+ # Build package
22
+ uv build
23
+
24
+ # Check package contents
25
+ tar tzf dist/livemcp-*.tar.gz
26
+
27
+ # Publish to PyPI (requires API token)
28
+ uv publish
29
+ ```
30
+
31
+ ## Verify Publication
32
+
33
+ ```bash
34
+ # Install from PyPI
35
+ uvx livemcp@X.Y.Z
36
+
37
+ # Should connect to Ableton on port 9877
38
+ # Test with Claude Desktop or Claude Code
39
+ ```
40
+
41
+ ## Rollback
42
+
43
+ PyPI doesn't allow deleting versions. If bad release:
44
+ 1. Publish a new patch version (X.Y.Z+1)
45
+ 2. Update docs/README to skip the broken version
@@ -0,0 +1,58 @@
1
+ # /restart-ableton — Restart Ableton Live
2
+
3
+ Critical procedure after modifying remote script files. Clears Python bytecode cache so Ableton loads fresh code.
4
+
5
+ ## Quick Version
6
+
7
+ ```bash
8
+ bash scripts/restart_ableton.sh
9
+ ```
10
+
11
+ ## Manual Steps (if script fails)
12
+
13
+ ```bash
14
+ # 1. Clear bytecode cache
15
+ find /home/alaarab/Sites/livemcp/remote_script -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null
16
+
17
+ # 2. Quit Ableton
18
+ osascript -e 'tell application "Ableton Live 12 Suite" to quit'
19
+ sleep 2
20
+
21
+ # 3. Dismiss save dialog
22
+ osascript -e 'tell application "System Events" to tell process "Ableton Live 12 Suite" to if exists window 1 then click button "Don'\''t Save" of window 1' 2>/dev/null
23
+
24
+ # 4. Wait for exit (max 15s)
25
+ for i in $(seq 1 15); do
26
+ pgrep -x "Ableton Live" > /dev/null 2>&1 || break
27
+ sleep 1
28
+ done
29
+
30
+ # 5. Force kill if hanging
31
+ pgrep -x "Ableton Live" > /dev/null 2>&1 && pkill -9 -x "Ableton Live" && sleep 2
32
+
33
+ # 6. Relaunch
34
+ open -a "Ableton Live 12 Suite"
35
+
36
+ # 7. Dismiss "unexpectedly quit" dialog (poll for 10s)
37
+ for i in $(seq 1 10); do
38
+ osascript -e 'tell application "System Events" to tell process "Ableton Live 12 Suite" to if exists window 1 then click button "Reopen" of window 1' 2>/dev/null && break
39
+ sleep 1
40
+ done
41
+
42
+ # 8. Wait for LiveMCP socket (port 9877)
43
+ for i in $(seq 1 30); do
44
+ python3 -c "import socket; s=socket.socket(); s.settimeout(2); s.connect(('127.0.0.1', 9877)); s.close()" 2>/dev/null && break
45
+ sleep 3
46
+ done
47
+ ```
48
+
49
+ ## Verify
50
+
51
+ 1. Check Ableton status bar: "LiveMCP: Server started on port 9877"
52
+ 2. Test MCP server: `uvx livemcp` (should connect)
53
+
54
+ ## Common Issues
55
+
56
+ - **Cache not cleared**: Ableton loads old .pyc files → always clear `__pycache__` first
57
+ - **Save dialog blocks**: Script clicks "Don't Save" automatically
58
+ - **Socket timeout**: Takes 15-30s for port 9877 to be ready after launch
@@ -0,0 +1,49 @@
1
+ # /verify — Pre-Commit Gate
2
+
3
+ Run before `git commit`. Tests and tool registration check.
4
+
5
+ ## Steps
6
+
7
+ ### 1. Tool Count
8
+ ```bash
9
+ uv run python -c "from livemcp.server import mcp; print(f'{len(mcp._tool_manager._tools)} tools registered')"
10
+ ```
11
+ ✅ 171 tools | ❌ If count is wrong, check server.py registrations
12
+
13
+ ### 2. Syntax Check (all Python files)
14
+ ```bash
15
+ find . -name "*.py" -not -path "./.venv/*" | xargs -I{} python3 -c "import py_compile; py_compile.compile('{}', doraise=True)"
16
+ ```
17
+ ✅ All files valid | ❌ Report syntax errors
18
+
19
+ ### 3. Lint (Ruff)
20
+ ```bash
21
+ uv run ruff check src/livemcp/
22
+ ```
23
+ ✅ Clean | ❌ Fix with `uv run ruff check --fix src/livemcp/`
24
+
25
+ ### 4. Git Status
26
+ ```bash
27
+ git status
28
+ ```
29
+ ✅ No `.env` or credentials in staging
30
+
31
+ ### 4. Remote Script Check
32
+ ```bash
33
+ ls -l ~/Music/"Ableton/User Library/Remote Scripts/LiveMCP/" | grep __init__
34
+ ```
35
+ ✅ Symlink intact | ⚠️ If broken, run `./scripts/install.sh`
36
+
37
+ ## Output
38
+
39
+ ```
40
+ /verify Report
41
+
42
+ 1. Tools ✅ 171 tools registered
43
+ 2. Syntax ✅ All Python files valid
44
+ 3. Lint ✅ Ruff clean
45
+ 4. Git status ✅ Clean
46
+ 5. Remote script ✅ Symlink intact
47
+
48
+ RESULT: ✅ SAFE TO COMMIT
49
+ ```
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.pyo
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+ .venv/
9
+ .env
10
+ .DS_Store
11
+ *.so
12
+ .ruff_cache/
13
+ .pytest_cache/
@@ -0,0 +1,210 @@
1
+ # LiveMCP — Claude Code Instructions
2
+
3
+ ## Project Overview
4
+
5
+ LiveMCP is a Model Context Protocol (MCP) bridge that exposes Ableton Live's internal Python API to AI assistants. Version 1.0.0, published on PyPI as `livemcp`, invoked via `uvx livemcp`.
6
+
7
+ It provides 171 tools across 7 categories: session, clips, tracks, devices, mixer, arrangement, grooves.
8
+
9
+ macOS only. The remote script relies on Ableton's macOS application bundle structure and the osascript-based install/restart scripts target macOS paths exclusively.
10
+
11
+ ## Architecture
12
+
13
+ LiveMCP has two components that must stay in sync:
14
+
15
+ **MCP Server (`src/livemcp/`)** — Python 3.10+, FastMCP, communicates with Ableton over a TCP socket.
16
+
17
+ - `src/livemcp/server.py` — FastMCP instance, registers all tools
18
+ - `src/livemcp/connection.py` — singleton TCP connection to Ableton
19
+ - `src/livemcp/tools/` — one module per category, each exports a `TOOLS` list of functions
20
+
21
+ **Remote Script (`remote_script/LiveMCP/`)** — Runs inside Ableton Live's embedded Python 3.11 interpreter as a MIDI Remote Script (extends `ControlSurface`).
22
+
23
+ - `remote_script/LiveMCP/server.py` — TCP server, command dispatcher
24
+ - `remote_script/LiveMCP/handlers/` — one module per category, each exports `READ_HANDLERS` and `WRITE_HANDLERS` dicts
25
+
26
+ ## Connection Details
27
+
28
+ - Host: `127.0.0.1`, Port: `9877`
29
+ - Singleton: one `AbletonConnection` instance shared across all tool calls (thread-safe via `threading.Lock`)
30
+ - Timeout: 15 seconds per command
31
+ - Retries: 3 attempts with 1-second delay between attempts
32
+ - Validation: on first connect, `get_session_info` is sent as a ping to confirm the remote script is ready
33
+
34
+ ## READ vs WRITE Handler Threading Model
35
+
36
+ This is the most important rule when adding handlers in `remote_script/LiveMCP/handlers/`:
37
+
38
+ - **READ_HANDLERS** run directly on the socket thread. Safe for reading Live object properties.
39
+ - **WRITE_HANDLERS** are dispatched to Ableton's main thread via `schedule_message`. Required for any mutation of Live's object model (setting properties, calling methods that modify state).
40
+
41
+ **Putting a write operation in READ_HANDLERS will crash or corrupt Ableton's state.** When in doubt, use WRITE_HANDLERS.
42
+
43
+ ## Adding a New Tool
44
+
45
+ Adding a tool requires changes in four places:
46
+
47
+ **Step 1 — Add the tool function** in `src/livemcp/tools/<category>.py`:
48
+
49
+ ```python
50
+ def my_new_tool(track_index: int, value: float) -> str:
51
+ """One-line summary for the AI assistant.
52
+
53
+ Args:
54
+ track_index: Zero-based track index.
55
+ value: The value to set.
56
+ """
57
+ result = get_connection().send_command("my_new_tool", {
58
+ "track_index": track_index,
59
+ "value": value,
60
+ })
61
+ return json.dumps(result)
62
+ ```
63
+
64
+ **Step 2 — Append to TOOLS list** at the bottom of the same file:
65
+
66
+ ```python
67
+ TOOLS = [
68
+ # ... existing tools ...
69
+ my_new_tool,
70
+ ]
71
+ ```
72
+
73
+ **Step 3 — Add the handler** in `remote_script/LiveMCP/handlers/<category>.py`:
74
+
75
+ ```python
76
+ def my_new_tool(control_surface, params):
77
+ track_index = params.get("track_index")
78
+ value = params.get("value")
79
+ if track_index is None or value is None:
80
+ raise ValueError("Missing required parameters")
81
+ song = control_surface.song()
82
+ track = song.tracks[track_index]
83
+ # mutate state here
84
+ return {"ok": True}
85
+ ```
86
+
87
+ **Step 4 — Register in READ_HANDLERS or WRITE_HANDLERS** in the same handler file:
88
+
89
+ ```python
90
+ READ_HANDLERS = {
91
+ # read-only: runs on socket thread
92
+ "get_something": get_something,
93
+ }
94
+
95
+ WRITE_HANDLERS = {
96
+ # state mutation: queued to Ableton's main thread
97
+ "my_new_tool": my_new_tool,
98
+ }
99
+ ```
100
+
101
+ The command string (e.g. `"my_new_tool"`) must be identical in `send_command(...)` and the handler dict key.
102
+
103
+ ## Project Structure
104
+
105
+ ```
106
+ src/livemcp/
107
+ server.py # FastMCP instance, registers all tools from TOOLS lists
108
+ connection.py # AbletonConnection singleton, send_command()
109
+ tools/
110
+ session.py # tempo, transport, time signature, cue points
111
+ tracks.py # create/delete/rename tracks, arm, solo, mute
112
+ clips.py # create clips, add notes, quantize, warp
113
+ devices.py # load instruments/effects, device parameters
114
+ mixer.py # volume, pan, send levels, routing
115
+ arrangement.py # arrangement view clips
116
+ grooves.py # groove pool
117
+
118
+ remote_script/LiveMCP/
119
+ __init__.py # ControlSurface entry point
120
+ server.py # TCP server + dispatcher (READ vs WRITE routing)
121
+ handlers/
122
+ __init__.py # aggregates all READ/WRITE handler dicts
123
+ session.py
124
+ tracks.py
125
+ clips.py
126
+ devices.py
127
+ mixer.py
128
+ arrangement.py
129
+ grooves.py
130
+
131
+ scripts/
132
+ install.sh # symlinks remote_script/LiveMCP into Ableton's MIDI Remote Scripts dir
133
+ uninstall.sh # removes the symlink from all detected Ableton versions
134
+ restart_ableton.sh # full restart procedure (cache clear, quit, relaunch, wait for socket)
135
+ ```
136
+
137
+ ## Restarting Ableton Live
138
+
139
+ When you need to restart Ableton (e.g. after modifying remote script files), **always** use this procedure:
140
+
141
+ ```bash
142
+ # 1. Clear bytecode cache so Ableton loads fresh Python
143
+ find /home/alaarab/Sites/livemcp/remote_script -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null
144
+
145
+ # 2. Gracefully quit (sends save dialog — dismiss it)
146
+ osascript -e 'tell application "Ableton Live 12 Suite" to quit'
147
+
148
+ # 3. Dismiss any "Save" dialog that appears
149
+ sleep 2
150
+ osascript -e 'tell application "System Events" to tell process "Ableton Live 12 Suite" to if exists window 1 then click button "Don'\''t Save" of window 1' 2>/dev/null
151
+
152
+ # 4. Wait for process to fully exit
153
+ for i in $(seq 1 15); do
154
+ pgrep -x "Ableton Live" > /dev/null 2>&1 || break
155
+ sleep 1
156
+ done
157
+
158
+ # 5. Force kill if it's still hanging
159
+ pgrep -x "Ableton Live" > /dev/null 2>&1 && pkill -9 -x "Ableton Live" && sleep 2
160
+
161
+ # 6. Relaunch
162
+ open -a "Ableton Live 12 Suite"
163
+
164
+ # 7. Dismiss "unexpectedly quit" dialog if it appears (poll for a few seconds)
165
+ for i in $(seq 1 10); do
166
+ osascript -e 'tell application "System Events" to tell process "Ableton Live 12 Suite" to if exists window 1 then click button "Reopen" of window 1' 2>/dev/null && break
167
+ sleep 1
168
+ done
169
+
170
+ # 8. Wait for LiveMCP socket to be ready
171
+ for i in $(seq 1 30); do
172
+ python3 -c "import socket; s=socket.socket(); s.settimeout(2); s.connect(('127.0.0.1', 9877)); s.close()" 2>/dev/null && break
173
+ sleep 3
174
+ done
175
+ ```
176
+
177
+ Or use the helper script: `bash scripts/restart_ableton.sh`
178
+
179
+ ### Important Notes
180
+
181
+ - **Always clear `__pycache__`** before restarting — Ableton caches .pyc files and won't see your changes otherwise
182
+ - The "unexpectedly quit" dialog appears if the previous quit wasn't clean. The script handles this automatically.
183
+ - The "Save?" dialog appears on graceful quit. The script clicks "Don't Save" — if you need to save, do it manually first.
184
+ - Socket on port 9877 typically takes 15-30 seconds after launch to become available.
185
+
186
+ ## Verification After Changes
187
+
188
+ ```bash
189
+ # Syntax check all Python files
190
+ find . -name "*.py" -not -path "./.venv/*" | xargs -I{} python3 -c "import py_compile; py_compile.compile('{}', doraise=True)"
191
+
192
+ # Verify registered tool count (target: 171)
193
+ uv run python -c "from livemcp.server import mcp; print(len(mcp._tool_manager._tools), 'tools')"
194
+
195
+ # Lint with ruff (line-length 100, configured in pyproject.toml)
196
+ uv run ruff check src/livemcp/
197
+ ```
198
+
199
+ ## Code Style
200
+
201
+ Ruff is the linter. Line length is 100, configured in `pyproject.toml` under `[tool.ruff]`. Run `uv run ruff check src/livemcp/` before committing. Run `uv run ruff format src/livemcp/` to auto-format.
202
+
203
+ ## Known API Gotchas
204
+
205
+ - `MidiNoteSpecification`: must use constructor kwargs, NOT attribute setting
206
+ - `apply_note_modifications`: pass the original tuple from `get_notes_extended`, don't convert to list
207
+ - `quantize_clip` grid: must be int, not float
208
+ - Mixer zero-value: never use `params.get("x") or params.get("y")` — use explicit None checks (0.0 is falsy)
209
+ - `scene.tempo`: can't set to -1.0 to clear; use `scene.tempo_enabled = False` instead
210
+ - `clip.groove = None` doesn't work; groove removal is an API limitation
livemcp-1.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ala Arab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.