MCP Template
by aviciot
README.md
# MCP Template
A minimal, production-ready **FastMCP** server template.
Use this as a starting point for building your own MCP (Model Context Protocol) server.
## What This Is
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 |
## Project Structure
```
├── 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
```
## Installation
```bash
python -m venv .venv
# Windows:
.venv\Scripts\activate
# macOS / Linux:
source .venv/bin/activate
pip install -r requirements.txt
```
## Running Locally
```bash
# 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.py
```
Server is available at `http://localhost:8000`.
## Running with Docker
```bash
# 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 down
```
The 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.
## Configuration
### Environment Variables
| 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 |
### YAML Configuration
Edit `config/settings.yaml` for persistent defaults.
Copy `.env.example` to `.env` for local overrides (never commit `.env`).
### Logging Level
Set `logging.level` in `config/settings.yaml` to `DEBUG`, `INFO`, `WARNING`, or `ERROR`.
Override per environment in `settings.dev.yaml` / `settings.prod.yaml`.
## Authentication
Disabled by default. To enable:
1. Set `AUTH_ENABLED=true` env var **or** `security.authentication.enabled: true` in YAML
2. Set `AUTH_TOKEN=<your-token>` env var **or** `security.authentication.token` in YAML
All MCP requests then require:
```
Authorization: Bearer <your-token>
```
Health-check paths (`/healthz`, `/health`, `/version`) are always unauthenticated.
## How Auto-Discovery Works
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 in `src/server.py`.
## How to Add a New Tool
```python
# 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.
## How to Add a New Prompt
```python
# 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}"
```
## How to Add a New Resource
```python
# 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"}
```
## How to Add Knowledgebase Topics
Edit `knowledgebase/topics.yaml` — **no server restart needed**:
```yaml
topics:
my_topic:
title: "My Topic"
tags: [example]
content: |
Topic content goes here.
```
## How to Test
```bash
# Health check:
curl http://localhost:8000/healthz
# Version:
curl http://localhost:8000/version
# With auth:
curl -H "Authorization: Bearer my-secret" http://localhost:8000/healthz
```
Connect with any MCP-compatible client (Claude Desktop, MCP Inspector, etc.).
## Getting Started with AI Agents
This template is designed to be cloned and extended with the help of AI coding agents
(Claude Code, Amazon Q, Cursor, etc.).
### Claude Code (CLI)
```bash
git clone <this-repo> my-mcp-server
cd my-mcp-server
claude
```
Claude Code **automatically reads `CLAUDE.md`** at the project root — no extra setup needed.
Just describe what you want to build.
### Amazon Q (IDE)
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.
### Cursor / Windsurf / Other IDEs
Reference the conventions file explicitly:
```
@CLAUDE.md Build me an MCP server that does X, Y, Z.
```
### Starter Prompts
See **[STARTER_PROMPTS.md](STARTER_PROMPTS.md)** for ready-to-paste prompts you can give
any AI agent to scaffold a new MCP server from this template.
---
## FastMCP Notes
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.
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues