A zero-dependency Model Context Protocol (MCP) server framework in pure Python.
No pip install. No third-party packages. No network egress. Just Python 3.9+
and its standard library. Copy mcp_zero.py into any project —
including air-gapped or locked-down corporate machines — and build an MCP server
that Claude Desktop, Claude Code, or any MCP client can talk to.
The popular MCP frameworks (FastMCP, the official SDK, mcp-use) all require installing packages from PyPI and, often, a Node/TypeScript build toolchain. In a hardened enterprise environment that is frequently not allowed.
mcp-zero removes that barrier. The entire framework is one auditable file
(~400 lines) that depends only on the standard library (json, sys,
inspect, typing, http.server). What you can read, you can approve.
| mcp-zero | FastMCP / official SDK | mcp-use | |
|---|---|---|---|
| External dependencies | none | several (PyPI) | many (PyPI + npm) |
| Files to deploy | 1 | package install | package install |
| Transports | stdio + HTTP | stdio + HTTP | stdio + HTTP |
| Build toolchain | none | none | Node/Vite |
| Audit surface | one file | large | large |
from mcp_zero import MCPServer
server = MCPServer("my-server", "1.0.0")
@server.tool()
def add(a: float, b: float) -> float:
"""Add two numbers and return the sum."""
return a + b
if __name__ == "__main__":
server.run() # stdio (the transport Claude Desktop/Code use)
# server.run_http() # or Streamable HTTP on 127.0.0.1:8000That's a complete, working MCP server. The tool's JSON Schema is inferred from the type hints, and the docstring becomes the tool's description.
Claude Desktop / Claude Code — add to the MCP servers config:
{
"mcpServers": {
"my-server": {
"command": "python3",
"args": ["/absolute/path/to/server.py"]
}
}
}| File | What it shows |
|---|---|
examples/echo_server.py |
The smallest possible server |
examples/calculator_server.py |
Numeric tools, optional args, MCPError |
examples/files_server.py |
A sandboxed read-only filesystem tool (a realistic internal-tool template) |
Run any of them over stdio:
python3 examples/calculator_server.pyRegister a function with @server.tool(). Type hints become the input schema,
the docstring becomes the description.
@server.tool()
def search(query: str, limit: int = 10) -> list:
"""Search the catalog and return matching item names."""
...
return ["item-a", "item-b"]- Return values are normalized automatically: a
strbecomes text content; adict/listbecomes pretty-printed JSON plusstructuredContent. - Expected errors — raise
MCPError("message")to send a clean JSON-RPC error to the client. - Unexpected exceptions are caught and returned as a tool error
(
isError: true) so a bug in one tool never crashes the server.
Supported type-hint → JSON Schema mappings: str, int, float, bool,
list/List[T], dict, and Optional[T]. For anything more exotic, pass an
explicit schema via server.add_tool(func, input_schema=...).
server.run()— stdio, newline-delimited JSON-RPC. This is what Claude Desktop and Claude Code launch.stdoutis reserved for protocol traffic; all logging goes tostderr.server.run_http(host, port)— a simplified Streamable HTTP endpoint (POST JSON-RPC to/) built onhttp.server. Useful for testing withcurlor for clients that prefer HTTP.
The test suite uses only the standard-library unittest (no pytest):
python3 -m unittest discover -s tests -vImplements the MCP server methods needed for tool use: initialize, ping,
notifications/initialized, tools/list, and tools/call, speaking JSON-RPC
2.0. The initialize handshake echoes the client's requested protocolVersion,
so the server stays compatible across MCP revisions. Resources and prompts are
intentionally out of scope to keep the core minimal — they can be added the same
way tools are.
See CLAUDE.md — it's a self-contained spec that lets an AI
assistant generate a new, correct MCP server from this framework without any
external reference.
MIT — see LICENSE.