py-exec-mcp
Allows executing Python code directly from an MCP client, passing code via stdin to a Python interpreter and returning stdout, stderr, and the exit code.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@py-exec-mcprun this Python and show output: print(f"hello {name}")"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
py-exec-mcp
Run Python from an MCP client without a shell mangling your code.
The problem
Ask an agent to run a one-liner and it reaches for python -c "...". That code passes through
three parsers before Python ever sees it — the shell, argv splitting, then Python itself — each
with its own escaping rules.
python -c "print(f'he said \"hi {name}\"')" # which layer eats which quote?The failure mode is what makes this worth fixing: you usually get a wrong answer, not an error. A backslash vanishes, a quote closes early, an f-string silently becomes a literal — and the output looks plausible. So the agent retries with different escaping, or falls back to writing a temp file and running it, every single time.
Related MCP server: MCP Shell Server
The fix
Code arrives as a JSON string in the MCP tool call and is handed to the interpreter over stdin
(python -). No shell. No argv. Nothing re-parses it.
Write the code exactly as it would appear in a .py file — nested quotes, f-strings, backslashes,
regex, triple-quoted blocks — and it arrives verbatim.
Install
uvx py-exec-mcp # no install
pip install py-exec-mcp # or the usual wayWorks on both MCP SDK majors — 2.x renamed FastMCP to MCPServer, and the server binds
whichever one your environment has, so you are not forced to pin the SDK to match it.
Configure
{
"mcpServers": {
"py-exec": {
"command": "uvx",
"args": ["py-exec-mcp"]
}
}
}{
"mcpServers": {
"py-exec": {
"command": "uvx",
"args": ["py-exec-mcp"],
"env": { "PY_EXEC_CWD": "/absolute/path/to/your/project" }
}
}
}python -m py_exec_mcpThe tool
run_python(code: str, timeout_s: float = 120) -> str
Returns stdout, stderr and the exit code as text:
42
--- stderr ---
warning: something
--- exit 0 ---Four behaviours worth knowing, because each one is a thing that bit somebody:
behaviour | why |
Truncation is announced | a silently clipped result is indistinguishable from a short one. You get |
A timeout still returns output | the runs that time out are the ones whose partial output matters most |
The workdir is on | your project's own packages import without a |
A missing interpreter says so | rather than failing as an empty result |
Configuration
All optional. Everything works with none of them set.
variable | default | what it does |
| process cwd | directory code runs in, and the root added to |
| project venv, else | interpreter to run code with |
|
| upper clamp on |
|
| per-stream character cap before truncation |
Interpreter resolution, in order: PY_EXEC_PYTHON → .venv/Scripts/python.exe (Windows) or
.venv/bin/python (everywhere else) under the working directory → the interpreter running the
server. So in a project with a virtualenv, your dependencies are simply there.
⚠️ Security
This server executes arbitrary Python with the full privileges of the process that launched it. That is its entire purpose, and it is not sandboxed.
Code runs as your user, with your filesystem access and your network access.
The child process inherits the server's environment, so any secrets already exported into it are readable by executed code. If that matters, launch the server with a scrubbed environment.
Timeouts bound how long code runs. They bound nothing else.
Give it the same trust you would give a terminal. If you would not paste a script into your shell and hit enter, do not ask an agent to run it here. For untrusted code, run this inside a container or a VM — the isolation has to come from the layer underneath, because this server provides none.
Development
git clone https://github.com/blurxy/py-exec-mcp
cd py-exec-mcp
pip install -e ".[dev]"
pytest -q
ruff check . && ruff format --check .Tests assert on what a caller reads — the returned string — never on "it did not crash". A test
that asserts exit 0 has tested the process surviving, not the answer being right. CI runs the suite
on Linux, macOS and Windows across Python 3.10–3.13, because cross-platform interpreter resolution
is the part most likely to break, plus one job pinned to mcp<2 — the matrix always resolves the
newest SDK, so without that job the 1.x import path would never be exercised.
Prior art
MCP has several Python-execution servers, and most target a different problem: sandboxing (containers, Pyodide, gVisor), or a persistent REPL/kernel where state survives between calls.
This one is deliberately narrow. It solves the quoting problem and nothing else — one tool, no sandbox, no session state, no notebook. If you need isolation, use a sandboxed server. If you need variables to persist across calls, use a Jupyter-backed one. If you keep losing an afternoon to escaping, this is the smaller thing.
Licence
Available Tools
1 toolrun_pythonA
Execute Python code and return its stdout, stderr and exit code.
The code is fed to the interpreter over STDIN, so it is never parsed by a shell or split into argv. Write it exactly as it would appear in a .py file: f-strings, nested quotes and backslashes all survive verbatim.
Runs in the working directory (PY_EXEC_CWD or cwd), which is also prepended to PYTHONPATH so the project's own packages import. timeout_s is clamped to [1, PY_EXEC_MAX_TIMEOUT]; on timeout, whatever was produced is still returned.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | ||
| timeout_s | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It discloses return values, input delivery mechanism, absence of shell parsing, working directory, PYTHONPATH prepending, timeout clamping, and partial output on timeout. This is substantial, though it does not mention broader execution sandbox limits or side-effect risks.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three information-dense sentences with no filler. The core purpose is front-loaded, followed by necessary execution details. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 2-parameter execution tool, the description covers return values, input handling, working directory, import path, and timeout behavior. It is mostly complete, though details like available packages or Python version are left to the environment. The output schema also exists to document return format.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It does: 'code' is clarified with verbatim escaping guidance, and 'timeout_s' is explained with clamping range and timeout behavior. It does not restate the default value, but that is already in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence states a specific verb and resource: 'Execute Python code and return its stdout, stderr and exit code.' This unambiguously identifies the tool's function. With no sibling tools, differentiation is unnecessary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear practical guidance: code is fed via STDIN, not shell-parsed, so it should be written as in a .py file. It also explains the working directory and PYTHONPATH behavior. There are no sibling alternatives to contrast against, but the usage context is explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.1.0- First observed
run_python
TDQS
Scored across 1 tool
Only one tool exists, so there is no possibility of confusing it with another tool. Its purpose is explicit and unique.
The single tool name follows a clear verb_noun snake_case convention. There are no other tool names to create inconsistency.
One tool exactly matches the server's narrow purpose of executing Python code. The count is well-scoped without unnecessary breadth.
The tool fully covers the execution domain: it handles stdin, working directory, PYTHONPATH, timeouts, and returns stdout, stderr, and exit code. No obvious gaps exist.
Maintenance
Related MCP Connectors
A paid remote MCP for OpenAI Codex agent coordination MCP, built to return verdicts, receipts, usage
Remote MCP server for supportsheep: run AI interviews and manage support content for your blog.
Host your MCP tool over streamable HTTP in one command.
A paid remote MCP for OpenAI Codex harness MCP, built to return verdicts, receipts, usage logs, and
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables LLMs to execute Python code in isolated sandboxes with file operations and MCP integration, supporting multi-round execution and plot capture.1-
- AlicenseBqualityDmaintenanceEnables secure execution of whitelisted shell commands through MCP, with support for stdin input, timeout control, and comprehensive output including stdout, stderr, and execution time.1MIT
- AlicenseNot gradedqualityDmaintenanceProvides a persistent Python REPL session as a tool for executing code, managing files, installing packages, and initializing projects via the MCP protocol.1MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to execute arbitrary Python code securely in a sandboxed environment with resource limits and security constraints via MCP protocol.MIT