Skip to content

Commit 81879c2

Browse files
committed
FastMCP working
1 parent e817d75 commit 81879c2

20 files changed

+504
-549
lines changed

.github/workflows/python-ci.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Python CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
lint-and-format:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v3
14+
15+
- name: Set up Python 3.12
16+
uses: actions/setup-python@v4
17+
with:
18+
python-version: '3.12'
19+
20+
- name: Install dependencies
21+
run: |
22+
python -m pip install --upgrade pip
23+
pip install ruff
24+
25+
- name: Lint with Ruff
26+
run: |
27+
ruff check .
28+
ruff format --check .
29+

.github/workflows/test.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Test Deploy CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
vendoring:
13+
strategy:
14+
matrix:
15+
os: [ubuntu-latest, macos-latest] # , windows-latest
16+
runs-on: ${{ matrix.os }}
17+
18+
steps:
19+
- name: Checkout repository
20+
uses: actions/checkout@v4
21+
22+
- name: Set up Python
23+
uses: actions/setup-python@v4
24+
with:
25+
python-version: '3.12'
26+
27+
- name: Install Node.js
28+
uses: actions/setup-node@v4
29+
with:
30+
node-version: 22
31+
32+
- name: Install Wrangler
33+
run: npm install -g wrangler
34+
35+
- name: Run vendoring (Linux/macOS)
36+
if: runner.os != 'Windows'
37+
run: |
38+
python3.12 -m venv .venv
39+
source .venv/bin/activate
40+
.venv/bin/pip install pyodide-build
41+
.venv/bin/pyodide venv .venv-pyodide
42+
.venv-pyodide/bin/pip install -t src/vendor -r vendor.txt
43+
44+
# Windows is not supported by pyodide.
45+
# - name: Run vendoring (Windows)
46+
# if: runner.os == 'Windows'
47+
# run: |
48+
# python -m venv .venv
49+
# .\.venv\Scripts\Activate.ps1
50+
# .venv\Scripts\pip install pyodide-build
51+
# .venv\Scripts\pyodide venv .venv-pyodide
52+
# .venv-pyodide\Scripts\pip install -t src/vendor -r vendor.txt
53+
54+
- name: Test worker deployment
55+
run: wrangler deploy --dry-run
56+
57+
- name: Run tests (Linux/macOS)
58+
if: runner.os != 'Windows'
59+
run: |
60+
source .venv/bin/activate
61+
pip install -r requirements-test.txt
62+
pytest tests

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
.venv/
2+
.venv-pyodide/
3+
.pytest_cache/
24
node_modules/
5+
package-lock.json
6+
__pycache__/
37
src/vendor/
4-
.vscode/
8+
.vscode/
9+
.wrangler/

README.md

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,60 @@
1-
# Vendoring Packages: FastAPI + Jinja2 Example
1+
# Python Workers: FastMCP Example
22

