mcp-server-template
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-server-template Show me how to add a new custom tool to this MCP server template."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-server-template
Template repository for building MCP servers in Python with FastMCP.
It ships a working server with one example of each building block (tool, resource, prompt, service, schema) so you can clone it, delete the examples, and start writing your own features immediately.
Design goals: simple, organized, low coupling. server.py only assembles the server —
everything else lives behind explicit register_* functions.
Requirements
Python 3.12+
Related MCP server: Python MCP Server Template
Installation
uv syncThat creates .venv, installs runtime + dev dependencies, and installs the project itself
(so import mcp_server works with the src/ layout — no sys.path hacks).
Optional configuration:
cp .env.example .envRunning
STDIO (default — for local clients like Claude Desktop)
uv run fastmcp run src/mcp_server/server.py:mcpHTTP
uv run fastmcp run src/mcp_server/server.py:mcp \
--transport http \
--host 0.0.0.0 \
--port 8000Using the settings from .env
The installed entry point reads MCP_TRANSPORT, MCP_HOST and MCP_PORT:
uv run mcp-serverTests
uv run pytestTests drive the server in memory through fastmcp.Client(server) — no HTTP server, no
subprocess. The client fixture in tests/conftest.py does the wiring:
async def test_echo(client):
result = await client.call_tool("echo", {"message": "hello"})
assert result.data.result == "hello"Quality
uv run ruff check . # lint
uv run ruff format . # formatProject structure
mcp-server-template/
├── src/
│ └── mcp_server/
│ ├── server.py # assembly only: create_server() + mcp
│ ├── config.py # pydantic-settings (MCP_* env vars)
│ ├── tools/ # register_tools(mcp)
│ ├── resources/ # register_resources(mcp)
│ ├── prompts/ # register_prompts(mcp)
│ ├── services/ # business logic, MCP-agnostic
│ └── schemas/ # pydantic models
├── tests/
├── .env.example
├── Dockerfile
├── pyproject.toml
└── README.mdThe flow is always the same:
tool/resource/prompt -> service -> schema
(MCP surface) (logic) (data)Configuration
Settings come from environment variables (or .env) via pydantic-settings. Each field maps
to an MCP_-prefixed variable:
Variable | Default | Description |
|
| Name advertised to clients |
|
|
|
|
| HTTP host |
|
| HTTP port |
|
| Log level |
Add a new setting by adding a typed field to Settings in
src/mcp_server/config.py and documenting it in .env.example.
How to create a new tool
Create
src/mcp_server/tools/my_feature.py:
from fastmcp import FastMCP
from mcp_server.services.my_service import do_the_work
def register_my_feature_tool(mcp: FastMCP) -> None:
@mcp.tool
def my_feature(query: str, limit: int = 10) -> list[str]:
"""One-line description the model will read.
Args:
query: What to look for.
limit: Maximum number of results.
"""
return do_the_work(query, limit=limit)Register it in
src/mcp_server/tools/__init__.py:
from mcp_server.tools.my_feature import register_my_feature_tool
def register_tools(mcp: FastMCP) -> None:
register_my_feature_tool(mcp)Notes:
The docstring is the tool description sent to the model — write it for the model.
Return a Pydantic model (see
schemas/) when the output has structure.Keep the logic in a service; the tool stays a thin adapter.
Use
async defonly when the work is actually I/O-bound (HTTP calls, DB, etc.).
How to create a resource
# src/mcp_server/resources/my_resource.py
from fastmcp import FastMCP
def register_my_resource(mcp: FastMCP) -> None:
@mcp.resource("data://items", mime_type="application/json")
def items() -> list[dict[str, str]]:
"""Static resource: fixed URI."""
return [{"id": "1", "name": "example"}]
@mcp.resource("data://items/{item_id}")
def item(item_id: str) -> dict[str, str]:
"""Resource template: the URI carries a parameter."""
return {"id": item_id, "name": "example"}Then add register_my_resource(mcp) to register_resources in resources/__init__.py.
How to create a prompt
# src/mcp_server/prompts/my_prompt.py
from fastmcp import FastMCP
def register_my_prompt(mcp: FastMCP) -> None:
@mcp.prompt
def review_code(code: str, language: str = "python") -> str:
"""Ask the model to review a snippet."""
return f"Review this {language} code and list concrete issues:\n\n{code}"Then add register_my_prompt(mcp) to register_prompts in prompts/__init__.py.
Adding an external integration
Put the client in services/ (e.g. services/github_service.py), read credentials from
config.py, and keep the tool as a thin wrapper. The service never imports FastMCP, so it
stays unit-testable on its own.
Removing the examples
The echo example is self-contained. To drop it:
rm src/mcp_server/tools/echo.py \
src/mcp_server/resources/server_info.py \
src/mcp_server/prompts/summarize.py \
src/mcp_server/services/echo_service.py \
src/mcp_server/schemas/echo.py \
tests/test_tools_echo.py \
tests/test_services_echo.py \
tests/test_resources_and_prompts.pyThen remove the matching import + call in tools/__init__.py, resources/__init__.py and
prompts/__init__.py, and drop the capability assertions in tests/test_server.py.
Docker
docker build -t mcp-server-template .
docker run --rm -p 8000:8000 mcp-server-templateThe image runs the HTTP transport on port 8000 (MCP_TRANSPORT=http, MCP_HOST=0.0.0.0).
Pass overrides with -e, e.g. docker run --rm -p 8000:8000 -e MCP_SERVER_NAME=my-server ....
MCP client configuration
Claude Code
The repo ships a project-scoped .mcp.json: open the project in Claude Code
and approve the server when prompted. Or register it yourself:
claude mcp add my-server -- uv run --directory /absolute/path/to/mcp-server-template fastmcp run src/mcp_server/server.py:mcpThe bundled .mcp.json uses a relative path, so it assumes the client launches the server
from the project root. If yours doesn't, add --directory /absolute/path after run.
Codex CLI
Codex uses TOML, not JSON. In ~/.codex/config.toml (or a project-scoped
.codex/config.toml):
[mcp_servers.my-server]
command = "uv"
args = ["run", "--directory", "/absolute/path/to/mcp-server-template",
"fastmcp", "run", "src/mcp_server/server.py:mcp"]
[mcp_servers.my-server.env]
MCP_SERVER_NAME = "my-server"Or via CLI:
codex mcp add my-server -- uv run --directory /absolute/path/to/mcp-server-template fastmcp run src/mcp_server/server.py:mcpGeneric STDIO (other clients)
{
"mcpServers": {
"my-server": {
"command": "uv",
"args": [
"run",
"--directory",
"/absolute/path/to/mcp-server-template",
"fastmcp",
"run",
"src/mcp_server/server.py:mcp"
],
"env": {
"MCP_SERVER_NAME": "my-server"
}
}
}
}HTTP (server already running)
{
"mcpServers": {
"my-server": {
"url": "http://localhost:8000/mcp"
}
}
}Codex equivalent:
[mcp_servers.my-server]
url = "http://localhost:8000/mcp"On Windows,
uvmust be resolvable by the client process. It lives in%USERPROFILE%\.localin; if the client can't find it, use the absolute path touv.exeascommand.
License
No license file is included on purpose — add the one your project needs.
Available Tools
1 toolechoEchoA
Echo a message back, optionally repeated.
Inputs: message (required), times. Returns: Structured output returned by the ``echo`` tool.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 1 tool
With only one tool, there is no possibility of ambiguity or misselection. The tool name 'echo' is clear and the single purpose is obvious.
There is only one tool, so no pattern can be established. The name itself is a clean, descriptive verb, but consistency cannot be meaningfully assessed with a single instance.
The server exposes a single trivial tool ('echo'), which is far too thin to serve any meaningful MCP workflow. As per calibration, a single trivial tool warrants the lowest score.
The tool surface is severely incomplete for any practical domain. Even as a template, offering only an echo tool provides essentially no functionality that an agent could build upon.
Maintenance
Related MCP Connectors
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
MCP server for progressive tool usage at any scale (see https://klavis.ai)
Model Context Protocol server for the Apideck Unified API. Connect any MCP-compatible agent framework to 100+ accounting systems, HRIS platforms, file storage providers, and more through one integration. More information https://www.apideck.com/mcp-server
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA basic MCP server template that provides a foundation for building custom tools, resources, and prompts. Serves as a starting point for developers to create their own MCP server functionality.-
- FlicenseNot gradedqualityDmaintenanceA foundational template for building MCP servers in Python using Streamable HTTP transport. Provides example implementations of tools, resources, and prompts to help developers create custom MCP integrations for AI assistants.-
- AlicenseNot gradedqualityDmaintenanceA bare-bones FastMCP server template designed to serve as a starting point for building custom Model Context Protocol servers. It provides a foundational structure for implementing tools over HTTP and includes a built-in health check utility.GPL 3.0
- FlicenseNot gradedqualityDmaintenanceA production-ready Python scaffold for building Model Context Protocol (MCP) servers using FastMCP. It provides a structured framework for developers and AI agents to rapidly develop, test, and manage custom tools and workflows.1-