sonic-pi-mcp 0.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.
- sonic_pi_mcp-0.1.0/.gitignore +35 -0
- sonic_pi_mcp-0.1.0/LICENSE +21 -0
- sonic_pi_mcp-0.1.0/PKG-INFO +231 -0
- sonic_pi_mcp-0.1.0/README.md +209 -0
- sonic_pi_mcp-0.1.0/pyproject.toml +69 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/__init__.py +6 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/__main__.py +6 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/config.py +68 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/docs/__init__.py +2 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/docs/search.py +104 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/errors.py +19 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/models.py +48 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/server.py +115 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/sonic/__init__.py +2 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/sonic/daemon.py +128 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/sonic/events.py +83 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/sonic/locator.py +63 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/sonic/logs.py +48 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/sonic/osc.py +222 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/sonic/protocol.py +85 -0
- sonic_pi_mcp-0.1.0/src/sonic_pi_mcp/sonic/session.py +295 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Local runtime state and generated media
|
|
2
|
+
.runtime/
|
|
3
|
+
exports/
|
|
4
|
+
*.wav
|
|
5
|
+
*.wave
|
|
6
|
+
*.aiff
|
|
7
|
+
*.aif
|
|
8
|
+
*.flac
|
|
9
|
+
|
|
10
|
+
# Local composition/playback helpers excluded from the pip package
|
|
11
|
+
examples/
|
|
12
|
+
scripts/
|
|
13
|
+
tests/
|
|
14
|
+
|
|
15
|
+
# Python caches and virtual environments
|
|
16
|
+
__pycache__/
|
|
17
|
+
*.py[cod]
|
|
18
|
+
*$py.class
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.ruff_cache/
|
|
21
|
+
.mypy_cache/
|
|
22
|
+
.venv/
|
|
23
|
+
venv/
|
|
24
|
+
env/
|
|
25
|
+
|
|
26
|
+
# Build artifacts
|
|
27
|
+
dist/
|
|
28
|
+
build/
|
|
29
|
+
*.egg-info/
|
|
30
|
+
|
|
31
|
+
# OS/editor noise
|
|
32
|
+
.DS_Store
|
|
33
|
+
Thumbs.db
|
|
34
|
+
.vscode/
|
|
35
|
+
.idea/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 WEEZZ-admin
|
|
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.
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sonic-pi-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server for controlling a local Sonic Pi runtime
|
|
5
|
+
Project-URL: Homepage, https://github.com/WEEZZ-admin/sonic-pi-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/WEEZZ-admin/sonic-pi-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/WEEZZ-admin/sonic-pi-mcp/issues
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: mcp,music,osc,sonic-pi,stdio
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Requires-Dist: mcp<2.0.0,>=1.28.1
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# sonic-pi-mcp
|
|
24
|
+
|
|
25
|
+
`sonic-pi-mcp` is a Python MCP server that lets an MCP client control a local
|
|
26
|
+
Sonic Pi runtime over the standard `stdio` transport.
|
|
27
|
+
|
|
28
|
+
It starts Sonic Pi's Ruby daemon, sends OSC messages to the Spider runtime, runs
|
|
29
|
+
Sonic Pi code, stops jobs, reads runtime events/logs, and searches the local
|
|
30
|
+
Sonic Pi docs/samples/synthdefs.
|
|
31
|
+
|
|
32
|
+
## Requirements
|
|
33
|
+
|
|
34
|
+
- Python 3.11+
|
|
35
|
+
- A local Sonic Pi installation or checkout.
|
|
36
|
+
- The Sonic Pi root directory must contain:
|
|
37
|
+
- `app/server/ruby/bin/daemon.rb`
|
|
38
|
+
- `app/server/ruby/bin/spider-server.rb`
|
|
39
|
+
- usually `etc/doc`, `etc/samples`, and `etc/synthdefs`
|
|
40
|
+
|
|
41
|
+
No machine-specific path is baked into this package. Set `SONIC_PI_ROOT` in the
|
|
42
|
+
MCP client environment unless you pass `root_path` to `sonic_start`.
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
From PyPI, after the package is published:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install sonic-pi-mcp
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
From a local checkout:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install .
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Build a wheel/sdist:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
python -m build
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Then install the wheel on another machine:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install dist/sonic_pi_mcp-0.1.0-py3-none-any.whl
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The wheel only contains the Python package under `src/sonic_pi_mcp`. Generated
|
|
71
|
+
runtime files, exported audio, examples, tests, and local scripts are excluded
|
|
72
|
+
from distribution.
|
|
73
|
+
|
|
74
|
+
## Publish to PyPI
|
|
75
|
+
|
|
76
|
+
This repository is prepared for PyPI Trusted Publishing through GitHub Actions.
|
|
77
|
+
No PyPI API token should be stored in the repository.
|
|
78
|
+
|
|
79
|
+
Configure a PyPI Trusted Publisher for the package:
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
PyPI project name: sonic-pi-mcp
|
|
83
|
+
GitHub owner: WEEZZ-admin
|
|
84
|
+
GitHub repository: sonic-pi-mcp
|
|
85
|
+
Workflow name: publish.yml
|
|
86
|
+
Environment name: pypi
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Then publish a GitHub Release. The workflow in `.github/workflows/publish.yml`
|
|
90
|
+
will build the wheel/sdist and upload them to PyPI.
|
|
91
|
+
|
|
92
|
+
Before each release, update `version` in `pyproject.toml`. PyPI does not allow
|
|
93
|
+
re-uploading the same version.
|
|
94
|
+
|
|
95
|
+
Recommended local preflight:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
python -m pip install --upgrade build twine
|
|
99
|
+
python -m build
|
|
100
|
+
python -m twine check dist/*
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Configuration
|
|
104
|
+
|
|
105
|
+
Required in most deployments:
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
SONIC_PI_ROOT=<path to the Sonic Pi root directory>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Useful optional variables:
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
SONIC_PI_MCP_RUNTIME_DIR=<writable directory for temporary run_file buffers>
|
|
115
|
+
SONIC_PI_MCP_STARTUP_TIMEOUT=60
|
|
116
|
+
SONIC_PI_MCP_KEEPALIVE_INTERVAL=4
|
|
117
|
+
SONIC_PI_MCP_EVENT_BUFFER_SIZE=5000
|
|
118
|
+
SONIC_PI_MCP_DEFAULT_COLLECT_MS=1500
|
|
119
|
+
SONIC_PI_HOME=<custom Sonic Pi user-home root for logs, if needed>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`SONIC_PI_MCP_RUNTIME_DIR` is used when code is too large for Sonic Pi's OSC
|
|
123
|
+
packet size and must be submitted with `run_file`. If it is not set, the server
|
|
124
|
+
uses a per-user cache directory such as `%LOCALAPPDATA%\sonic-pi-mcp` on
|
|
125
|
+
Windows, `~/Library/Caches/sonic-pi-mcp` on macOS, or
|
|
126
|
+
`${XDG_CACHE_HOME:-~/.cache}/sonic-pi-mcp` on Linux.
|
|
127
|
+
|
|
128
|
+
PowerShell example without hard-coding a drive:
|
|
129
|
+
|
|
130
|
+
```powershell
|
|
131
|
+
$env:SONIC_PI_ROOT = Join-Path $env:ProgramFiles 'Sonic Pi'
|
|
132
|
+
$env:SONIC_PI_MCP_RUNTIME_DIR = Join-Path $env:LOCALAPPDATA 'sonic-pi-mcp'
|
|
133
|
+
sonic-pi-mcp
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
POSIX shell example:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
export SONIC_PI_ROOT="$HOME/apps/sonic-pi"
|
|
140
|
+
export SONIC_PI_MCP_RUNTIME_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/sonic-pi-mcp"
|
|
141
|
+
sonic-pi-mcp
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## MCP Client Setup
|
|
145
|
+
|
|
146
|
+
This package is a `stdio` MCP server. Configure clients to run the installed
|
|
147
|
+
console command `sonic-pi-mcp`.
|
|
148
|
+
|
|
149
|
+
Generic MCP JSON shape:
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"mcpServers": {
|
|
154
|
+
"sonic-pi": {
|
|
155
|
+
"command": "sonic-pi-mcp",
|
|
156
|
+
"args": [],
|
|
157
|
+
"env": {
|
|
158
|
+
"SONIC_PI_ROOT": "<path to Sonic Pi root>",
|
|
159
|
+
"SONIC_PI_MCP_RUNTIME_DIR": "<writable runtime directory>"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
If your client does not inherit shell environment variables, put the variables
|
|
167
|
+
in the client config. Avoid relying on the terminal profile of the user who
|
|
168
|
+
installed the package.
|
|
169
|
+
|
|
170
|
+
## Run Manually
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
python -m sonic_pi_mcp
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
or:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
sonic-pi-mcp
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Both commands run the same `stdio` MCP server. They do not open an HTTP port.
|
|
183
|
+
|
|
184
|
+
## MCP Tools
|
|
185
|
+
|
|
186
|
+
- `sonic_start(root_path?, no_inputs?)`
|
|
187
|
+
- `sonic_status()`
|
|
188
|
+
- `sonic_run_code(code, buffer_name?, collect_ms?)`
|
|
189
|
+
- `sonic_stop(collect_ms?)`
|
|
190
|
+
- `sonic_shutdown()`
|
|
191
|
+
- `sonic_read_events(since?, limit?)`
|
|
192
|
+
- `sonic_get_logs(source?, tail?)`
|
|
193
|
+
- `sonic_send_cue(path, args?)`
|
|
194
|
+
- `sonic_search_docs(query, limit?, root_path?)`
|
|
195
|
+
- `sonic_list_samples(limit?, root_path?)`
|
|
196
|
+
- `sonic_list_synths(limit?, root_path?)`
|
|
197
|
+
- `sonic_list_fx(limit?, root_path?)`
|
|
198
|
+
|
|
199
|
+
## Suggested Agent Workflow
|
|
200
|
+
|
|
201
|
+
1. Call `sonic_start(no_inputs=true)` unless the user needs audio input.
|
|
202
|
+
2. Call `sonic_status()` and confirm `state` is `ready`.
|
|
203
|
+
3. Use `sonic_search_docs`, `sonic_list_samples`, `sonic_list_synths`, and
|
|
204
|
+
`sonic_list_fx` to stay within the user's installed Sonic Pi version.
|
|
205
|
+
4. Send music with `sonic_run_code(code, buffer_name, collect_ms)`.
|
|
206
|
+
5. Inspect returned events for `syntax_error`, `runtime_error`, or missing
|
|
207
|
+
`Defining fn :live_loop_...` messages.
|
|
208
|
+
6. Call `sonic_stop()` before replacing a long-running composition.
|
|
209
|
+
7. Call `sonic_shutdown()` when the session is no longer needed.
|
|
210
|
+
|
|
211
|
+
## Security
|
|
212
|
+
|
|
213
|
+
`sonic_run_code` executes local Sonic Pi code through the same token-protected
|
|
214
|
+
Spider API used by the Sonic Pi GUI. Treat access to this MCP server as local
|
|
215
|
+
code execution and local audio-device control.
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
MIT License. You may use, copy, modify, publish, distribute, sublicense, and
|
|
220
|
+
sell copies of this package, provided the license text is included.
|
|
221
|
+
|
|
222
|
+
## Packaging Notes
|
|
223
|
+
|
|
224
|
+
The package is intentionally path-neutral:
|
|
225
|
+
|
|
226
|
+
- No repository-local absolute path is embedded.
|
|
227
|
+
- `SONIC_PI_ROOT` or the `root_path` tool argument identifies Sonic Pi.
|
|
228
|
+
- `SONIC_PI_MCP_RUNTIME_DIR` controls where temporary large-buffer files are
|
|
229
|
+
written.
|
|
230
|
+
- Build configuration excludes generated files such as `.runtime/`, `exports/`,
|
|
231
|
+
examples, tests, and local playback/export scripts.
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# sonic-pi-mcp
|
|
2
|
+
|
|
3
|
+
`sonic-pi-mcp` is a Python MCP server that lets an MCP client control a local
|
|
4
|
+
Sonic Pi runtime over the standard `stdio` transport.
|
|
5
|
+
|
|
6
|
+
It starts Sonic Pi's Ruby daemon, sends OSC messages to the Spider runtime, runs
|
|
7
|
+
Sonic Pi code, stops jobs, reads runtime events/logs, and searches the local
|
|
8
|
+
Sonic Pi docs/samples/synthdefs.
|
|
9
|
+
|
|
10
|
+
## Requirements
|
|
11
|
+
|
|
12
|
+
- Python 3.11+
|
|
13
|
+
- A local Sonic Pi installation or checkout.
|
|
14
|
+
- The Sonic Pi root directory must contain:
|
|
15
|
+
- `app/server/ruby/bin/daemon.rb`
|
|
16
|
+
- `app/server/ruby/bin/spider-server.rb`
|
|
17
|
+
- usually `etc/doc`, `etc/samples`, and `etc/synthdefs`
|
|
18
|
+
|
|
19
|
+
No machine-specific path is baked into this package. Set `SONIC_PI_ROOT` in the
|
|
20
|
+
MCP client environment unless you pass `root_path` to `sonic_start`.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
From PyPI, after the package is published:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install sonic-pi-mcp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
From a local checkout:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install .
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Build a wheel/sdist:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
python -m build
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then install the wheel on another machine:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install dist/sonic_pi_mcp-0.1.0-py3-none-any.whl
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The wheel only contains the Python package under `src/sonic_pi_mcp`. Generated
|
|
49
|
+
runtime files, exported audio, examples, tests, and local scripts are excluded
|
|
50
|
+
from distribution.
|
|
51
|
+
|
|
52
|
+
## Publish to PyPI
|
|
53
|
+
|
|
54
|
+
This repository is prepared for PyPI Trusted Publishing through GitHub Actions.
|
|
55
|
+
No PyPI API token should be stored in the repository.
|
|
56
|
+
|
|
57
|
+
Configure a PyPI Trusted Publisher for the package:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
PyPI project name: sonic-pi-mcp
|
|
61
|
+
GitHub owner: WEEZZ-admin
|
|
62
|
+
GitHub repository: sonic-pi-mcp
|
|
63
|
+
Workflow name: publish.yml
|
|
64
|
+
Environment name: pypi
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Then publish a GitHub Release. The workflow in `.github/workflows/publish.yml`
|
|
68
|
+
will build the wheel/sdist and upload them to PyPI.
|
|
69
|
+
|
|
70
|
+
Before each release, update `version` in `pyproject.toml`. PyPI does not allow
|
|
71
|
+
re-uploading the same version.
|
|
72
|
+
|
|
73
|
+
Recommended local preflight:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
python -m pip install --upgrade build twine
|
|
77
|
+
python -m build
|
|
78
|
+
python -m twine check dist/*
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Configuration
|
|
82
|
+
|
|
83
|
+
Required in most deployments:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
SONIC_PI_ROOT=<path to the Sonic Pi root directory>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Useful optional variables:
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
SONIC_PI_MCP_RUNTIME_DIR=<writable directory for temporary run_file buffers>
|
|
93
|
+
SONIC_PI_MCP_STARTUP_TIMEOUT=60
|
|
94
|
+
SONIC_PI_MCP_KEEPALIVE_INTERVAL=4
|
|
95
|
+
SONIC_PI_MCP_EVENT_BUFFER_SIZE=5000
|
|
96
|
+
SONIC_PI_MCP_DEFAULT_COLLECT_MS=1500
|
|
97
|
+
SONIC_PI_HOME=<custom Sonic Pi user-home root for logs, if needed>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`SONIC_PI_MCP_RUNTIME_DIR` is used when code is too large for Sonic Pi's OSC
|
|
101
|
+
packet size and must be submitted with `run_file`. If it is not set, the server
|
|
102
|
+
uses a per-user cache directory such as `%LOCALAPPDATA%\sonic-pi-mcp` on
|
|
103
|
+
Windows, `~/Library/Caches/sonic-pi-mcp` on macOS, or
|
|
104
|
+
`${XDG_CACHE_HOME:-~/.cache}/sonic-pi-mcp` on Linux.
|
|
105
|
+
|
|
106
|
+
PowerShell example without hard-coding a drive:
|
|
107
|
+
|
|
108
|
+
```powershell
|
|
109
|
+
$env:SONIC_PI_ROOT = Join-Path $env:ProgramFiles 'Sonic Pi'
|
|
110
|
+
$env:SONIC_PI_MCP_RUNTIME_DIR = Join-Path $env:LOCALAPPDATA 'sonic-pi-mcp'
|
|
111
|
+
sonic-pi-mcp
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
POSIX shell example:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
export SONIC_PI_ROOT="$HOME/apps/sonic-pi"
|
|
118
|
+
export SONIC_PI_MCP_RUNTIME_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/sonic-pi-mcp"
|
|
119
|
+
sonic-pi-mcp
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## MCP Client Setup
|
|
123
|
+
|
|
124
|
+
This package is a `stdio` MCP server. Configure clients to run the installed
|
|
125
|
+
console command `sonic-pi-mcp`.
|
|
126
|
+
|
|
127
|
+
Generic MCP JSON shape:
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"mcpServers": {
|
|
132
|
+
"sonic-pi": {
|
|
133
|
+
"command": "sonic-pi-mcp",
|
|
134
|
+
"args": [],
|
|
135
|
+
"env": {
|
|
136
|
+
"SONIC_PI_ROOT": "<path to Sonic Pi root>",
|
|
137
|
+
"SONIC_PI_MCP_RUNTIME_DIR": "<writable runtime directory>"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
If your client does not inherit shell environment variables, put the variables
|
|
145
|
+
in the client config. Avoid relying on the terminal profile of the user who
|
|
146
|
+
installed the package.
|
|
147
|
+
|
|
148
|
+
## Run Manually
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
python -m sonic_pi_mcp
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
or:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
sonic-pi-mcp
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Both commands run the same `stdio` MCP server. They do not open an HTTP port.
|
|
161
|
+
|
|
162
|
+
## MCP Tools
|
|
163
|
+
|
|
164
|
+
- `sonic_start(root_path?, no_inputs?)`
|
|
165
|
+
- `sonic_status()`
|
|
166
|
+
- `sonic_run_code(code, buffer_name?, collect_ms?)`
|
|
167
|
+
- `sonic_stop(collect_ms?)`
|
|
168
|
+
- `sonic_shutdown()`
|
|
169
|
+
- `sonic_read_events(since?, limit?)`
|
|
170
|
+
- `sonic_get_logs(source?, tail?)`
|
|
171
|
+
- `sonic_send_cue(path, args?)`
|
|
172
|
+
- `sonic_search_docs(query, limit?, root_path?)`
|
|
173
|
+
- `sonic_list_samples(limit?, root_path?)`
|
|
174
|
+
- `sonic_list_synths(limit?, root_path?)`
|
|
175
|
+
- `sonic_list_fx(limit?, root_path?)`
|
|
176
|
+
|
|
177
|
+
## Suggested Agent Workflow
|
|
178
|
+
|
|
179
|
+
1. Call `sonic_start(no_inputs=true)` unless the user needs audio input.
|
|
180
|
+
2. Call `sonic_status()` and confirm `state` is `ready`.
|
|
181
|
+
3. Use `sonic_search_docs`, `sonic_list_samples`, `sonic_list_synths`, and
|
|
182
|
+
`sonic_list_fx` to stay within the user's installed Sonic Pi version.
|
|
183
|
+
4. Send music with `sonic_run_code(code, buffer_name, collect_ms)`.
|
|
184
|
+
5. Inspect returned events for `syntax_error`, `runtime_error`, or missing
|
|
185
|
+
`Defining fn :live_loop_...` messages.
|
|
186
|
+
6. Call `sonic_stop()` before replacing a long-running composition.
|
|
187
|
+
7. Call `sonic_shutdown()` when the session is no longer needed.
|
|
188
|
+
|
|
189
|
+
## Security
|
|
190
|
+
|
|
191
|
+
`sonic_run_code` executes local Sonic Pi code through the same token-protected
|
|
192
|
+
Spider API used by the Sonic Pi GUI. Treat access to this MCP server as local
|
|
193
|
+
code execution and local audio-device control.
|
|
194
|
+
|
|
195
|
+
## License
|
|
196
|
+
|
|
197
|
+
MIT License. You may use, copy, modify, publish, distribute, sublicense, and
|
|
198
|
+
sell copies of this package, provided the license text is included.
|
|
199
|
+
|
|
200
|
+
## Packaging Notes
|
|
201
|
+
|
|
202
|
+
The package is intentionally path-neutral:
|
|
203
|
+
|
|
204
|
+
- No repository-local absolute path is embedded.
|
|
205
|
+
- `SONIC_PI_ROOT` or the `root_path` tool argument identifies Sonic Pi.
|
|
206
|
+
- `SONIC_PI_MCP_RUNTIME_DIR` controls where temporary large-buffer files are
|
|
207
|
+
written.
|
|
208
|
+
- Build configuration excludes generated files such as `.runtime/`, `exports/`,
|
|
209
|
+
examples, tests, and local playback/export scripts.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "sonic-pi-mcp"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "MCP server for controlling a local Sonic Pi runtime"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.11"
|
|
9
|
+
dependencies = [
|
|
10
|
+
"mcp>=1.28.1,<2.0.0",
|
|
11
|
+
]
|
|
12
|
+
keywords = ["mcp", "sonic-pi", "music", "osc", "stdio"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 3 - Alpha",
|
|
15
|
+
"Environment :: Console",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://github.com/WEEZZ-admin/sonic-pi-mcp"
|
|
26
|
+
Repository = "https://github.com/WEEZZ-admin/sonic-pi-mcp"
|
|
27
|
+
Issues = "https://github.com/WEEZZ-admin/sonic-pi-mcp/issues"
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
sonic-pi-mcp = "sonic_pi_mcp.server:main"
|
|
31
|
+
|
|
32
|
+
[build-system]
|
|
33
|
+
requires = ["hatchling"]
|
|
34
|
+
build-backend = "hatchling.build"
|
|
35
|
+
|
|
36
|
+
[tool.hatch.build]
|
|
37
|
+
exclude = [
|
|
38
|
+
"/.agents",
|
|
39
|
+
"/.codex",
|
|
40
|
+
"/.git",
|
|
41
|
+
"/.runtime",
|
|
42
|
+
"/assets",
|
|
43
|
+
"/dist",
|
|
44
|
+
"/exports",
|
|
45
|
+
"/examples",
|
|
46
|
+
"/scripts",
|
|
47
|
+
"/tests",
|
|
48
|
+
"**/__pycache__",
|
|
49
|
+
"**/*.pyc",
|
|
50
|
+
"**/*.wav",
|
|
51
|
+
"**/*.flac",
|
|
52
|
+
"**/*.aiff",
|
|
53
|
+
"**/*.aif",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
[tool.hatch.build.targets.wheel]
|
|
57
|
+
packages = ["src/sonic_pi_mcp"]
|
|
58
|
+
|
|
59
|
+
[tool.hatch.build.targets.sdist]
|
|
60
|
+
include = [
|
|
61
|
+
"/src/sonic_pi_mcp",
|
|
62
|
+
"/LICENSE",
|
|
63
|
+
"/README.md",
|
|
64
|
+
"/pyproject.toml",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
[tool.ruff]
|
|
68
|
+
line-length = 100
|
|
69
|
+
target-version = "py311"
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class Config:
|
|
11
|
+
sonic_pi_root: Path | None = None
|
|
12
|
+
runtime_dir: Path | None = None
|
|
13
|
+
startup_timeout: float = 60.0
|
|
14
|
+
keepalive_interval: float = 4.0
|
|
15
|
+
event_buffer_size: int = 5000
|
|
16
|
+
default_collect_ms: int = 1500
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def from_env(cls) -> "Config":
|
|
20
|
+
root = os.environ.get("SONIC_PI_ROOT")
|
|
21
|
+
runtime_dir = os.environ.get("SONIC_PI_MCP_RUNTIME_DIR")
|
|
22
|
+
return cls(
|
|
23
|
+
sonic_pi_root=Path(root).expanduser() if root else None,
|
|
24
|
+
runtime_dir=Path(runtime_dir).expanduser() if runtime_dir else None,
|
|
25
|
+
startup_timeout=_float_env("SONIC_PI_MCP_STARTUP_TIMEOUT", 60.0),
|
|
26
|
+
keepalive_interval=_float_env("SONIC_PI_MCP_KEEPALIVE_INTERVAL", 4.0),
|
|
27
|
+
event_buffer_size=_int_env("SONIC_PI_MCP_EVENT_BUFFER_SIZE", 5000),
|
|
28
|
+
default_collect_ms=_int_env("SONIC_PI_MCP_DEFAULT_COLLECT_MS", 1500),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def resolved_runtime_dir(self) -> Path:
|
|
32
|
+
if self.runtime_dir:
|
|
33
|
+
return self.runtime_dir.expanduser()
|
|
34
|
+
return default_runtime_dir()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def default_runtime_dir() -> Path:
|
|
38
|
+
if sys.platform == "win32":
|
|
39
|
+
base = os.environ.get("LOCALAPPDATA") or os.environ.get("APPDATA")
|
|
40
|
+
if base:
|
|
41
|
+
return Path(base) / "sonic-pi-mcp"
|
|
42
|
+
elif sys.platform == "darwin":
|
|
43
|
+
return Path.home() / "Library" / "Caches" / "sonic-pi-mcp"
|
|
44
|
+
else:
|
|
45
|
+
base = os.environ.get("XDG_CACHE_HOME")
|
|
46
|
+
if base:
|
|
47
|
+
return Path(base) / "sonic-pi-mcp"
|
|
48
|
+
return Path.home() / ".cache" / "sonic-pi-mcp"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _float_env(name: str, default: float) -> float:
|
|
52
|
+
raw = os.environ.get(name)
|
|
53
|
+
if raw is None:
|
|
54
|
+
return default
|
|
55
|
+
try:
|
|
56
|
+
return float(raw)
|
|
57
|
+
except ValueError:
|
|
58
|
+
return default
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _int_env(name: str, default: int) -> int:
|
|
62
|
+
raw = os.environ.get(name)
|
|
63
|
+
if raw is None:
|
|
64
|
+
return default
|
|
65
|
+
try:
|
|
66
|
+
return int(raw)
|
|
67
|
+
except ValueError:
|
|
68
|
+
return default
|