1. Conduid
  2. Communication
  3. Sonicpi MCP
MCP server · Communication

Sonicpi MCP

MCP server for Sonic Pi. Control live coding music sessions via LLMs using Streamable HTTP + OSC, implemented in Rust.

Unclaimed comms
34Low

Scored 6 months ago · breakdown

About Sonicpi MCP

Sonicpi MCP is an MCP server in the Communication category: mCP server for Sonic Pi. Control live coding music sessions via LLMs using Streamable HTTP + OSC, implemented in Rust.

Install

From source
git clone https://github.com/petrijr/sonicpi-mcp

This server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.

Ask AI

✦

Ask AI about Sonicpi MCP

Powered by Claude · Grounded in docs

I know everything about Sonicpi MCP. Ask me about installation, configuration, usage, or troubleshooting.

Security checks

  • ✓README presentThe repository ships documentation.

5 checks have not been run yet.

README

Sonic Pi MCP Server

This is a Rust MCP server that sends OSC commands to a running Sonic Pi for live audible feedback.

✅ Sonic Pi is expected to be running normally (GUI open, audio on).
Tool calls modify music in real time (usually immediately or on the next live_loop iteration).

Quick demo

Example prompt used to generate a Sonic Pi jam --> assets/gpt52-jam.mp3

Setup:

  • sonicpi-mcp running from this repository.
  • MCP added to Codex CLI.
  • Sonic Pi 4.6 running in Windows.
  • Codex CLI prompted to generate a jam, it automatically generated it and sent it to be played on Sonic Pi.
  • Recorded the loop, saved it as wav and converted to mp3 with Audacity.

Another one, this time prompted with Jetbrains AI.

![Example prompt in Jetbrains AI] -> assets\jetbrains-acid.mp3


Prerequisites

1) Install & run Sonic Pi (Windows)

  1. Install Sonic Pi for Windows
  2. Launch Sonic Pi manually
  3. Verify audio works by pressing Run on a simple buffer, e.g.:
live_loop :beat do
  sample :bd_haus
  sleep 0.5
end

Leave Sonic Pi running while you use this MCP server.

Install / Releases

You can run from source or from GitHub Release artifacts.

From source:

cargo run

From Releases:

  • Download the asset that matches your platform:
    • sonicpi-mcp-x86_64-pc-windows-msvc.zip
    • sonicpi-mcp-x86_64-unknown-linux-gnu.tar.gz
    • sonicpi-mcp-x86_64-apple-darwin.tar.gz
  • Extract it and run the binary:
    • Windows: sonicpi-mcp.exe
    • macOS/Linux: ./sonicpi-mcp

Run the MCP server (Windows)

From the repo root:

cargo run

Endpoint:

  • http://127.0.0.1:8787/mcp

Auto-discovery (default)

By default the server reads:

  • %USERPROFILE%\.sonic-pi\log\gui.log

and discovers:

  • Spider port from: Setting up OSC sender to Spider on port ####
  • Token from: the last daemon_stdout: ######### line where the number is > 65535

Configuration overrides (PowerShell)

You can override discovery with environment variables:

# Where Sonic Pi is running
$env:SONICPI_HOST = "127.0.0.1"

# Optional: point directly at gui.log
$env:SONICPI_GUI_LOG = "C:\Users\<home>\.sonic-pi\log\gui.log"

# Optional: hard override values (debugging)
$env:SONICPI_SERVER_PORT = "37560"
$env:SONICPI_TOKEN = "814946186"

# Required to enable sonicpi_send_osc (default deny)
$env:SONICPI_OSC_ALLOWLIST = "/cue/*"

If SONICPI_SERVER_PORT and SONICPI_TOKEN are set, the server will not read gui.log.

Quick manual tests (Windows PowerShell)

$uri = "http://127.0.0.1:8787/mcp"

Initialize

$body = @{
  jsonrpc = "2.0"
  id      = 1
  method  = "initialize"
  params  = @{}
} | ConvertTo-Json -Depth 10

Invoke-RestMethod -Method Post -Uri $uri -ContentType "application/json" -Body $body |
  ConvertTo-Json -Depth 20

List tools

$body = @{
  jsonrpc = "2.0"
  id      = 2
  method  = "tools/list"
  params  = @{}
} | ConvertTo-Json -Depth 10

Invoke-RestMethod -Method Post -Uri $uri -ContentType "application/json" -Body $body |
  ConvertTo-Json -Depth 20

Run code in Sonic Pi (live)

