Zero-config MCP server. Drop a .py file in a folder, it's a tool.
Project description
ZeroMCP — Python
Drop a .py file in a folder, get a sandboxed MCP server. Stdio out of the box, zero dependencies.
Getting started
# tools/hello.py — this is a complete MCP server
tool = {
"description": "Say hello to someone",
"input": {"name": "string"},
}
async def execute(args, ctx):
return f"Hello, {args['name']}!"
python3 -m zeromcp serve ./tools
That's it. Stdio transport works immediately. Drop another .py file to add another tool. Delete a file to remove one. No server object, no decorators, no main block.
vs. the official SDK
The official Python SDK (FastMCP) requires a server object, decorators, and a __main__ block. Adding a tool means editing server code and restarting. ZeroMCP is file-based — each tool is its own file, discovered automatically.
In benchmarks, ZeroMCP Python handles 12,936 requests/second over stdio versus the official SDK's 1,018 — 12.7x faster with 59% less memory. Over HTTP (Starlette), ZeroMCP serves 2,623 rps at 27 MB versus the official SDK's 635 rps at 80-87 MB. ZeroMCP uses only the standard library. The official SDK pulls in pydantic, httpx, uvicorn, and starlette just for stdio.
Python passes all 10 conformance suites and survives 21/22 chaos monkey attacks.
The official SDK has no sandbox. ZeroMCP enforces per-tool network allowlists, credential isolation, and filesystem controls at runtime.
HTTP / Streamable HTTP
ZeroMCP doesn't own the HTTP layer. You bring your own framework; ZeroMCP gives you an async handler that takes a JSON-RPC dict and returns a response dict (or None for notifications).
from zeromcp import create_handler
handler = await create_handler("./tools")
# handler(request: dict) -> dict | None
Flask
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/mcp", methods=["POST"])
async def mcp():
response = await handler(request.get_json())
if response is None:
return "", 204
return jsonify(response)
FastAPI
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
app = FastAPI()
@app.post("/mcp")
async def mcp(req: Request):
response = await handler(await req.json())
if response is None:
return JSONResponse(status_code=204, content=None)
return response
Requirements
- Python 3.10+
- No external dependencies (stdlib only)
Install
pip install -e .
Defining tools
# tools/add.py
tool = {
"description": "Add two numbers together",
"input": {"a": "number", "b": "number"},
}
async def execute(args, ctx):
return {"sum": args["a"] + args["b"]}
Input types
Shorthand strings: "string", "number", "boolean", "object", "array".
Returning values
Return a string or a dict. ZeroMCP wraps it in the MCP content envelope for you.
Sandbox
The Python implementation has full runtime sandboxing.
Network allowlists
tool = {
"description": "Fetch from our API",
"input": {"endpoint": "string"},
"permissions": {
"network": ["api.example.com", "*.internal.dev"],
},
}
async def execute(args, ctx):
res = await ctx.fetch(f"https://api.example.com/{args['endpoint']}")
return res["body"]
ctx.fetch validates the hostname against the allowlist. Unlisted domains are blocked and logged.
Credential injection
Tools receive secrets via ctx.credentials, configured per namespace. Tools never call os.environ directly.
Filesystem and exec control
Tools must declare fs: 'read' or fs: 'write' for filesystem access. Static auditing and proxy objects enforce the restrictions.
Directory structure
Tools are discovered recursively. Subdirectory names become namespace prefixes:
tools/
hello.py -> tool "hello"
math/
add.py -> tool "math_add"
Configuration
Optional zeromcp.config.json in the working directory. See the root README for the full schema.
Testing
python3 -m pytest
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file antidrift_zeromcp-0.1.1.tar.gz.
File metadata
- Download URL: antidrift_zeromcp-0.1.1.tar.gz
- Upload date:
- Size: 12.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f619a00ae2a212dd77bf5c95633f0433fcac51b8e8315e3bd8d30b9ae26a8f25
|
|
| MD5 |
b16018157c6f0edb4eae1350478cb736
|
|
| BLAKE2b-256 |
7b1a66edfe0d2c7a28fda75c4dfbff9b0775eecfc4df51822eb9d56a495dac5e
|
Provenance
The following attestation bundles were made for antidrift_zeromcp-0.1.1.tar.gz:
Publisher:
publish-python.yml on antidrift-dev/zeromcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
antidrift_zeromcp-0.1.1.tar.gz -
Subject digest:
f619a00ae2a212dd77bf5c95633f0433fcac51b8e8315e3bd8d30b9ae26a8f25 - Sigstore transparency entry: 1247591641
- Sigstore integration time:
-
Permalink:
antidrift-dev/zeromcp@372e732b67c8e921b1e90094b610b08ab2e22b61 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/antidrift-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python.yml@372e732b67c8e921b1e90094b610b08ab2e22b61 -
Trigger Event:
push
-
Statement type:
File details
Details for the file antidrift_zeromcp-0.1.1-py3-none-any.whl.
File metadata
- Download URL: antidrift_zeromcp-0.1.1-py3-none-any.whl
- Upload date:
- Size: 13.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa3336c6c183f2ec138dc4492b41b5b3e9019fce9362980db7ff11241f1a7c42
|
|
| MD5 |
64aae1bd4ffafb04646655fbda2e73cd
|
|
| BLAKE2b-256 |
e340705a46f3f3e54b5260c444e1792b7746ec05b25ae2d4df89170eb66f8d6d
|
Provenance
The following attestation bundles were made for antidrift_zeromcp-0.1.1-py3-none-any.whl:
Publisher:
publish-python.yml on antidrift-dev/zeromcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
antidrift_zeromcp-0.1.1-py3-none-any.whl -
Subject digest:
fa3336c6c183f2ec138dc4492b41b5b3e9019fce9362980db7ff11241f1a7c42 - Sigstore transparency entry: 1247591643
- Sigstore integration time:
-
Permalink:
antidrift-dev/zeromcp@372e732b67c8e921b1e90094b610b08ab2e22b61 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/antidrift-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python.yml@372e732b67c8e921b1e90094b610b08ab2e22b61 -
Trigger Event:
push
-
Statement type: