Jeremiah Lowin commited on
Commit
7e21d4d
·
unverified ·
2 Parent(s): 8346df70661529

Merge pull request #783 from jlowin/tutorials

Browse files
Files changed (2) hide show
  1. docs/docs.json +72 -59
  2. docs/tutorials/create-mcp-server.mdx +198 -0
docs/docs.json CHANGED
@@ -52,84 +52,97 @@
52
  }
53
  },
54
  "navigation": {
55
- "groups": [
56
  {
57
- "group": "Get Started",
58
- "pages": [
59
- "getting-started/welcome",
60
- "getting-started/installation",
61
- "getting-started/quickstart",
62
- "updates"
63
- ]
64
- },
65
- {
66
- "group": "Servers",
67
- "pages": [
68
- "servers/fastmcp",
69
  {
70
- "group": "Core Components",
71
- "icon": "toolbox",
72
  "pages": [
73
- "servers/tools",
74
- "servers/resources",
75
- "servers/prompts",
76
- "servers/context"
77
  ]
78
  },
79
  {
80
- "group": "Authentication",
81
- "icon": "shield-check",
82
  "pages": [
83
- "servers/auth/bearer"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  ]
85
  },
86
- "servers/openapi",
87
- "servers/proxy",
88
- "servers/composition",
89
  {
90
- "group": "Deployment",
91
- "icon": "upload",
92
  "pages": [
93
- "deployment/running-server",
94
- "deployment/asgi"
 
 
 
 
 
 
 
 
 
95
  ]
96
- }
97
- ]
98
- },
99
- {
100
- "group": "Clients",
101
- "pages": [
102
- "clients/client",
103
- "clients/transports",
104
  {
105
- "group": "Authentication",
106
- "icon": "user-shield",
107
  "pages": [
108
- "clients/auth/oauth",
109
- "clients/auth/bearer"
 
 
 
110
  ]
111
  },
112
- "clients/advanced-features"
113
- ]
114
- },
115
- {
116
- "group": "Integrations",
117
- "pages": [
118
- "integrations/anthropic",
119
- "integrations/claude-desktop",
120
- "integrations/openai",
121
- "integrations/gemini",
122
- "integrations/contrib"
123
- ]
124
  },
125
  {
126
- "group": "Patterns",
 
127
  "pages": [
128
- "patterns/tool-transformation",
129
- "patterns/decorating-methods",
130
- "patterns/http-requests",
131
- "patterns/testing",
132
- "patterns/cli"
133
  ]
134
  }
135
  ]
 
52
  }
53
  },
