Skip to content

Commit a60975b

Browse files
committed
moving code from pydantic-ai/mcp-run-python
0 parents  commit a60975b

File tree

19 files changed

+2745
-0
lines changed

19 files changed

+2745
-0
lines changed

.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
node_modules/
2+
.venv
3+
dist
4+
__pycache__
5+
.env
6+
/scratch/
7+
/.coverage
8+
env*/
9+
.DS_Store
10+
.cache/
11+
.vscode/
12+
**.idea/
13+
.coverage*
14+
/test_tmp/
15+
16+
/mcp_run_python/deno/prepareEnvCode.ts

.pre-commit-config.yaml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
repos:
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: v5.0.0
4+
hooks:
5+
# - id: no-commit-to-branch # prevent direct commits to the `main` branch
6+
- id: check-yaml
7+
- id: check-toml
8+
- id: end-of-file-fixer
9+
- id: trailing-whitespace
10+
11+
- repo: https://github.com/codespell-project/codespell
12+
# Configuration for codespell is in pyproject.toml
13+
rev: v2.3.0
14+
hooks:
15+
- id: codespell
16+
17+
- repo: local
18+
hooks:
19+
- id: format-ts
20+
name: format typescript
21+
entry: make
22+
args: [format-ts]
23+
language: system
24+
types_or: [javascript, ts, json]
25+
pass_filenames: false
26+
- id: lint-ts
27+
name: lint typescript
28+
entry: make
29+
args: [lint-ts]
30+
language: system
31+
types_or: [javascript, ts, json]
32+
pass_filenames: false
33+
- id: typecheck-ts
34+
name: typecheck typescript
35+
entry: make
36+
args: [typecheck-ts]
37+
language: system
38+
types_or: [javascript, ts, json]
39+
pass_filenames: false
40+
- id: format-py
41+
name: format python
42+
entry: make
43+
args: [format-py]
44+
language: system
45+
types: [python]
46+
pass_filenames: false
47+
- id: typecheck-py
48+
name: typecheck python
49+
entry: make
50+
args: [typecheck-py]
51+
language: system
52+
types: [python]
53+
pass_filenames: false

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.13

.zed/settings.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Folder-specific settings to tell zed to use deno not npm
2+
{
3+
"languages": {
4+
"TypeScript": {
5+
"language_servers": [
6+
"deno",
7+
"!typescript-language-server",
8+
"!vtsls",
9+
"!eslint"
10+
],
11+
"formatter": "language_server"
12+
}
13+
},
14+
"lsp": {
15+
"deno": {
16+
"settings": {
17+
"deno": {
18+
"enable": true
19+
}
20+
}
21+
}
22+
}
23+
}

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) Pydantic Services Inc. 2024 to present
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.

Makefile

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
.DEFAULT_GOAL := all
2+
3+
.PHONY: .uv
4+
.uv: ## Check that uv is installed
5+
@uv --version || (echo '✖ Please install uv: https://docs.astral.sh/uv/getting-started/installation/' && exit 1)
6+
7+
.PHONY: .deno
8+
.deno: ## Check that deno is installed
9+
@deno --version || (echo "✖ Please install deno: https://deno.com" && exit 1)
10+
11+
.PHONY: .pre-commit
12+
.pre-commit: ## Check that pre-commit is installed
13+
@pre-commit -V || (echo '✖ Please install pre-commit: https://pre-commit.com/' && exit 1)
14+
15+
.PHONY: install
16+
install: .uv .deno .pre-commit ## Install the package, dependencies, and pre-commit for local development
17+
uv sync --frozen
18+
pre-commit install --install-hooks
19+
20+
.PHONY: build
21+
build: ## Build mcp_run_python/deno/prepareEnvCode.ts
22+
uv run build/build.py
23+
24+
.PHONY: format-ts
25+
format-ts: ## Format TS code
26+
cd mcp_run_python && deno task format
27+
28+
.PHONY: format-py
29+
format-py: ## Format Python code
30+
uv run ruff format
31+
uv run ruff check --fix --fix-only
32+
33+
.PHONY: format
34+
format: format-ts format-py ## Format all code
35+
36+
.PHONY: lint-ts
37+
lint-ts: ## Lint TS code
38+
cd mcp_run_python && deno task lint
39+
40+
.PHONY: lint-py
41+
lint-py: ## Lint Python code
42+
uv run ruff format --check
43+
uv run ruff check
44+
45+
.PHONY: lint
46+
lint: lint-ts lint-py ## Lint all code
47+
48+
.PHONY: typecheck-ts
49+
typecheck-ts: ## Typecheck TS code
50+
cd mcp_run_python && deno task typecheck
51+
52+
.PHONY: typecheck-py
53+
typecheck-py: ## Typecheck the code
54+
uv run basedpyright
55+
56+
.PHONY: typecheck
57+
typecheck: typecheck-ts typecheck-py ## Typecheck all code
58+
59+
.PHONY: test-ts
60+
test-ts: ## Run TS tests
61+
CI=1 npm run test
62+
63+
.PHONY: test
64+
test: test-ts ## Run all tests
65+
66+
.PHONY: all
67+
all: format typecheck test ## run format, typecheck and test
68+
69+
.PHONY: help
70+
help: ## Show this help (usage: make help)
71+
@echo "Usage: make [recipe]"
72+
@echo "Recipes:"
73+
@awk '/^[a-zA-Z0-9_-]+:.*?##/ { \
74+
helpMessage = match($$0, /## (.*)/); \
75+
if (helpMessage) { \
76+
recipe = $$1; \
77+
sub(/:/, "", recipe); \
78+
printf " \033[36m%-20s\033[0m %s\n", recipe, substr($$0, RSTART + 3, RLENGTH); \
79+
} \
80+
}' $(MAKEFILE_LIST)

