About
Py Server Template — Model Context Protocol server
README
A clean, complete boilerplate for building a Model Context Protocol (MCP) server in Python using FastMCP.
Features
- Standard
src/project layout - Example tools with full type hints and Google-style docstrings
- Example resources (static and parameterized URI templates)
- Example prompts (reusable single- and multi-message templates)
- Context-aware tool (client logging, progress reporting, resource access)
- Environment-based configuration (
pydantic-settings) - Structured JSON logging (production) or console logging (dev)
- Selectable transport:
stdio(local) orstreamable-http(networked) - Runnable via
uvx(no manual environment setup) - Optional JWT bearer-token authentication for HTTP transports
- Per-tool timeouts and safe error handling
- Optional OpenTelemetry tracing & metrics
- Multi-stage
Dockerfile(non-root) +.dockerignore - GitHub Actions CI (lint, format, type-check, tests) across Python 3.10–3.12
- Pinned
requirements.lockfor reproducible installs - Ready-to-run test suite (
pytest+pytest-asyncio)
Project structure
mcp-py-server-template/
├── pyproject.toml # Build config, dependencies, tooling
├── requirements.lock # Pinned versions for reproducible installs
├── Makefile # Common dev tasks (make help)
├── Dockerfile # Multi-stage, non-root production image
├── .dockerignore
├── .env.example # Sample environment configuration
├── README.md
├── .github/workflows/ci.yml # Lint, format, type-check, test pipeline
├── src/
│ └── mcp_server_template/
│ ├── __init__.py # Package exports & version
│ ├── config.py # Env-based settings (pydantic-settings)
│ ├── logging_config.py # JSON / console logging setup
│ ├── auth.py # Optional JWT bearer-token verifier
│ ├── telemetry.py # Optional OpenTelemetry setup
│ ├── server.py # FastMCP app instance + entry point
│ ├── tools.py # Example tools (greet, add, slow_double, process_items)
│ ├── resources.py # Example resources (static + templates)
│ └── prompts.py # Example prompts (reusable templates)
└── tests/
├── __init__.py
├── test_tools.py # Tool tests via the in-memory client
├── test_resources.py # Resource tests via the in-memory client
└── test_prompts.py # Prompt tests via the in-memory client
Configuration
All settings are read from environment variables (prefixed MCP_) or a .env
file. Copy .env.example to .env and adjust. Key variables:
| Variable | Default | Description |
|---|---|---|
MCP_TRANSPORT |
stdio |
stdio or streamable-http |
MCP_HOST |
127.0.0.1 |
Bind host (HTTP transports) |
MCP_PORT |
8000 |
Bind port (HTTP transports) |
MCP_LOG_LEVEL |
INFO |
Logging level |
MCP_JSON_LOGS |
false |
Emit structured JSON logs |
MCP_TOOL_TIMEOUT_SECONDS |
30 |
Per-tool timeout |
MCP_AUTH_JWKS_URI |
(unset) | JWKS endpoint; enables auth when set |
MCP_AUTH_ISSUER |
(unset) | Expected token iss claim |
MCP_AUTH_AUDIENCE |
(unset) | Expected token aud claim |
MCP_OTEL_ENABLED |
false |
Enable OpenTelemetry export |
MCP_OTEL_SERVICE_NAME |
mcp-py-server-template |
Telemetry service name |
Getting started
Create a virtual environment and install the package in editable mode with the dev extras:
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
For a reproducible install of pinned versions, use the lockfile instead:
pip install -r requirements.lock
Running the server
Start the server over stdio (the default MCP transport):
mcp-py-server-template
Or run the module directly:
python -m mcp_server_template.server
Run as a networked HTTP service with structured logs:
MCP_TRANSPORT=streamable-http MCP_HOST=0.0.0.0 MCP_PORT=8000 MCP_JSON_LOGS=true \
mcp-py-server-template
Authentication
For HTTP transports, set the JWKS variables to require valid JWT bearer tokens
(signature, issuer, and audience are verified). Auth is disabled when
MCP_AUTH_JWKS_URI is unset — safe for local/stdio use, but do not expose
the server publicly without it:
MCP_TRANSPORT=streamable-http \
MCP_AUTH_JWKS_URI=https://auth.example.com/.well-known/jwks.json \
MCP_AUTH_ISSUER=https://auth.example.com \
MCP_AUTH_AUDIENCE=mcp-py-server-template \
mcp-py-server-template
Clients then send Authorization: Bearer <token> on each request.
Observability
Enable OpenTelemetry tracing and metrics (install the extra first):
pip install -e ".[otel]"
MCP_OTEL_ENABLED=true OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
mcp-py-server-template
Docker
docker build -t mcp-py-server-template .
docker run -p 8000:8000 mcp-py-server-template
The image defaults to the HTTP transport on 0.0.0.0:8000 with JSON logs and
runs as a non-root user. Override any MCP_* variable with -e.
Connect from an MCP client
Add the following to your client's MCP configuration (e.g. Claude Desktop,
VS Code). Use an absolute path to the interpreter inside your virtual
environment — MCP clients do not inherit your shell's PATH, so a bare
command name will fail with spawn ... ENOENT:
{
"mcpServers": {
"mcp-py-server-template": {
"command": "/absolute/path/to/mcp-py-server-template/.venv/bin/python",
"args": ["-m", "mcp_server_template.server"]
}
}
}
Alternatively, point directly at the generated console script:
{
"mcpServers": {
"mcp-py-server-template": {
"command": "/absolute/path/to/mcp-py-server-template/.venv/bin/mcp-py-server-template"
}
}
}
Run with uvx (recommended)
uvx (from
uv) fetches and runs the package in an ephemeral,
isolated environment. This avoids managing a virtual environment or worrying
about PATH, since the client only needs uvx on its PATH.
Run it locally from the project directory (no publishing required):
uvx --from . mcp-py-server-template
Or run directly from a Git repository:
uvx --from git+https://github.com/Omar-Emam-99/mcp-py-server-template mcp-py-server-template
Once the package is published to PyPI, the source can be omitted entirely:
uvx mcp-py-server-template
Corresponding MCP client configuration:
{
"mcpServers": {
"mcp-py-server-template": {
"command": "uvx",
"args": ["--from", "git+https://github.com/Omar-Emam-99/mcp-py-server-template", "mcp-py-server-template"]
}
}
}
After publishing to PyPI, simplify the args to just the package name:
{
"mcpServers": {
"mcp-py-server-template": {
"command": "uvx",
"args": ["mcp-py-server-template"]
}
}
}
Publishing
Build distributables and publish to a package index using uv (targets provided by the Makefile):
make build # build sdist + wheel into dist/
make publish-test # upload to TestPyPI
make publish # upload to PyPI
Provide credentials via the UV_PUBLISH_TOKEN environment variable (or
uv publish --token ...). Once published to PyPI, clients can launch the
server with the bare uvx mcp-py-server-template form shown above.
Adding your own tools
Register new tools in src/mcp_server_template/tools.py
by decorating a function with @mcp.tool. Type hints define the input schema
and the docstring becomes the tool description:
@mcp.tool
def multiply(a: float, b: float) -> float:
"""Multiply two numbers.
Args:
a: The first factor.
b: The second factor.
Returns:
The product of ``a`` and ``b``.
"""
return a * b
Tools may be async and can be wrapped with @with_timeout (see
tools.py) to enforce the configured
per-tool timeout and convert failures into safe ToolError messages. Validate
inputs at the top of the tool and raise ToolError for bad requests.
Adding your own resources
Resources expose read-only data to clients, addressed by a URI. Register new
resources in src/mcp_server_template/resources.py
by decorating a function with @mcp.resource. A URI containing {placeholders}
becomes a resource template, and the matching function parameters are filled
from the requested URI:
@mcp.resource(
"users://{user_id}/profile",
name="user-profile",
description="A synthetic user profile keyed by user id.",
mime_type="application/json",
)
def user_profile(user_id: str) -> str:
"""Return a JSON profile for the given user id."""
return json.dumps({"id": user_id, "display_name": f"User {user_id}"})
The template ships with three examples: a static resource
(config://server-info) plus two templates (greeting://{name} and
users://{user_id}/profile). Clients discover them via list_resources /
list_resource_templates and fetch content with read_resource.
Adding your own prompts
Prompts are reusable message templates. Register new prompts in
src/mcp_server_template/prompts.py by
decorating a function with @mcp.prompt. Function parameters become the
prompt's arguments, and the docstring becomes its description. Return a plain
string for a single user message, or a list of Message objects for a
multi-turn template:
from fastmcp.prompts import Message
@mcp.prompt(name="summarize-text", description="Summarize the provided text.")
def summarize_text(text: str) -> list[Message]:
"""Prime the model to summarize the given text."""
return [
Message("You are a concise summarizer.", role="assistant"),
Message(f"Summarize the following text:\n\n{text}"),
]
The template ships with two examples: explain-topic (single message with an
optional level argument) and summarize-text (multi-message). Clients
discover them via list_prompts and render them with get_prompt.
Using the request context
Tools, resources, and prompts can access per-request MCP capabilities through
the FastMCP Context object. Declare a parameter annotated as Context and
FastMCP injects it automatically — clients never supply it, and it does not
appear in the tool's input schema. The context provides structured logging back
to the client, incremental progress reporting, resource access, sampling,
elicitation, and per-request metadata:
from fastmcp import Context
@mcp.tool
async def process_items(count: int, ctx: Context) -> dict[str, object]:
"""Process items while reporting progress and logging to the client."""
await ctx.info(f"Processing {count} items for request {ctx.request_id}")
for index in range(1, count + 1):
await ctx.report_progress(progress=index, total=count)
result = await ctx.read_resource("config://server-info")
return {"processed": count, "request_id": ctx.request_id}
The process_items tool in
src/mcp_server_template/tools.py
demonstrates client logging (ctx.info / ctx.debug), progress reporting
(ctx.report_progress), and reading a server resource (ctx.read_resource).
Clients receive the log and progress notifications via the log_handler and
progress_handler callbacks.
Development
A Makefile wraps the common tasks. List all targets with:
make help
Run the checks:
make check # format-check, lint, type-check, tests
make ci # same checks as GitHub Actions CI
Other useful targets: make install / make install-all, make sync
(install from the lockfile), make lock (regenerate it), make format,
make lint-fix, make run / make run-http, make docker-build /
make docker-run, and make clean.
The equivalent raw commands are:
ruff format --check . # formatting
ruff check . # lint
mypy src # type-check
pytest -q # tests
CI runs the same checks across Python 3.10, 3.11, and 3.12 on every push and pull request — see .github/workflows/ci.yml.
License
MIT — see LICENSE.
Install Py Server Template in Claude Desktop, Claude Code & Cursor
unyly install py-server-templateInstalls into Claude Desktop, Claude Code, Cursor & VS Code — handles npx, uvx and build-from-source repos for you.
First time? Get the CLI: curl -fsSL https://unyly.org/install | sh
Or configure manually
Run in your terminal:
claude mcp add py-server-template -- uvx --from git+https://github.com/Omar-Emam-99/mcp-py-server-template mcp-py-server-templateStep-by-step: how to install Py Server Template
FAQ
Is Py Server Template MCP free?
Yes, Py Server Template MCP is free — one-click install via Unyly at no cost.
Does Py Server Template need an API key?
No, Py Server Template runs without API keys or environment variables.
Is Py Server Template hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Py Server Template in Claude Desktop, Claude Code or Cursor?
Open Py Server Template on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Unyly Deploy
Deploy sites and MCP servers to Unyly straight from your AI agent
by UnylyAmap Maps Mcp Server
MCP server for using the AMap Maps API
by duxiaohuiPayMCP
Lightweight payments layer for MCP servers: turn tools into paid endpoints with a two-line decorator. [PyPI](https://pypi.org/project/paymcp/) · [npm](https://w
by blustAITemplate MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectSupabase
Database, auth and storage
by SupabaseEverything
Reference / test server with prompts, resources, and tools.
Git
Tools to read, search, and manipulate Git repositories.
Compare Py Server Template with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All development MCPs