54
  "navigation": {
55
+ "anchors": [
56
  {
57
+ "anchor": "Documentation",
58
+ "groups": [
 
 
 
 
 
 
 
 
 
 
59
  {
60
+ "group": "Get Started",
 
61
  "pages": [
62
+ "getting-started/welcome",
63
+ "getting-started/installation",
64
+ "getting-started/quickstart",
65
+ "updates"
66
  ]
67
  },
68
  {
69
+ "group": "Servers",
 
70
  "pages": [
71
+ "servers/fastmcp",
72
+ {
73
+ "group": "Core Components",
74
+ "icon": "toolbox",
75
+ "pages": [
76
+ "servers/tools",
77
+ "servers/resources",
78
+ "servers/prompts",
79
+ "servers/context"
80
+ ]
81
+ },
82
+ {
83
+ "group": "Authentication",
84
+ "icon": "shield-check",
85
+ "pages": [
86
+ "servers/auth/bearer"
87
+ ]
88
+ },
89
+ "servers/openapi",
90
+ "servers/proxy",
91
+ "servers/composition",
92
+ {
93
+ "group": "Deployment",
94
+ "icon": "upload",
95
+ "pages": [
96
+ "deployment/running-server",
97
+ "deployment/asgi"
98
+ ]
99
+ }
100
  ]
101
  },
 
 
 
102
  {
103
+ "group": "Clients",
 
104
  "pages": [
105
+ "clients/client",
106
+ "clients/transports",
107
+ {
108
+ "group": "Authentication",
109
+ "icon": "user-shield",
110
+ "pages": [
111
+ "clients/auth/oauth",
112
+ "clients/auth/bearer"
113
+ ]
114
+ },
115
+ "clients/advanced-features"
116
  ]
117
+ },
 
 
 
 
 
 
 
118
  {
119
+ "group": "Integrations",
 
120
  "pages": [
121
+ "integrations/anthropic",
122
+ "integrations/claude-desktop",
123
+ "integrations/openai",
124
+ "integrations/gemini",
125
+ "integrations/contrib"
126
  ]
127
  },
128
+ {
129
+ "group": "Patterns",
130
+ "pages": [
131
+ "patterns/tool-transformation",
132
+ "patterns/decorating-methods",
133
+ "patterns/http-requests",
134
+ "patterns/testing",
135
+ "patterns/cli"
136
+ ]
137
+ }
138
+ ],
139
+ "icon": "book"
140
  },
141
  {
142
+ "anchor": "Tutorials",
143
+ "icon": "graduation-cap",
144
  "pages": [
145
+ "tutorials/create-mcp-server"
 
 
 
 
146
  ]
147
  }
148
  ]
docs/tutorials/create-mcp-server.mdx ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: "How to Create an MCP Server in Python"
3
+ sidebarTitle: "Creating an MCP Server"
4
+ description: "A step-by-step guide to building a Model Context Protocol (MCP) server using Python and FastMCP, from basic tools to dynamic resources."
5
+ icon: server
6
+ ---
7
+
8
+ 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.
9
+
10
+ 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.
11
+
12
+ This guide will walk you through creating a fully-featured MCP server from scratch using FastMCP.
13
+
14
+ <Tip>
15
+ 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.
16
+ </Tip>
17
+
18
+ ### Prerequisites
19
+
20
+ Make sure you have FastMCP installed. If not, follow the [installation guide](/getting-started/installation).
21
+
22
+ ```bash
23
+ pip install fastmcp
24
+ ```
25
+
26
+
27
+ ## Step 1: Create the Basic Server
28
+
29
+ Every FastMCP application starts with an instance of the `FastMCP` class. This object acts as the container for all your tools and resources.
30
+
31
+ Create a new file called `my_mcp_server.py`:
32
+
33
+ ```python my_mcp_server.py
34
+ from fastmcp import FastMCP
35
+
36
+ # Create a server instance with a descriptive name
37
+ mcp = FastMCP(name="My First MCP Server")
38
+ ```
39
+
40
+ That's it! You have a valid (though empty) MCP server. Now, let's add some functionality.
41
+
42
+ ## Step 2: Add a Tool
43
+
44
+ Tools are functions that an LLM can execute. Let's create a simple tool that adds two numbers.
45
+
46
+ To do this, simply write a standard Python function and decorate it with `@mcp.tool`.
47
+
48
+ ```python my_mcp_server.py {5-8}
49
+ from fastmcp import FastMCP
50
+
51
+ mcp = FastMCP(name="My First MCP Server")
52
+
53
+ @mcp.tool
54
+ def add(a: int, b: int) -> int:
55
+ """Adds two integer numbers together."""
56
+ return a + b
57
+ ```
58
+
59
+ FastMCP automatically handles the rest:
60
+ - **Tool Name:** It uses the function name (`add`) as the tool's name.
61
+ - **Description:** It uses the function's docstring as the tool's description for the LLM.
62
+ - **Schema:** It inspects the type hints (`a: int`, `b: int`) to generate a JSON schema for the inputs.
63
+
64
+ This is the core philosophy of FastMCP: **write Python, not protocol boilerplate.**
65
+
66
+ ## Step 3: Expose Data with Resources
67
+
68
+ Resources provide read-only data to the LLM. You can define a resource by decorating a function with `@mcp.resource`, providing a unique URI.
69
+
70
+ Let's expose a simple configuration dictionary as a resource.
71
+
72
+ ```python my_mcp_server.py {10-13}
73
+ from fastmcp import FastMCP
74
+
75
+ mcp = FastMCP(name="My First MCP Server")
76
+
77
+ @mcp.tool
78
+ def add(a: int, b: int) -> int:
79
+ """Adds two integer numbers together."""
80
+ return a + b
81
+
82
+ @mcp.resource("resource://config")
83
+ def get_config() -> dict:
84
+ """Provides the application's configuration."""
85
+ return {"version": "1.0", "author": "MyTeam"}
86
+ ```
87
+
88
+ 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.
89
+
90
+ ## Step 4: Generate Dynamic Content with Resource Templates
91
+
92
+ 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.
93
+
94
+ Let's create a template that provides a personalized greeting.
95
+
96
+ ```python my_mcp_server.py {15-17}
97
+ from fastmcp import FastMCP
98
+
99
+ mcp = FastMCP(name="My First MCP Server")
100
+
101
+ @mcp.tool
102
+ def add(a: int, b: int) -> int:
103
+ """Adds two integer numbers together."""
104
+ return a + b
105
+
106
+ @mcp.resource("resource://config")
107
+ def get_config() -> dict:
108
+ """Provides the application's configuration."""
109
+ return {"version": "1.0", "author": "MyTeam"}
110
+
111
+ @mcp.resource("greetings://{name}")
112
+ def personalized_greeting(name: str) -> str:
113
+ """Generates a personalized greeting for the given name."""
114
+ return f"Hello, {name}! Welcome to the MCP server."
115
+ ```
116
+
117
+ Now, clients can request dynamic URIs:
118
+ - `greetings://Ford` will call `personalized_greeting(name="Ford")`.
119
+ - `greetings://Marvin` will call `personalized_greeting(name="Marvin")`.
120
+
121
+ FastMCP automatically maps the `{name}` placeholder in the URI to the `name` parameter in your function.
122
+
123
+ ## Step 5: Run the Server
124
+
125
+ To make your server executable, add a `__main__` block to your script that calls `mcp.run()`.
126
+
127
+ ```python my_mcp_server.py {19-20}
128
+ from fastmcp import FastMCP
129
+
130
+ mcp = FastMCP(name="My First MCP Server")
131
+
132
+ @mcp.tool
133
+ def add(a: int, b: int) -> int:
134
+ """Adds two integer numbers together."""
135
+ return a + b
136
+
137
+ @mcp.resource("resource://config")
138
+ def get_config() -> dict:
139
+ """Provides the application's configuration."""
140
+ return {"version": "1.0", "author": "MyTeam"}
141
+
142
+ @mcp.resource("greetings://{name}")
143
+ def personalized_greeting(name: str) -> str:
144
+ """Generates a personalized greeting for the given name."""
145
+ return f"Hello, {name}! Welcome to the MCP server."
146
+
147
+ if __name__ == "__main__":
148
+ mcp.run()
149
+ ```
150
+
151
+ Now you can run your server from the command line:
152
+ ```bash
153
+ python my_mcp_server.py
154
+ ```
155
+ 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.
156
+
157
+ ## The Complete Server
158
+
159
+ Here is the full code for `my_mcp_server.py` (click to expand):
160
+
161
+ ```python my_mcp_server.py [expandable]
162
+ from fastmcp import FastMCP
163
+
164
+ # 1. Create the server
165
+ mcp = FastMCP(name="My First MCP Server")
166
+
167
+ # 2. Add a tool
168
+ @mcp.tool
169
+ def add(a: int, b: int) -> int:
170
+ """Adds two integer numbers together."""
171
+ return a + b
172
+
173
+ # 3. Add a static resource
174
+ @mcp.resource("resource://config")
175
+ def get_config() -> dict:
176
+ """Provides the application's configuration."""
177
+ return {"version": "1.0", "author": "MyTeam"}
178
+
179
+ # 4. Add a resource template for dynamic content
180
+ @mcp.resource("greetings://{name}")
181
+ def personalized_greeting(name: str) -> str:
182
+ """Generates a personalized greeting for the given name."""
183
+ return f"Hello, {name}! Welcome to the MCP server."
184
+
185
+ # 5. Make the server runnable
186
+ if __name__ == "__main__":
187
+ mcp.run()
188
+ ```
189
+
190
+ ## Next Steps
191
+
192
+ You've successfully built an MCP server! From here, you can explore more advanced topics:
193
+
194
+ - [**Tools in Depth**](/servers/tools): Learn about asynchronous tools, error handling, and custom return types.
195
+ - [**Resources & Templates**](/servers/resources): Discover different resource types, including files and HTTP endpoints.
196
+ - [**Prompts**](/servers/prompts): Create reusable prompt templates for your LLM.
197
+ - [**Running Your Server**](/deployment/running-server): Deploy your server with different transports like HTTP.
198
+