README.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# MCP Run Python
2+
3+
[Model Context Protocol](https://modelcontextprotocol.io/) server to run Python code in a sandbox.
4+
5+
The code is executed using [Pyodide](https://pyodide.org) in [Deno](https://deno.com/) and is therefore isolated from
6+
the rest of the operating system.
7+
8+
**See <https://ai.pydantic.dev/mcp/run-python/> for complete documentation.**
9+
10+
The server can be run with `deno` installed using:
11+
12+
```bash
13+
deno run \
14+
-N -R=node_modules -W=node_modules --node-modules-dir=auto \
15+
jsr:@pydantic/mcp-run-python [stdio|streamable_http|sse|warmup]
16+
```
17+
18+
where:
19+
20+
- `-N -R=node_modules -W=node_modules` (alias of `--allow-net --allow-read=node_modules --allow-write=node_modules`)
21+
allows network access and read+write access to `./node_modules`. These are required so pyodide can download and cache
22+
the Python standard library and packages
23+
- `--node-modules-dir=auto` tells deno to use a local `node_modules` directory
24+
- `stdio` runs the server with the
25+
[Stdio MCP transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#stdio) — suitable for
26+
running the process as a subprocess locally
27+
- `streamable_http` runs the server with the
28+
[Streamable HTTP MCP transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http) -
29+
suitable for running the server as an HTTP server to connect locally or remotely. This supports stateful requests, but
30+
does not require the client to hold a stateful connection like SSE
31+
- `sse` runs the server with the
32+
[SSE MCP transport](https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#http-with-sse)
33+
suitable for running the server as an HTTP server to connect locally or remotely. Note that the SSE transport has been
34+
[deprecated in newer MCP protocol versions](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#backwards-compatibility)
35+
and is there to maintain backwards compatibility.
36+
- `warmup` will run a minimal Python script to download and cache the Python standard library. This is also useful to
37+
check the server is running correctly.
38+
39+
Here's an example of using `@pydantic/mcp-run-python` with Pydantic AI:
40+
41+
```python
42+
from pydantic_ai import Agent
43+
from pydantic_ai.mcp import MCPServerStdio
44+
45+
import logfire
46+
47+
logfire.configure()
48+
logfire.instrument_mcp()
49+
logfire.instrument_pydantic_ai()
50+
51+
server = MCPServerStdio('deno',
52+
args=[
53+
'run',
54+
'-N',
55+
'-R=node_modules',
56+
'-W=node_modules',
57+
'--node-modules-dir=auto',
58+
'jsr:@pydantic/mcp-run-python',
59+
'stdio',
60+
])
61+
agent = Agent('claude-3-5-haiku-latest', toolsets=[server])
62+
63+
64+
async def main():
65+
async with agent:
66+
result = await agent.run('How many days between 2000-01-01 and 2025-03-18?')
67+
print(result.output)
68+
#> There are 9,208 days between January 1, 2000, and March 18, 2025.w
69+
70+
if __name__ == '__main__':
71+
import asyncio
72+
asyncio.run(main())
73+
```

build/build.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env python3
2+
"""Build script to inline ./prepare_env.py into mcp_run_python/deno/prepareEnvCode.ts"""
3+
4+
from pathlib import Path
5+
6+
this_dir = Path(__file__).parent
7+
root_dir = this_dir.parent
8+
9+
# Define source and destination paths
10+
src = this_dir / "prepare_env.py"
11+
dst = root_dir / "mcp_run_python" / "deno" / "prepareEnvCode.ts"
12+
13+
python_code = src.read_text()
14+
15+
# Escape backslashes for JavaScript string literal
16+
python_code = python_code.replace("\\", "\\\\")
17+
18+
# Create the JavaScript/TypeScript code
19+
ts_code = f"""// DO NOT EDIT THIS FILE DIRECTLY, INSTEAD RUN "make build"
20+
export const preparePythonCode = `{python_code}`
21+
"""
22+
23+
dst.write_text(ts_code)
24+
25+
print(f"Successfully built {dst}")

0 commit comments

Comments
 (0)