$code = @"
live_loop :beat do
  sample :bd_haus
  sleep 0.5
end
"@

$body = @{
  jsonrpc = "2.0"
  id      = 3
  method  = "tools/call"
  params  = @{
    name      = "sonicpi_run_code"
    arguments = @{
      code = $code
    }
  }
} | ConvertTo-Json -Depth 20

Invoke-RestMethod -Method Post -Uri $uri -ContentType "application/json" -Body $body |
  ConvertTo-Json -Depth 20

Stop all jobs

$body = @{
  jsonrpc = "2.0"
  id      = 4
  method  = "tools/call"
  params  = @{
    name      = "sonicpi_stop_all"
    arguments = @{}
  }
} | ConvertTo-Json -Depth 10

Invoke-RestMethod -Method Post -Uri $uri -ContentType "application/json" -Body $body |
  ConvertTo-Json -Depth 20

Implemented OSC commands

  • /run-code with args [token, code] (sent to discovered Spider port)
  • /stop-all-jobs is sent both tokened [token] and tokenless [] (best-effort for compatibility)
  • sonicpi_send_osc is default-deny and only allows OSC paths listed in SONICPI_OSC_ALLOWLIST
  • sonicpi_cue sends /cue/<name> and works well with SONICPI_OSC_ALLOWLIST="/cue/*"
  • sonicpi_set sends /set/<key> and works well with SONICPI_OSC_ALLOWLIST="/set/*"
  • sonicpi_run_code_status reports the current-program guardrail state
  • sonicpi_metrics reports lightweight in-memory counters

Note: tool names use underscores for client compatibility (e.g. JetBrains AI). Dotted aliases like sonicpi.run_code are still accepted.

OSC allowlist (default deny)

sonicpi_send_osc is disabled unless you set SONICPI_OSC_ALLOWLIST.

Format:

  • Comma-separated OSC paths.
  • Wildcards are supported as a suffix * and act as a prefix match.

Examples (PowerShell):

# Allow all cues (recommended starting point)
$env:SONICPI_OSC_ALLOWLIST = "/cue/*"

# Allow all sets
$env:SONICPI_OSC_ALLOWLIST = "/set/*"

# Allow both cues and sets
$env:SONICPI_OSC_ALLOWLIST = "/cue/*,/set/*"

# Allow specific addresses only
$env:SONICPI_OSC_ALLOWLIST = "/cue/tempo,/cue/section,/set/bpm"

Sonic Pi live-control template

A cue/set-friendly starter buffer is available at:

  • examples/live_control_template.rb
  • examples/cue_transition_template.rb (section changes via sonicpi_cue)

Suggested allowlist for the template:

$env:SONICPI_OSC_ALLOWLIST = "/cue/*,/set/*"

Example live controls:

# Change tempo without rewriting the whole buffer
Invoke-RestMethod -Method Post -Uri http://127.0.0.1:8787/mcp -ContentType "application/json" -Body (@{
  jsonrpc = "2.0"
  id      = 100
  method  = "tools/call"
  params  = @{
    name      = "sonicpi_set"
    arguments = @{ key = "tempo"; value = 140 }
  }
} | ConvertTo-Json -Depth 10)

# Trigger a cue that loops can sync to
Invoke-RestMethod -Method Post -Uri http://127.0.0.1:8787/mcp -ContentType "application/json" -Body (@{
  jsonrpc = "2.0"
  id      = 101
  method  = "tools/call"
  params  = @{
    name      = "sonicpi_cue"
    arguments = @{ name = "mode"; args = @(1) }
  }
} | ConvertTo-Json -Depth 10)

Recommended live workflow

  1. Start Sonic Pi manually (GUI open, audio on).
  2. Run the template once using sonicpi_run_code (from examples/live_control_template.rb).
  3. Avoid full rewrites during playback.
  4. Evolve the music with small controls:
    • Use sonicpi_set for state (e.g., tempo, intensity, mode, root)
    • Use sonicpi_cue for synced events (e.g., tempo, mode, section)

This keeps audio stable while still allowing expressive live changes.

Session model and run_code guardrail

This server targets a single Sonic Pi instance, but guardrails can be scoped with an optional session_id (default: "global").

To reduce accidental loop duplication, sonicpi_run_code blocks rapid duplicate submissions of identical code per session_id for a short window.

Configure the window (default: 1000ms):

$env:SONICPI_RUN_CODE_DEDUPE_MS = "1000"

# Optional: managed program mode (stop all jobs before run_code)
$env:SONICPI_MANAGED_PROGRAM = "1"

