PEP MCP Server
MCP server that exposes on-demand Python PEP lookup tools backed by the live PEP index.
Features
list_peps: list only active PEPssearch_peps: search active PEP titlesget_pep: fetch a PEP document by number, optionally returning focused excerpts for a query
Data Sources
- PEP index JSON:
https://peps.python.org/api/peps.json - PEP content:
https://raw.githubusercontent.com/python/peps/main/peps/pep-XXXX.rst- Fallback:
https://github.com/python/peps/blob/main/peps/pep-XXXX.rst?plain=1
Setup
python -m venv .venv
.venv/bin/pip install -e ".[dev]"
Run
.venv/bin/pep-mcp-server
or:
.venv/bin/python -m pep_mcp_server
Docker
Build and tag:
docker build -t pep-mcp-server:latest .
MCP uses stdio, so the container must keep stdin open (-i). Example:
docker run --rm -i pep-mcp-server:latest
Cursor MCP (Docker)
You do not put PEP or GitHub URLs in mcp.json. Cursor only needs the command that runs the server; listing and fetching PEPs happens inside the process when tools run.
Use -i (required for stdio). Optional -e lines silence the startup banner and pin transport:
{
"mcpServers": {
"pep": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-e",
"FASTMCP_TRANSPORT=stdio",
"-e",
"FASTMCP_SHOW_SERVER_BANNER=false",
"pep-mcp-server:latest"
]
}
}
}
If the image is not on this machine yet, build it once from the project directory (see above).
If the MCP log shows Found 0 tools but listOfferingsForUI / Not connected warnings, that is often a Cursor UI race or a separate UI listing path; try reloading the window or invoking a tool from chat. The server still exposes three tools over stdio (verified with the MCP Python client).
Tool Contracts
list_peps() -> list[dict]
Returns active PEPs with:
numbertitletypetopiccreatedurl
(status is omitted; every row is active.)
search_peps(query: str) -> list[dict]
Case-insensitive substring search on active PEP titles.
get_pep(pep, query=None, max_full_content_chars=None) -> dict
- Accepts
8,0008, orpep-0008. - Returns metadata and:
contentwhenqueryis not provided (capped by default for token efficiency)excerptwhenqueryis provided and matchescontentfallback whenqueryhas no matches (also capped by default)
- Optional
max_full_content_chars: omit orNonefor the default cap; use0for the full document (can be very large).
Tests
.venv/bin/pytest -q