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.
@@ -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,6 @@
1
+ """MCP server for controlling a local Sonic Pi runtime."""
2
+
3
+ __all__ = ["__version__"]
4
+
5
+ __version__ = "0.1.0"
6
+
@@ -0,0 +1,6 @@
1
+ from .server import main
2
+
3
+
4
+ if __name__ == "__main__":
5
+ main()
6
+
@@ -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
@@ -0,0 +1,2 @@
1
+ """Local Sonic Pi documentation index helpers."""
2
+