Override the guardrail per call by setting force = true:

{
  "jsonrpc": "2.0",
  "id": 200,
  "method": "tools/call",
  "params": {
    "name": "sonicpi_run_code",
    "arguments": {
      "code": "live_loop :beat do\n  sample :bd_haus\n  sleep 0.5\nend",
      "force": true,
      "session_id": "jam-a",
      "managed": true
    }
  }
}

Check current-program guardrail state (optionally per session):

{
  "jsonrpc": "2.0",
  "id": 201,
  "method": "tools/call",
  "params": {
    "name": "sonicpi_run_code_status",
    "arguments": { "session_id": "jam-a" }
  }
}

Example MCP workflow (safe live evolution)

  1. Set allowlists:
    • SONICPI_OSC_ALLOWLIST="/cue/*,/set/*"
    • Optional SSE filter: SONICPI_OSC_IN_ALLOWLIST="/cue/*,/set/*"
  2. Run the template once with sonicpi_run_code from examples/live_control_template.rb.
  3. During playback, prefer:
    • sonicpi_set for state changes (tempo, intensity, mode, root)
    • sonicpi_cue for synced transitions/events
  4. Use sonicpi_stop_all to recover quickly from runaway loops.
  5. Use sonicpi_run_code_status if you suspect duplicate run_code calls are being blocked.

OSC listener → SSE (feedback loop)

The server can listen for inbound OSC (e.g., Sonic Pi cues) and forward them to SSE clients.

Enable it explicitly (disabled by default to avoid port conflicts in tests):

$env:SONICPI_ENABLE_LISTENER = "1"
$env:SONICPI_LISTEN_HOST = "0.0.0.0"
$env:SONICPI_LISTEN_PORT = "4559"

# Optional: inbound OSC filter for SSE (default allow)
$env:SONICPI_OSC_IN_ALLOWLIST = "/cue/*,/set/*"

# Optional: tag inbound OSC events with a session_id (default: global)
$env:SONICPI_OSC_IN_SESSION_ID = "global"

# Optional: inbound OSC SSE spam protection
$env:SONICPI_OSC_IN_MIN_INTERVAL_MS = "25"
$env:SONICPI_OSC_IN_DEDUPE_MS = "100"

When enabled, SSE clients may receive events like:

{
  "type": "osc.in",
  "ts_ms": 1769530000000,
  "from": "127.0.0.1:4559",
  "address": "/cue/tempo",
  "args": [140]
}

SSE event types currently include:

  • osc.in: a single OSC message
  • osc.bundle.in: an OSC bundle flattened into events
  • tool.call: structured tool lifecycle events (start and ok)

tool.call schema (example):

{
  "type": "tool.call",
  "tool": "sonicpi_run_code",
  "stage": "start",
  "request_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "detail": {
    "spider_port": 37560,
    "code_hash": 1234567890,
    "force": false
  }
}

Simple curl-based SSE client:

curl -N -H "Accept: text/event-stream" http://127.0.0.1:8787/mcp

Per-session SSE filtering (matches session_id, default is global):

curl -N -H "Accept: text/event-stream" "http://127.0.0.1:8787/mcp?session_id=jam-a"

SSE contract reference:

  • docs/SSE-CONTRACT.md
  • docs/MCP-WORKFLOWS.md

Metrics

You can retrieve lightweight in-memory counters via sonicpi_metrics.

Example request:

{
  "jsonrpc": "2.0",
  "id": 300,
  "method": "tools/call",
  "params": {
    "name": "sonicpi_metrics",
    "arguments": {}
  }
}

The response includes counters for:

  • inbound OSC receive/publish/drop paths
  • SSE session filtering
  • tool call lifecycle counts

Troubleshooting

  • If discovery fails, call sonicpi_health to see the error message.
  • If sonicpi_run_code does nothing, check that gui.log contains the Spider port line and a token value. You can also temporarily set SONICPI_SERVER_PORT and SONICPI_TOKEN as overrides.

README copy captured when this server was indexed; it may lag the repository. The original is authoritative.

Questions

About Sonicpi MCP

How do I install Sonicpi MCP?

No package has been published for this server, so install it from source: clone the repository and follow its README.

Is Sonicpi MCP safe to use with an AI agent?

Its trust score is 34 out of 100 (low). It passes 1 of the 1 static security checks run so far. It has no ConduID identity yet, so agent calls to it are not receipted.

Is Sonicpi MCP still maintained?

Conduid hasn't recorded a commit date for this repository yet. Check the repository directly for recent activity.