-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Description
Description
Summary
The current Python SDK docs and examples focus on minimal, single-file servers (e.g. weather.py with all tools in one module). This is great for getting started but leaves a gap for users who are building larger, multi-tool or multi-team MCP servers.
With modelcontextprotocol/modelcontextprotocol#1575 introducing tool versioning support, it would be useful to document a recommended FastMCP server layout that scales well, including:
- A clear separation between MCP wiring and tool implementations.
- How to organize tools into modules.
- How to implement and register multiple versions of a tool in Python.
Motivation
As soon as a server grows beyond a couple of tools, authors start reinventing patterns:
- One giant
server.pyfile with all tools mixed in. - Ad-hoc imports where helpers and MCP wiring are interleaved.
- Inconsistent placement of new versions of tools (new file vs. new function vs. new package).
A light-weight, documented pattern in the Python SDK would help:
- Teams share a consistent “shape” for MCP servers.
- New contributors can navigate repositories more easily.
- Versioned tools from SEP-1575 can be implemented in a predictable way.
Proposed pattern
1. Server entrypoint (server.py)
- A single entrypoint file that handles:
- Creating the
FastMCPinstance. - Configuring transports and logging.
- Registering tools imported from
tools/. - The
main()function andif __name__ == "__main__":guard.
- Creating the
Example (simplified):
# server.py
from mcp.server.fastmcp import FastMCP
from .tools.get_info import get_info_v1, get_info_v2
mcp = FastMCP("example-server")
# Register versioned tools (SEP-1575)
mcp.add_tool(get_info_v1, name="get_info", version="1.0.0")
mcp.add_tool(get_info_v2, name="get_info", version="2.0.0")
def main() -> None:
mcp.run(transport="stdio")
if __name__ == "__main__":
main()2. Tools package (tools/)
-
A Python package
tools/with one module per conceptual tool:tools/get_info.pytools/list_invoices.py- etc.
-
Each module contains:
- Pure business logic helpers.
- One or more versioned handler functions for MCP.
Example:
# tools/get_info.py
from typing import Any
def _get_info_core(resource_id: str) -> dict[str, Any]:
# Shared logic across all versions
...
async def get_info_v1(resource_id: str) -> str:
"""Legacy text-only version."""
data = _get_info_core(resource_id)
return f"{data['name']}\n{data['description']}"
async def get_info_v2(resource_id: str) -> dict[str, Any]:
"""Structured JSON version."""
return _get_info_core(resource_id)The decorators can either live here (using FastMCP as a global) or be applied in server.py when registering tools, depending on the desired separation of concerns.
3. Versioned tools with SEP-1575
- For SEP-1575-based versioning, the recommended SDK usage would be:
# server.py
from mcp.server.fastmcp import FastMCP
from .tools.get_info import get_info_v1, get_info_v2
mcp = FastMCP("example-server")
@mcp.tool(name="get_info", version="1.0.0")
async def get_info_v1_handler(resource_id: str) -> str:
return await get_info_v1(resource_id)
@mcp.tool(name="get_info", version="2.0.0")
async def get_info_v2_handler(resource_id: str) -> dict[str, Any]:
return await get_info_v2(resource_id)Or, using add_tool if that is preferred over decorators.
This shows:
- Stable tool name:
"get_info". - Multiple versions via the
versionargument. - A natural place to factor shared logic.
Proposed changes in this repo
-
Documentation
-
Add a new section under the server docs (e.g.
Server PatternsorScaling your server) describing this layout and its rationale. -
Include a short code example of:
server.pywiring.tools/<tool>.pymodule with multiple versions.- How to use
versionwith FastMCP decorators oradd_tool.
-
-
Example project
-
Add an
examples/versioned_server/example (or similar):-
Uses the proposed layout.
-
Demonstrates:
- Multiple tools in
tools/. - One tool with two versions (
1.x,2.x). - How clients can call different versions (e.g. via
tool_requirementsin a small client script).
- Multiple tools in
-
-
-
Cross-link from tutorials
-
From the existing “Build a server” quickstart, add a short “Next steps” link:
- “For larger projects, see the recommended server layout in [link].”
-
Alternatives / Open Questions
- Should the SDK encourage decorators-in-module vs. decorators-in-server patterns, or present both as valid?
- Should there be a simple CLI template (e.g.
mcp init) that scaffolds this layout? - How tightly should this layout guidance be coupled to SEP-1575 (e.g. only documented once tool versioning is merged and stable)?
How I can help
I am happy to:
- Draft the documentation page for the proposed layout.
- Contribute a small
examples/versioned_server/example aligned with SEP-1575. - Iterate on naming and structure based on maintainer feedback.
References
No response