A minimal, production-ready FastMCP server template. Use this as a starting point for building your own MCP (Model Context Protocol) server.
A clean reference implementation that includes:
| Feature | Details |
|---|---|
| Auto-discovery | Drop .py files into src/tools/, src/prompts/, or src/resources/ — they register automatically |
| YAML config | Base + environment-specific overrides with env-var substitution |
| Auth middleware | Bearer token, toggle on/off via config — no code change needed |
| Graceful shutdown | SIGINT / SIGTERM handlers |
| Request logging | Correlation IDs, per-request timing, level-aware |
| Knowledgebase | YAML-backed topic store, live-reloadable without restart |
| Docker | Dockerfile + docker-compose.yml included |
| 3 example tools | echo_message, greet, calculate |
| 2 KB tools | search_knowledgebase, get_knowledgebase_topic |
| 3 example prompts | general_assistant, task_helper, analysis_mode |
| 3 example resources | capabilities, quick-reference, server info |
├── src/
│ ├── mcp_app.py # FastMCP instance — import `mcp` from here
│ ├── server.py # Entry point: Starlette app, middleware, routing
│ ├── tools/
│ │ ├── example_tools.py # echo_message, greet, calculate
│ │ └── knowledgebase_tools.py # search_knowledgebase, get_knowledgebase_topic
│ ├── prompts/
│ │ └── example_prompts.py # general_assistant, task_helper, analysis_mode
│ ├── resources/
│ │ ├── help_resources.py # help://<name>/capabilities, quick-reference
│ │ └── server_info.py # data://server/info
│ └── utils/
│ └── logging_middleware.py # HTTP logging with correlation IDs
├── config/
│ ├── config.py # Config loader (YAML + env vars)
│ ├── settings.yaml # Base configuration
│ ├── settings.dev.yaml # Overrides for ENV=dev
│ └── settings.prod.yaml # Overrides for ENV=prod
├── knowledgebase/
│ ├── loader.py # Loads topics.yaml (no caching)
│ └── topics.yaml # Knowledgebase topic definitions
├── Dockerfile
├── docker-compose.yml
├── .dockerignore
├── .env.example
├── requirements.txt
├── README.md
└── CLAUDE.md
python -m venv .venv
# Windows:
.venv\Scripts\activate
# macOS / Linux:
source .venv/bin/activate
pip install -r requirements.txt# Default (port 8000, no auth, INFO logging):
python src/server.py
# Development mode (DEBUG logging):
ENV=dev python src/server.py
# Custom port:
MCP_PORT=9000 python src/server.py
# With authentication:
AUTH_ENABLED=true AUTH_TOKEN=my-secret python src/server.py
# Production mode (auth on, WARNING logging):
ENV=prod AUTH_TOKEN=my-secret python src/server.pyServer is available at http://localhost:8000.
# Build and start:
docker compose up --build
# With auth enabled:
AUTH_ENABLED=true AUTH_TOKEN=my-secret docker compose up --build
# Detached:
docker compose up -d
# Stop:
docker compose downThe container exposes port 8000 (override with MCP_PORT env var for the host port).
knowledgebase/topics.yaml is bind-mounted so you can update topics without rebuilding the image.
| Variable | Default | Description |
|---|---|---|
ENV |
default |
Config file selector: default, dev, prod |
MCP_PORT |
8000 |
HTTP listen port |
AUTH_ENABLED |
false |
Enable bearer token auth (true / false) |
AUTH_TOKEN |
— | Bearer token value (required when auth is enabled) |
AUTO_DISCOVER |
true |
Auto-import all tools / prompts / resources |
Edit config/settings.yaml for persistent defaults.
Copy .env.example to .env for local overrides (never commit .env).
Set logging.level in config/settings.yaml to DEBUG, INFO, WARNING, or ERROR.
Override per environment in settings.dev.yaml / settings.prod.yaml.
Disabled by default. To enable:
- Set
AUTH_ENABLED=trueenv var orsecurity.authentication.enabled: truein YAML - Set
AUTH_TOKEN=<your-token>env var orsecurity.authentication.tokenin YAML
All MCP requests then require:
Authorization: Bearer <your-token>
Health-check paths (/healthz, /health, /version) are always unauthenticated.
On startup src/server.py calls import_submodules() for the tools, resources, and
prompts packages. This uses pkgutil.iter_modules() to find every non-private .py file,
imports it, and the @mcp.tool() / @mcp.resource() / @mcp.prompt() decorators register
with the global mcp instance in src/mcp_app.py.
- Files starting with
_are skipped automatically — use this to temporarily disable a module. - To disable entirely:
AUTO_DISCOVER=false, then import modules manually insrc/server.py.
# src/tools/my_tool.py
from mcp_app import mcp
@mcp.tool(name="my_tool", description="Does something useful.")
def my_tool(input: str) -> dict:
return {"result": input.upper()}Restart the server — no other changes needed.
# src/prompts/my_prompt.py
from mcp_app import mcp
@mcp.prompt(name="my_prompt", description="A focused system prompt.")
def my_prompt(context: str = "") -> str:
return f"You are a helpful assistant. Context: {context}"# src/resources/my_resource.py
from mcp_app import mcp
@mcp.resource("data://my-domain/my-resource")
def my_resource() -> dict:
return {"data": "your payload here"}Edit knowledgebase/topics.yaml — no server restart needed:
topics:
my_topic:
title: "My Topic"
tags: [example]
content: |
Topic content goes here.# Health check:
curl http://localhost:8000/healthz
# Version:
curl http://localhost:8000/version
# With auth:
curl -H "Authorization: Bearer my-secret" http://localhost:8000/healthzConnect with any MCP-compatible client (Claude Desktop, MCP Inspector, etc.).
This template is designed to be cloned and extended with the help of AI coding agents (Claude Code, Amazon Q, Cursor, etc.).
git clone <this-repo> my-mcp-server
cd my-mcp-server
claudeClaude Code automatically reads CLAUDE.md at the project root — no extra setup needed.
Just describe what you want to build.
Open the project in your IDE with the Amazon Q plugin installed.
The .amazonq/rules/mcp-conventions.md file is auto-loaded into every chat session.
Describe what you want to build — Q will follow the template conventions.
Reference the conventions file explicitly:
@CLAUDE.md Build me an MCP server that does X, Y, Z.
See STARTER_PROMPTS.md for ready-to-paste prompts you can give any AI agent to scaffold a new MCP server from this template.
Targets FastMCP >= 2.0.0. Key patterns:
| Pattern | Where |
|---|---|
FastMCP(name="...") |
src/mcp_app.py |
mcp.http_app(transport="streamable-http") |
src/server.py |
async with mcp_http_app.lifespan(app) |
src/server.py lifespan |
@mcp.tool() / @mcp.resource() / @mcp.prompt() |
tools / resources / prompts |
If you upgrade to a new FastMCP major version, verify these four patterns first.
See CLAUDE.md for full architecture details and coding rules.