60e0ffc959
Upgrade checks / Notify on failure (push) Has been cancelled
Upgrade checks / Close issue on success (push) Has been cancelled
Schema Crash Test / Real-world schema crash test (232K schemas) (push) Has been cancelled
Run static analysis / static_analysis (push) Has been cancelled
Tests / Tests: Python 3.10 on ubuntu-latest (push) Has been cancelled
Tests / Tests: Python 3.13 on ubuntu-latest (push) Has been cancelled
Tests / Tests: Python 3.10 on windows-latest (push) Has been cancelled
Tests / Tests with lowest-direct dependencies (push) Has been cancelled
Tests / MCP conformance tests (push) Has been cancelled
Tests / Integration tests (push) Has been cancelled
Tests / Package install smoke (push) Has been cancelled
Upgrade checks / Static analysis (push) Has been cancelled
Upgrade checks / Tests: Python 3.10 on ubuntu-latest (push) Has been cancelled
Upgrade checks / Tests: Python 3.13 on ubuntu-latest (push) Has been cancelled
Upgrade checks / Tests: Python 3.10 on windows-latest (push) Has been cancelled
Upgrade checks / Integration tests (push) Has been cancelled
Update MCPServerConfig Schema / update-config-schema (push) Has been cancelled
Update SDK Documentation / update-sdk-docs (push) Has been cancelled
199 lines
7.0 KiB
Plaintext
199 lines
7.0 KiB
Plaintext
---
|
|
title: "How to Create an MCP Server in Python"
|
|
sidebarTitle: "Creating an MCP Server"
|
|
description: "A step-by-step guide to building a Model Context Protocol (MCP) server using Python and FastMCP, from basic tools to dynamic resources."
|
|
icon: server
|
|
---
|
|
|
|
So you want to build a Model Context Protocol (MCP) server in Python. The goal is to create a service that can provide tools and data to AI models like Claude, Gemini, or others that support the protocol. While the [MCP specification](https://modelcontextprotocol.io/specification/) is powerful, implementing it from scratch involves a lot of boilerplate: handling JSON-RPC, managing session state, and correctly formatting requests and responses.
|
|
|
|
This is where **FastMCP** comes in. It's a high-level framework that handles all the protocol complexities for you, letting you focus on what matters: writing the Python functions that power your server.
|
|
|
|
This guide will walk you through creating a fully-featured MCP server from scratch using FastMCP.
|
|
|
|
<Tip>
|
|
Every code block in this tutorial is a complete, runnable example. You can copy and paste it into a file and run it, or paste it directly into a Python REPL like IPython to try it out.
|
|
</Tip>
|
|
|
|
### Prerequisites
|
|
|
|
Make sure you have FastMCP installed. If not, follow the [installation guide](/getting-started/installation).
|
|
|
|
```bash
|
|
pip install fastmcp
|
|
```
|
|
|
|
|
|
## Step 1: Create the Basic Server
|
|
|
|
Every FastMCP application starts with an instance of the `FastMCP` class. This object acts as the container for all your tools and resources.
|
|
|
|
Create a new file called `my_mcp_server.py`:
|
|
|
|
```python my_mcp_server.py
|
|
from fastmcp import FastMCP
|
|
|
|
# Create a server instance with a descriptive name
|
|
mcp = FastMCP(name="My First MCP Server")
|
|
```
|
|
|
|
That's it! You have a valid (though empty) MCP server. Now, let's add some functionality.
|
|
|
|
## Step 2: Add a Tool
|
|
|
|
Tools are functions that an LLM can execute. Let's create a simple tool that adds two numbers.
|
|
|
|
To do this, simply write a standard Python function and decorate it with `@mcp.tool`.
|
|
|
|
```python my_mcp_server.py {5-8}
|
|
from fastmcp import FastMCP
|
|
|
|
mcp = FastMCP(name="My First MCP Server")
|
|
|
|
@mcp.tool
|
|
def add(a: int, b: int) -> int:
|
|
"""Adds two integer numbers together."""
|
|
return a + b
|
|
```
|
|
|
|
FastMCP automatically handles the rest:
|
|
- **Tool Name:** It uses the function name (`add`) as the tool's name.
|
|
- **Description:** It uses the function's docstring as the tool's description for the LLM.
|
|
- **Schema:** It inspects the type hints (`a: int`, `b: int`) to generate a JSON schema for the inputs.
|
|
|
|
This is the core philosophy of FastMCP: **write Python, not protocol boilerplate.**
|
|
|
|
## Step 3: Expose Data with Resources
|
|
|
|
Resources provide read-only data to the LLM. You can define a resource by decorating a function with `@mcp.resource`, providing a unique URI.
|
|
|
|
Let's expose a simple configuration dictionary as a resource.
|
|
|
|
```python my_mcp_server.py {10-13}
|
|
from fastmcp import FastMCP
|
|
|
|
mcp = FastMCP(name="My First MCP Server")
|
|
|
|
@mcp.tool
|
|
def add(a: int, b: int) -> int:
|
|
"""Adds two integer numbers together."""
|
|
return a + b
|
|
|
|
@mcp.resource("resource://config")
|
|
def get_config() -> dict:
|
|
"""Provides the application's configuration."""
|
|
return {"version": "1.0", "author": "MyTeam"}
|
|
```
|
|
|
|
When a client requests the URI `resource://config`, FastMCP will execute the `get_config` function and return its output (serialized as JSON) to the client. The function is only called when the resource is requested, enabling lazy-loading of data.
|
|
|
|
## Step 4: Generate Dynamic Content with Resource Templates
|
|
|
|
Sometimes, you need to generate resources based on parameters. This is what **Resource Templates** are for. You define them using the same `@mcp.resource` decorator but with placeholders in the URI.
|
|
|
|
Let's create a template that provides a personalized greeting.
|
|
|
|
```python my_mcp_server.py {15-17}
|
|
from fastmcp import FastMCP
|
|
|
|
mcp = FastMCP(name="My First MCP Server")
|
|
|
|
@mcp.tool
|
|
def add(a: int, b: int) -> int:
|
|
"""Adds two integer numbers together."""
|
|
return a + b
|
|
|
|
@mcp.resource("resource://config")
|
|
def get_config() -> dict:
|
|
"""Provides the application's configuration."""
|
|
return {"version": "1.0", "author": "MyTeam"}
|
|
|
|
@mcp.resource("greetings://{name}")
|
|
def personalized_greeting(name: str) -> str:
|
|
"""Generates a personalized greeting for the given name."""
|
|
return f"Hello, {name}! Welcome to the MCP server."
|
|
```
|
|
|
|
Now, clients can request dynamic URIs:
|
|
- `greetings://Ford` will call `personalized_greeting(name="Ford")`.
|
|
- `greetings://Marvin` will call `personalized_greeting(name="Marvin")`.
|
|
|
|
FastMCP automatically maps the `{name}` placeholder in the URI to the `name` parameter in your function.
|
|
|
|
## Step 5: Run the Server
|
|
|
|
To make your server executable, add a `__main__` block to your script that calls `mcp.run()`.
|
|
|
|
```python my_mcp_server.py {19-20}
|
|
from fastmcp import FastMCP
|
|
|
|
mcp = FastMCP(name="My First MCP Server")
|
|
|
|
@mcp.tool
|
|
def add(a: int, b: int) -> int:
|
|
"""Adds two integer numbers together."""
|
|
return a + b
|
|
|
|
@mcp.resource("resource://config")
|
|
def get_config() -> dict:
|
|
"""Provides the application's configuration."""
|
|
return {"version": "1.0", "author": "MyTeam"}
|
|
|
|
@mcp.resource("greetings://{name}")
|
|
def personalized_greeting(name: str) -> str:
|
|
"""Generates a personalized greeting for the given name."""
|
|
return f"Hello, {name}! Welcome to the MCP server."
|
|
|
|
if __name__ == "__main__":
|
|
mcp.run()
|
|
```
|
|
|
|
Now you can run your server from the command line:
|
|
```bash
|
|
python my_mcp_server.py
|
|
```
|
|
This starts the server using the default **STDIO transport**, which is how clients like Claude Desktop communicate with local servers. To learn about other transports, like HTTP, see the [Running Your Server](/deployment/running-server) guide.
|
|
|
|
## The Complete Server
|
|
|
|
Here is the full code for `my_mcp_server.py` (click to expand):
|
|
|
|
```python my_mcp_server.py [expandable]
|
|
from fastmcp import FastMCP
|
|
|
|
# 1. Create the server
|
|
mcp = FastMCP(name="My First MCP Server")
|
|
|
|
# 2. Add a tool
|
|
@mcp.tool
|
|
def add(a: int, b: int) -> int:
|
|
"""Adds two integer numbers together."""
|
|
return a + b
|
|
|
|
# 3. Add a static resource
|
|
@mcp.resource("resource://config")
|
|
def get_config() -> dict:
|
|
"""Provides the application's configuration."""
|
|
return {"version": "1.0", "author": "MyTeam"}
|
|
|
|
# 4. Add a resource template for dynamic content
|
|
@mcp.resource("greetings://{name}")
|
|
def personalized_greeting(name: str) -> str:
|
|
"""Generates a personalized greeting for the given name."""
|
|
return f"Hello, {name}! Welcome to the MCP server."
|
|
|
|
# 5. Make the server runnable
|
|
if __name__ == "__main__":
|
|
mcp.run()
|
|
```
|
|
|
|
## Next Steps
|
|
|
|
You've successfully built an MCP server! From here, you can explore more advanced topics:
|
|
|
|
- [**Tools in Depth**](/servers/tools): Learn about asynchronous tools, error handling, and custom return types.
|
|
- [**Resources & Templates**](/servers/resources): Discover different resource types, including files and HTTP endpoints.
|
|
- [**Prompts**](/servers/prompts): Create reusable prompt templates for your LLM.
|
|
- [**Running Your Server**](/deployment/running-server): Deploy your server with different transports like HTTP.
|
|
|