diff --git a/docs/docs.json b/docs/docs.json index 17d49594f..fa0b4a866 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -52,84 +52,97 @@ } }, "navigation": { - "groups": [ + "anchors": [ { - "group": "Get Started", - "pages": [ - "getting-started/welcome", - "getting-started/installation", - "getting-started/quickstart", - "updates" - ] - }, - { - "group": "Servers", - "pages": [ - "servers/fastmcp", + "anchor": "Documentation", + "groups": [ { - "group": "Core Components", - "icon": "toolbox", + "group": "Get Started", "pages": [ - "servers/tools", - "servers/resources", - "servers/prompts", - "servers/context" + "getting-started/welcome", + "getting-started/installation", + "getting-started/quickstart", + "updates" ] }, { - "group": "Authentication", - "icon": "shield-check", + "group": "Servers", "pages": [ - "servers/auth/bearer" + "servers/fastmcp", + { + "group": "Core Components", + "icon": "toolbox", + "pages": [ + "servers/tools", + "servers/resources", + "servers/prompts", + "servers/context" + ] + }, + { + "group": "Authentication", + "icon": "shield-check", + "pages": [ + "servers/auth/bearer" + ] + }, + "servers/openapi", + "servers/proxy", + "servers/composition", + { + "group": "Deployment", + "icon": "upload", + "pages": [ + "deployment/running-server", + "deployment/asgi" + ] + } ] }, - "servers/openapi", - "servers/proxy", - "servers/composition", { - "group": "Deployment", - "icon": "upload", + "group": "Clients", "pages": [ - "deployment/running-server", - "deployment/asgi" + "clients/client", + "clients/transports", + { + "group": "Authentication", + "icon": "user-shield", + "pages": [ + "clients/auth/oauth", + "clients/auth/bearer" + ] + }, + "clients/advanced-features" + ] + }, + { + "group": "Integrations", + "pages": [ + "integrations/anthropic", + "integrations/claude-desktop", + "integrations/openai", + "integrations/gemini", + "integrations/contrib" + ] + }, + { + "group": "Patterns", + "pages": [ + "patterns/tool-transformation", + "patterns/decorating-methods", + "patterns/http-requests", + "patterns/testing", + "patterns/cli" ] } - ] + ], + "icon": "book" }, { - "group": "Clients", + "anchor": "Tutorials", + "icon": "graduation-cap", "pages": [ - "clients/client", - "clients/transports", - { - "group": "Authentication", - "icon": "user-shield", - "pages": [ - "clients/auth/oauth", - "clients/auth/bearer" - ] - }, - "clients/advanced-features" - ] - }, - { - "group": "Integrations", - "pages": [ - "integrations/anthropic", - "integrations/claude-desktop", - "integrations/openai", - "integrations/gemini", - "integrations/contrib" - ] - }, - { - "group": "Patterns", - "pages": [ - "patterns/tool-transformation", - "patterns/decorating-methods", - "patterns/http-requests", - "patterns/testing", - "patterns/cli" + "tutorials/create-mcp-server" ] } ] diff --git a/docs/tutorials/create-mcp-server.mdx b/docs/tutorials/create-mcp-server.mdx new file mode 100644 index 000000000..de1000703 --- /dev/null +++ b/docs/tutorials/create-mcp-server.mdx @@ -0,0 +1,198 @@ +--- +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. + + +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. + + +### 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. +