pd-mcp
Basic MCP server for agentic interaction with vanilla Pure Data.
This project is intentionally shaped after the Max/MSP MCP workflow described in the ISMIR 2025 late-breaking demo paper and the associated Max reference implementation, but adapted to what is practical in plain vanilla Pd:
- bundled object docs for in-context lookup
- live patch creation and rewiring
- direct object/message/atom creation
- patch-state inspection
- runtime bang/message/number injection
- DSP on/off control
Architecture
The system has two parts:
- A Python MCP server that owns an authoritative graph model of the patch.
- A vanilla Pd bridge patch that listens on UDP port
5000and forwards dynamic patching messages into a managed subpatch canvas.
Instead of trying to delete or mutate arbitrary objects inside Pd one-at-a-time, the server updates its graph model and resynchronizes the target canvas by sending:
clear- object creation messages
- optional hidden control receivers for explicitly controllable objects
- connection messages
That tradeoff is deliberate. It is simpler and more reliable in vanilla Pd, while still feeling agentic from the MCP client side.
Included Tools
list_pd_objectssearch_pd_objectsget_pd_object_docget_patch_stateadd_pd_objectremove_pd_objectconnect_pd_objectsdisconnect_pd_objectsset_object_textmove_pd_objectclear_patchsync_patchset_dspsend_bang_to_objectsend_message_to_objectset_number
Project Layout
src/pd_mcp/server.py: MCP tool definitionssrc/pd_mcp/model.py: in-memory patch graph and Pd index layoutsrc/pd_mcp/bridge.py: UDP FUDI bridge to Pdsrc/pd_mcp/pd_docs.json: small bundled docs set for common vanilla objectspd/pd_mcp_bridge.pd: bridge patch to open in Pure Data
Install
Using uv:
uv venv
source .venv/bin/activate
uv pip install -e .
Or with pip:
python -m venv .venv
source .venv/bin/activate
pip install -e .
Run
- Open
pd/pd_mcp_bridge.pdin vanilla Pure Data. - Keep the bridge patch open.
- Start the MCP server:
python main.py
Environment variables:
PD_MCP_HOSTdefaults to127.0.0.1PD_MCP_PORTdefaults to5000
Cursor MCP Config
Add something like this to your MCP config:
{
"mcpServers": {
"pd-mcp": {
"command": "/bin/zsh",
"args": [
"-lc",
"cd /Users/chrisdonahue/Code/pd-mcp && source .venv/bin/activate && python main.py"
]
}
}
}
Typical Workflow
- Call
add_pd_objecta few times to createobj,msg,text, or atom boxes. - Use
connect_pd_objectsto wire them. - Only set
controllable=trueonadd_pd_objectwhen you want runtime tools likesend_message_to_object,send_bang_to_object, orset_number. - Call
get_patch_statewhenever the agent needs a reliable snapshot.
Example object boxes:
box_type="obj", text="osc~ 440"box_type="obj", text="*~ 0.1"box_type="obj", text="dac~"box_type="msg", text="440"box_type="floatatom"box_type="obj", text="line~", controllable=true
Limitations
- The bundled docs are intentionally small, not a full export of the Pd manual.
- The server manages only the objects it created in the bridge patch's target subpatch.
- Selection introspection is not implemented in this first cut.
- Object attributes in the Max sense do not map cleanly onto vanilla Pd, so the API is text-centric instead.
- Because sync is graph-based, manual edits inside the managed target subpatch can be overwritten.
Why This Shape
The Max paper emphasizes two ideas:
- documentation retrieval for in-context learning
- tool-based direct manipulation instead of raw patch-file generation
This server keeps those properties while using a safer Pd backend than the nascent Pd MCP implementations that mutate Pd more directly.






