Heroku MCP Code Execution - Python
by Heroku
This repository provides a Python implementation for Heroku MCP (Managed Code Platform) code execution. It allows you to execute Python code snippets within a secure and isolated environment on Heroku.
Last updated: N/A
Heroku MCP Code Execution - Python
- Heroku MCP Code Execution - Python
Automatic Deployment
Manual Deployment
Set Required Environment Variables from Heroku CLI
Instead of manually setting each variable, use the Heroku CLI to pull the correct values.
export APP_NAME=<your-heroku-app-name>
heroku create $APP_NAME
heroku buildpacks:set heroku/python -a $APP_NAME
heroku config:set WEB_CONCURRENCY=1 -a $APP_NAME
# set a private API key that you create, for example:
heroku config:set API_KEY=$(openssl rand -hex 32) -a $APP_NAME
heroku config:set STDIO_MODE_ONLY=<true/false> -a $APP_NAME
Note: we recommend setting STDIO_MODE_ONLY
to true
for security and code execution isolation security.
Also put these config variables into a local .env file for local development:
heroku config -a $APP_NAME --shell | tee .env > /dev/null
Next, connect your app to your git repo:
heroku git:remote -a $APP_NAME
And deploy!
git push heroku main
View logs with:
heroku logs --tail -a $APP_NAME
Local Testing
Local SSE
One-time packages installation:
virtualenv venv
source venv/bin/activate
pip install -r requirements.txt
If you're testing SSE, in one terminal pane you'll need to start the server:
source venv/bin/activate
export API_KEY=$(heroku config:get API_KEY -a $APP_NAME)
uvicorn src.sse_server:app --reload
Running with --reload is optional, but great for local development
Next, in a new pane, you can try running some queries against your server:
Local SSE - Example Requests
First run:
export API_KEY=$(heroku config:get API_KEY -a $APP_NAME)
List tools:
python example_clients/test_sse.py mcp list_tools | jq
Example tool call request:
NOTE: this will intentionally NOT work if you have set STDIO_MODE_ONLY
to true
.
python example_clients/test_sse.py mcp call_tool --args '{
"name": "code_exec_python",
"arguments": {
"code": "import numpy as np; print(np.random.rand(50).tolist())",
"packages": ["numpy"]
}
}' | jq
Local STDIO
There are two ways to easily test out your MCP server in STDIO mode:
1. Local STDIO - Example Python STDIO Client
List tools:
python example_clients/test_stdio.py mcp list_tools | jq
Example tool call request:
python example_clients/test_stdio.py mcp call_tool --args '{
"name": "code_exec_python",
"arguments": {
"code": "import numpy as np; print(np.random.rand(50).tolist())",
"packages": ["numpy"]
}
}' | jq
2. Local STDIO - Direct Calls
Example tool call request:
cat <<EOF | python -m src.stdio_server
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"0.1.0","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}
{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"code_exec_python","arguments":{"code":"import numpy as np; print(np.random.rand(50).tolist())","packages":["numpy"]}}}
EOF
(Note that the server expects the client to send a shutdown request, so you can stop the connection with CTRL-C)
Remote Testing
export API_KEY=$(heroku config:get API_KEY -a $APP_NAME)
export MCP_SERVER_URL=$(heroku info -s -a $APP_NAME | grep web_url | cut -d= -f2)
Remote SSE
You can run the same queries as shown in the Local SSE - Example Requests testing section - because you've set MCP_SERVER_URL
, the client will call out to your deployed server.
Remote STDIO
There are two ways to test out your remote MCP server in STDIO mode:
1. Remote STDIO - Example Python STDIO Client, Running On-Server
To run against your deployed code, you can run the example client code on your deployed server inside a one-off dyno:
heroku run --app $APP_NAME -- bash -c 'python -m example_clients.test_stdio mcp list_tools | jq'
or:
heroku run --app $APP_NAME -- bash -c '
python -m example_clients.test_stdio mcp call_tool --args '\''{
"name": "code_exec_python",
"arguments": {
"code": "import numpy as np; print(np.random.rand(50).tolist())",
"packages": ["numpy"]
}
}'\'' | jq
'
2. Remote STDIO - Direct Calls to One-Off Dyno
Or, you can also run or simulate a client locally that sends your client-side requests to a one-off dyno:
heroku run --app "$APP_NAME" -- bash -c "python -m src.stdio_server 2> logs.txt" <<EOF
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"0.1.0","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}
{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"code_exec_python","arguments":{"code":"import numpy as np; print(np.random.rand(50).tolist())","packages":["numpy"]}}}
EOF
Again, note that since we're running our request through a single command, we're unable to simulate a client's shutdown request.
3. Coming Soon - Heroku MCP Gateway!
Soon, you'll also be able to connect up your MCP repo to Heroku's MCP Gateway, which will make streaming requests and responses from one-off MCP dynos simple!
The Heroku MCP Gateway will implement a rendezvous protocol so that you can easily talk to your MCP server one-off dynos (code execution isolation!) with seamless back-and-forth communication.