3-
*Note: You must have Python Packages enabled on your account for built-in packages to work. Request Access to our Closed Beta using [This Form](https://forms.gle/FcjjhV3YtPyjRPaL8)*
3+
This is an example of a Python Worker that uses the FastMCP package.
44

5-
This is an example of a Python Worker that uses a built-in package (FastAPI) with a vendored package (Jinja2).
5+
[![Deploy to Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/ai/tree/main/demos/python-workers-mcp)
66

7-
## Adding Packages
7+
>[!NOTE]
8+
>Due to the [size](https://developers.cloudflare.com/workers/platform/limits/#worker-size) of the Worker, this example can only be deployed if you're using the Workers Paid plan. Free plan users will encounter deployment errors because this Worker exceeds the 3MB size limit.
89
9-
Built-in packages can be selected from [this list](https://developers.cloudflare.com/workers/languages/python/packages/#supported-packages) and added to your `requirements.txt` file. These can be used with no other explicit install step.
10+
## Adding Packages
1011

1112
Vendored packages are added to your source files and need to be installed in a special manner. The Python Workers team plans to make this process automatic in the future, but for now, manual steps need to be taken.
1213

1314
### Vendoring Packages
1415

15-
[//]: # (NOTE: when updating the instructions below, be sure to also update the vendoring.yml CI workflow)
16-
1716
First, install Python3.12 and pip for Python 3.12.
1817

1918
*Currently, other versions of Python will not work - use 3.12!*
2019

21-
Then create a virtual environment and activate it from your shell:
20+
Then set up your local pyodide virtual environment:
2221
```console
23-
python3.12 -m venv .venv
24-
source .venv/bin/activate
22+
npm run build
2523
```
2624

27-
Within our virtual environment, install the pyodide CLI:
25+
### Developing and Deploying
26+
27+
To develop your Worker run:
2828
```console
29-
.venv/bin/pip install pyodide-build
30-
.venv/bin/pyodide venv .venv-pyodide
29+
npm run dev
3130
```
3231

33-
Next, add packages to your vendor.txt file. Here we'll add jinja2
34-
```
35-
jinja2
32+
To deploy your Worker run:
33+
```console
34+
npm run deploy
3635
```
3736

38-
Lastly, add these packages to your source files at `src/vendor`. For any additional packages, re-run this command.
37+
### Testing
38+
39+
To test run:
3940
```console
40-
.venv-pyodide/bin/pip install -t src/vendor -r vendor.txt
41+
npm run test
4142
```
4243

43-
### Using Vendored packages
44+
### Linting and Formatting
4445

45-
In your wrangler.toml, make the vendor directory available:
46+
This project uses Ruff for linting and formatting:
4647

47-
```toml
48-
[[rules]]
49-
globs = ["vendor/**"]
50-
type = "Data"
51-
fallthrough = true
48+
```console
49+
npm run lint
5250
```
5351

54-
Now, you can import and use the packages:
52+
### IDE Integration
5553

56-
```python
57-
import jinja2
58-
# ... etc ...
59-
```
54+
To have good autocompletions in your IDE simply select .venv-pyodide/bin/python as your IDE's interpreter.
6055

61-
### Developing and Deploying
56+
You should also install your dependencies for type hints.
6257

63-
To develop your Worker, run `npx wrangler@latest dev`.
64-
65-
To deploy your Worker, run `npx wrangler@latest deploy`.
58+
```console
59+
.venv-pyodide/bin/pip install -r requirements-dev.txt
60+
```

package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "python-workers-mcp",
3+
"version": "1.0.0",
4+
"private": true,
5+
"description": "Python Workers MCP Demo",
6+
"scripts": {
7+
"build": "./scripts/build.sh",
8+
"test": "./scripts/test.sh",
9+
"lint": "./scripts/lint.sh",
10+
"dev": "wrangler dev",
11+
"deploy": "wrangler deploy"
12+
},
13+
"devDependencies": {
14+
"wrangler": "^4.14.0"
15+
}
16+
}

pyproject.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[tool.ruff]
2+
target-version = "py312"
3+
line-length = 100
4+
[tool.ruff.lint]
5+
select = [
6+
"E", # pycodestyle errors
7+
"F", # pyflakes
8+
"B", # flake8-bugbear
9+
"I", # isort
10+
"C4", # flake8-comprehensions
11+
"UP", # pyupgrade
12+
"N", # pep8-naming
13+
"RUF", # ruff-specific rules
14+
]
15+
ignore = []
16+
17+
[tool.ruff.lint.isort]
18+
known-first-party = ["src"]
19+
20+
[tool.ruff.format]
21+
quote-style = "double"
22+
indent-style = "space"
23+
line-ending = "auto"
24+
skip-magic-trailing-comma = false

requirements-dev.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
pytest
2+
requests
3+
mcp
4+
pytest-asyncio
5+
ruff
6+
mcp
7+
structlog
8+
webtypy
9+
pyodide-py

requirements-test.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pytest
2+
requests
3+
mcp
4+
pytest-asyncio
5+
ruff

scripts/build.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# Check if Python 3.12 is installed
5+
if ! command -v python3.12 &> /dev/null; then
6+
echo "Error: Python 3.12 is required but not installed."
7+
exit 1
8+
fi
9+
10+
# Create Python virtual environment
11+
if [ ! -d ".venv" ]; then
12+
echo "Creating Python virtual environment (.venv)..."
13+
python3.12 -m venv .venv
14+
else
15+
echo "Using existing Python virtual environment (.venv)..."
16+
fi
17+
18+
19+
# Create pyodide virtual environment if it doesn't exist
20+
if [ ! -d ".venv-pyodide" ]; then
21+
# Activate the Python virtual environment
22+
echo "Activating Python virtual environment..."
23+
source .venv/bin/activate
24+
25+
# Install pyodide-build in the Python venv
26+
echo "Installing pyodide-build..."
27+
pip install pyodide-build
28+
29+
echo "Creating pyodide virtual environment (.venv-pyodide)..."
30+
pyodide venv .venv-pyodide
31+
32+
# Deactivate the virtual environment
33+
echo "Deactivating Python virtual environment..."
34+
deactivate
35+
else
36+
echo "Using existing pyodide virtual environment (.venv-pyodide)..."
37+
fi
38+
39+
# Download vendored packages
40+
echo "Installing vendored packages from vendor.txt..."
41+
.venv-pyodide/bin/pip install -t src/vendor -r vendor.txt
42+
43+
echo "Build completed successfully!"

scripts/lint.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
source .venv/bin/activate
2+
pip install ruff
3+
ruff format . # Format code
4+
ruff check . # Run linting

0 commit comments

Comments
 (0)