fastmcp 2.2.4__tar.gz → 2.2.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. {fastmcp-2.2.4 → fastmcp-2.2.6}/PKG-INFO +2 -2
  2. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/clients/client.mdx +71 -64
  3. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/docs.json +2 -1
  4. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/patterns/fastapi.mdx +35 -14
  5. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/patterns/openapi.mdx +97 -27
  6. fastmcp-2.2.6/docs/patterns/testing.mdx +38 -0
  7. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/servers/context.mdx +69 -15
  8. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/servers/prompts.mdx +12 -21
  9. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/servers/resources.mdx +40 -29
  10. fastmcp-2.2.6/docs/servers/tools.mdx +666 -0
  11. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/smart_home/src/smart_home/lights/server.py +25 -13
  12. {fastmcp-2.2.4 → fastmcp-2.2.6}/pyproject.toml +1 -1
  13. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/__init__.py +1 -0
  14. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/client/client.py +12 -8
  15. fastmcp-2.2.6/src/fastmcp/client/logging.py +13 -0
  16. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/client/sampling.py +2 -0
  17. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/client/transports.py +37 -4
  18. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/prompts/prompt.py +43 -4
  19. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/prompts/prompt_manager.py +14 -3
  20. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/resources/resource.py +12 -2
  21. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/resources/resource_manager.py +20 -5
  22. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/resources/template.py +43 -4
  23. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/resources/types.py +55 -11
  24. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/server/context.py +15 -13
  25. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/server/openapi.py +86 -31
  26. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/server/proxy.py +38 -21
  27. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/server/server.py +49 -15
  28. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/tools/tool.py +22 -6
  29. fastmcp-2.2.6/tests/client/test_logs.py +60 -0
  30. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/server/test_openapi.py +203 -5
  31. fastmcp-2.2.6/tests/server/test_server.py +736 -0
  32. fastmcp-2.2.4/tests/server/test_server.py → fastmcp-2.2.6/tests/server/test_server_interactions.py +606 -784
  33. fastmcp-2.2.6/tests/tools/__init__.py +0 -0
  34. fastmcp-2.2.4/docs/servers/tools.mdx +0 -341
  35. fastmcp-2.2.4/src/fastmcp/client/base.py +0 -1
  36. {fastmcp-2.2.4 → fastmcp-2.2.6}/.cursor/rules/core-mcp-objects.mdc +0 -0
  37. {fastmcp-2.2.4 → fastmcp-2.2.6}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
  38. {fastmcp-2.2.4 → fastmcp-2.2.6}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  39. {fastmcp-2.2.4 → fastmcp-2.2.6}/.github/ISSUE_TEMPLATE/enhancement.yml +0 -0
  40. {fastmcp-2.2.4 → fastmcp-2.2.6}/.github/release.yml +0 -0
  41. {fastmcp-2.2.4 → fastmcp-2.2.6}/.github/workflows/publish.yml +0 -0
  42. {fastmcp-2.2.4 → fastmcp-2.2.6}/.github/workflows/run-static.yml +0 -0
  43. {fastmcp-2.2.4 → fastmcp-2.2.6}/.github/workflows/run-tests.yml +0 -0
  44. {fastmcp-2.2.4 → fastmcp-2.2.6}/.gitignore +0 -0
  45. {fastmcp-2.2.4 → fastmcp-2.2.6}/.pre-commit-config.yaml +0 -0
  46. {fastmcp-2.2.4 → fastmcp-2.2.6}/LICENSE +0 -0
  47. {fastmcp-2.2.4 → fastmcp-2.2.6}/README.md +0 -0
  48. {fastmcp-2.2.4 → fastmcp-2.2.6}/Windows_Notes.md +0 -0
  49. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/assets/demo-inspector.png +0 -0
  50. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/clients/transports.mdx +0 -0
  51. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/getting-started/installation.mdx +0 -0
  52. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/getting-started/quickstart.mdx +0 -0
  53. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/getting-started/welcome.mdx +0 -0
  54. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/patterns/composition.mdx +0 -0
  55. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/patterns/contrib.mdx +0 -0
  56. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/patterns/decorating-methods.mdx +0 -0
  57. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/patterns/proxy.mdx +0 -0
  58. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/servers/fastmcp.mdx +0 -0
  59. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/snippets/version-badge.mdx +0 -0
  60. {fastmcp-2.2.4 → fastmcp-2.2.6}/docs/style.css +0 -0
  61. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/complex_inputs.py +0 -0
  62. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/desktop.py +0 -0
  63. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/echo.py +0 -0
  64. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/memory.py +0 -0
  65. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/mount_example.py +0 -0
  66. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/readme-quickstart.py +0 -0
  67. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/sampling.py +0 -0
  68. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/screenshot.py +0 -0
  69. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/simple_echo.py +0 -0
  70. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/smart_home/README.md +0 -0
  71. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/smart_home/pyproject.toml +0 -0
  72. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/smart_home/src/smart_home/__init__.py +0 -0
  73. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/smart_home/src/smart_home/__main__.py +0 -0
  74. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/smart_home/src/smart_home/hub.py +0 -0
  75. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/smart_home/src/smart_home/lights/__init__.py +0 -0
  76. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/smart_home/src/smart_home/lights/hue_utils.py +0 -0
  77. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/smart_home/src/smart_home/py.typed +0 -0
  78. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/smart_home/src/smart_home/settings.py +0 -0
  79. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/smart_home/uv.lock +0 -0
  80. {fastmcp-2.2.4 → fastmcp-2.2.6}/examples/text_me.py +0 -0
  81. {fastmcp-2.2.4 → fastmcp-2.2.6}/justfile +0 -0
  82. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/cli/__init__.py +0 -0
  83. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/cli/claude.py +0 -0
  84. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/cli/cli.py +0 -0
  85. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/client/__init__.py +0 -0
  86. /fastmcp-2.2.4/src/fastmcp/py.typed → /fastmcp-2.2.6/src/fastmcp/client/base.py +0 -0
  87. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/client/roots.py +0 -0
  88. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/contrib/README.md +0 -0
  89. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/contrib/bulk_tool_caller/README.md +0 -0
  90. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/contrib/bulk_tool_caller/__init__.py +0 -0
  91. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py +0 -0
  92. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/contrib/bulk_tool_caller/example.py +0 -0
  93. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/contrib/mcp_mixin/README.md +0 -0
  94. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/contrib/mcp_mixin/__init__.py +0 -0
  95. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/contrib/mcp_mixin/example.py +0 -0
  96. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/contrib/mcp_mixin/mcp_mixin.py +0 -0
  97. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/exceptions.py +0 -0
  98. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/prompts/__init__.py +0 -0
  99. /fastmcp-2.2.4/tests/__init__.py → /fastmcp-2.2.6/src/fastmcp/py.typed +0 -0
  100. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/resources/__init__.py +0 -0
  101. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/server/__init__.py +0 -0
  102. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/settings.py +0 -0
  103. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/tools/__init__.py +0 -0
  104. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/tools/tool_manager.py +0 -0
  105. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/utilities/__init__.py +0 -0
  106. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/utilities/decorators.py +0 -0
  107. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/utilities/func_metadata.py +0 -0
  108. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/utilities/logging.py +0 -0
  109. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/utilities/openapi.py +0 -0
  110. {fastmcp-2.2.4 → fastmcp-2.2.6}/src/fastmcp/utilities/types.py +0 -0
  111. {fastmcp-2.2.4/tests/prompts → fastmcp-2.2.6/tests}/__init__.py +0 -0
  112. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/cli/test_run.py +0 -0
  113. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/client/__init__.py +0 -0
  114. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/client/test_client.py +0 -0
  115. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/client/test_roots.py +0 -0
  116. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/client/test_sampling.py +0 -0
  117. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/conftest.py +0 -0
  118. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/contrib/__init__.py +0 -0
  119. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/contrib/test_bulk_tool_caller.py +0 -0
  120. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/contrib/test_mcp_mixin.py +0 -0
  121. {fastmcp-2.2.4/tests/resources → fastmcp-2.2.6/tests/prompts}/__init__.py +0 -0
  122. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/prompts/test_base.py +0 -0
  123. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/prompts/test_prompt_manager.py +0 -0
  124. {fastmcp-2.2.4/tests/server → fastmcp-2.2.6/tests/resources}/__init__.py +0 -0
  125. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/resources/test_file_resources.py +0 -0
  126. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/resources/test_function_resources.py +0 -0
  127. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/resources/test_resource_manager.py +0 -0
  128. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/resources/test_resource_template.py +0 -0
  129. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/resources/test_resources.py +0 -0
  130. {fastmcp-2.2.4/tests/tools → fastmcp-2.2.6/tests/server}/__init__.py +0 -0
  131. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/server/test_file_server.py +0 -0
  132. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/server/test_import_server.py +0 -0
  133. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/server/test_lifespan.py +0 -0
  134. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/server/test_mount.py +0 -0
  135. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/server/test_proxy.py +0 -0
  136. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/server/test_run_server.py +0 -0
  137. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/test_servers/fastmcp_server.py +0 -0
  138. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/test_servers/sse.py +0 -0
  139. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/test_servers/stdio.py +0 -0
  140. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/tools/test_tool_manager.py +0 -0
  141. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/utilities/__init__.py +0 -0
  142. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/utilities/openapi/__init__.py +0 -0
  143. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/utilities/openapi/conftest.py +0 -0
  144. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/utilities/openapi/test_openapi.py +0 -0
  145. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/utilities/openapi/test_openapi_advanced.py +0 -0
  146. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/utilities/openapi/test_openapi_fastapi.py +0 -0
  147. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/utilities/test_decorated_function.py +0 -0
  148. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/utilities/test_func_metadata.py +0 -0
  149. {fastmcp-2.2.4 → fastmcp-2.2.6}/tests/utilities/test_logging.py +0 -0
  150. {fastmcp-2.2.4 → fastmcp-2.2.6}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastmcp
3
- Version: 2.2.4
3
+ Version: 2.2.6
4
4
  Summary: The fast, Pythonic way to build MCP servers.
5
5
  Project-URL: Homepage, https://gofastmcp.com
6
6
  Project-URL: Repository, https://github.com/jlowin/fastmcp
@@ -24,7 +24,7 @@ Requires-Dist: openapi-pydantic>=0.5.1
24
24
  Requires-Dist: python-dotenv>=1.1.0
25
25
  Requires-Dist: rich>=13.9.4
26
26
  Requires-Dist: typer>=0.15.2
27
- Requires-Dist: websockets>=15.0.1
27
+ Requires-Dist: websockets>=14.0
28
28
  Description-Content-Type: text/markdown
29
29
 
30
30
  <div align="center">
@@ -149,83 +149,90 @@ The `Client` provides methods corresponding to standard MCP requests:
149
149
  * **`list_prompts()`**: Retrieves available prompt templates.
150
150
  * **`get_prompt(name: str, arguments: dict[str, Any] | None = None)`**: Retrieves a rendered prompt message list.
151
151
 
152
- ### Callbacks
152
+ ### Advanced Features
153
153
 
154
- MCP allows servers to make requests *back* to the client for certain capabilities. The `Client` constructor accepts callback functions to handle these server requests:
154
+ MCP allows servers to interact with clients in order to provide additional capabilities. The `Client` constructor accepts additional configuration to handle these server requests.
155
155
 
156
- #### Roots
157
156
 
158
- * **`roots: RootsList | RootsHandler | None`**: Provides the server with a list of root directories the client grants access to. This can be a static list or a function that dynamically determines roots.
159
- ```python
160
- from pathlib import Path
161
- from fastmcp.client.roots import RootsHandler, RootsList
162
- from mcp.shared.context import RequestContext # For type hint
163
-
164
- # Option 1: Static list
165
- static_roots: RootsList = [str(Path.home() / "Documents")]
166
-
167
- # Option 2: Dynamic function
168
- def dynamic_roots_handler(context: RequestContext) -> RootsList:
169
- # Logic to determine accessible roots based on context
170
- print(f"Server requested roots (Request ID: {context.request_id})")
171
- return [str(Path.home() / "Downloads")]
172
-
173
- client_with_roots = Client(
174
- "my_server.py",
175
- roots=dynamic_roots_handler # or roots=static_roots
176
- )
157
+ #### LLM Sampling
177
158
 
178
- # Tell the server the roots might have changed (if needed)
179
- # async with client_with_roots:
180
- # await client_with_roots.send_roots_list_changed()
181
- ```
182
- See `fastmcp.client.roots` for helpers.
159
+ MCP Servers can request LLM completions from clients. The client can provide a `sampling_handler` to handle these requests. The sampling handler receives a list of messages and other parameters from the server, and should return a string completion.
183
160
 
184
- #### LLM Sampling
161
+ The following example uses the `marvin` library to generate a completion:
185
162
 
186
- * **`sampling_handler: SamplingHandler | None`**: Handles `sampling/createMessage` requests from the server. This callback receives messages from the server and should return an LLM completion.
187
- ```python
188
- from fastmcp.client.sampling import SamplingHandler, MessageResult
189
- from mcp.types import SamplingMessage, SamplingParams, TextContent
190
- from mcp.shared.context import RequestContext # For type hint
191
-
192
- async def my_llm_handler(
193
- messages: list[SamplingMessage],
194
- params: SamplingParams,
195
- context: RequestContext
196
- ) -> str | MessageResult:
197
- print(f"Server requested sampling (Request ID: {context.request_id})")
198
- # In a real scenario, call your LLM API here
199
- last_user_message = next((m for m in reversed(messages) if m.role == 'user'), None)
200
- prompt = last_user_message.content.text if last_user_message and isinstance(last_user_message.content, TextContent) else "Default prompt"
201
-
202
- # Simulate LLM response
203
- response_text = f"LLM processed: {prompt[:50]}..."
204
- # Return simple string (becomes TextContent) or a MessageResult object
205
- return response_text
206
-
207
- client_with_sampling = Client(
208
- "my_server.py",
209
- sampling_handler=my_llm_handler
163
+ ```python {8-17, 21}
164
+ import marvin
165
+ from fastmcp import Client
166
+ from fastmcp.client.sampling import (
167
+ SamplingMessage,
168
+ SamplingParams,
169
+ RequestContext,
170
+ )
171
+
172
+ async def sampling_handler(
173
+ messages: list[SamplingMessage],
174
+ params: SamplingParams,
175
+ context: RequestContext
176
+ ) -> str:
177
+ return await marvin.say_async(
178
+ message=[m.content.text for m in messages],
179
+ instructions=params.systemPrompt,
210
180
  )
211
- ```
212
- See `fastmcp.client.sampling` for helpers.
181
+
182
+ client = Client(
183
+ ...,
184
+ sampling_handler=sampling_handler,
185
+ )
186
+ ```
213
187
 
214
188
  #### Logging
215
189
 
216
- * **`log_handler: LoggingFnT | None`**: Receives log messages sent from the server (`ctx.info`, `ctx.error`, etc.).
217
- ```python
218
- from mcp.client.session import LoggingFnT, LogLevel
190
+ MCP servers can emit logs to clients. The client can set a logging callback to receive these logs.
219
191
 
220
- def my_log_handler(level: LogLevel, message: str, logger_name: str | None):
221
- print(f"[Server Log - {level.upper()}] {logger_name or 'default'}: {message}")
192
+ ```python {4-5, 9}
193
+ from fastmcp import Client
194
+ from fastmcp.client.logging import LogHandler, LogMessage
222
195
 
223
- client_with_logging = Client(
224
- "my_server.py",
225
- log_handler=my_log_handler
226
- )
227
- ```
196
+ async def my_log_handler(params: LogMessage):
197
+ print(f"[Server Log - {params.level.upper()}] {params.logger or 'default'}: {params.data}")
228
198
 
199
+ client_with_logging = Client(
200
+ ...,
201
+ log_handler=my_log_handler,
202
+ )
203
+ ```
204
+
205
+ #### Roots
206
+
207
+ Roots are a way for clients to inform servers about the resources they have access to or certain boundaries on their access. The server can use this information to adjust behavior or provide more accurate responses.
208
+
209
+ Servers can request roots from clients, and clients can notify servers when their roots change.
210
+
211
+ To set the roots when creating a client, users can either provide a list of roots (which can be a list of strings) or an async function that returns a list of roots.
212
+
213
+ <CodeGroup>
214
+ ```python Static Roots {5}
215
+ from fastmcp import Client
216
+
217
+ client = Client(
218
+ ...,
219
+ roots=["/path/to/root1", "/path/to/root2"],
220
+ )
221
+ ```
222
+ ```python Dynamic Roots Callback {4-6, 10}
223
+ from fastmcp import Client
224
+ from fastmcp.client.roots import RequestContext
225
+
226
+ async def roots_callback(context: RequestContext) -> list[str]:
227
+ print(f"Server requested roots (Request ID: {context.request_id})")
228
+ return ["/path/to/root1", "/path/to/root2"]
229
+
230
+ client = Client(
231
+ ...,
232
+ roots=roots_callback,
233
+ )
234
+ ```
235
+ </CodeGroup>
229
236
  ### Utility Methods
230
237
 
231
238
  * **`ping()`**: Sends a ping request to the server to verify connectivity.
@@ -62,7 +62,8 @@
62
62
  "patterns/decorating-methods",
63
63
  "patterns/openapi",
64
64
  "patterns/fastapi",
65
- "patterns/contrib"
65
+ "patterns/contrib",
66
+ "patterns/testing"
66
67
  ]
67
68
  },
68
69
  {
@@ -44,6 +44,19 @@ if __name__ == "__main__":
44
44
  mcp.run() # Start the MCP server
45
45
  ```
46
46
 
47
+ ## Configuration Options
48
+
49
+ ### Timeout
50
+
51
+ You can set a timeout for all API requests:
52
+
53
+ ```python
54
+ # Set a 5 second timeout for all requests
55
+ mcp = FastMCP.from_fastapi(app=app, timeout=5.0)
56
+ ```
57
+
58
+ This timeout is applied to all requests made by tools, resources, and resource templates.
59
+
47
60
  ## Route Mapping
48
61
 
49
62
  By default, FastMCP will map FastAPI routes to MCP components according to the following rules:
@@ -60,7 +73,7 @@ For more details on route mapping or custom mapping rules, see the [OpenAPI inte
60
73
 
61
74
  Here's a more detailed example with a data model:
62
75
 
63
- ```python
76
+ ```python [expandable]
64
77
  import asyncio
65
78
  from fastapi import FastAPI, HTTPException
66
79
  from pydantic import BaseModel
@@ -95,24 +108,32 @@ def create_item(item: Item):
95
108
  return items[item_id]
96
109
 
97
110
  # Test your MCP server with a client
98
- async def test():
99
- # Create MCP server from FastAPI app
100
- mcp = await FastMCP.from_fastapi(app=app)
101
-
111
+ async def check_mcp(mcp: FastMCP):
102
112
  # List the components that were created
103
- tools = await mcp.list_tools()
104
- resources = await mcp.list_resources()
105
- templates = await mcp.list_resource_templates()
113
+ tools = await mcp.get_tools()
114
+ resources = await mcp.get_resources()
115
+ templates = await mcp.get_resource_templates()
106
116
 
107
- print(f"Generated {len(tools)} tools")
108
- print(f"Generated {len(resources)} resources")
109
- print(f"Generated {len(templates)} templates")
117
+ print(
118
+ f"{len(tools)} Tool(s): {', '.join([t.name for t in tools.values()])}"
119
+ )
120
+ print(
121
+ f"{len(resources)} Resource(s): {', '.join([r.name for r in resources.values()])}"
122
+ )
123
+ print(
124
+ f"{len(templates)} Resource Template(s): {', '.join([t.name for t in templates.values()])}"
125
+ )
110
126
 
111
- # In a real scenario, you would run the server:
112
- # mcp.run()
127
+ return mcp
113
128
 
114
129
  if __name__ == "__main__":
115
- asyncio.run(test())
130
+ # Create MCP server from FastAPI app
131
+ mcp = FastMCP.from_fastapi(app=app)
132
+
133
+ asyncio.run(check_mcp(mcp))
134
+
135
+ # In a real scenario, you would run the server:
136
+ mcp.run()
116
137
  ```
117
138
 
118
139
  ## Benefits
@@ -27,6 +27,23 @@ if __name__ == "__main__":
27
27
  mcp.run()
28
28
  ```
29
29
 
30
+ ## Configuration Options
31
+
32
+ ### Timeout
33
+
34
+ You can set a timeout for all API requests:
35
+
36
+ ```python
37
+ # Set a 5 second timeout for all requests
38
+ mcp = FastMCP.from_openapi(
39
+ openapi_spec=spec,
40
+ client=api_client,
41
+ timeout=5.0
42
+ )
43
+ ```
44
+
45
+ This timeout is applied to all requests made by tools, resources, and resource templates.
46
+
30
47
  ## Route Mapping
31
48
 
32
49
  By default, OpenAPI routes are mapped to MCP components based on these rules:
@@ -89,26 +106,67 @@ mcp = await FastMCP.from_openapi(
89
106
  - It sends the request through the provided httpx client
90
107
  - It translates the HTTP response to the appropriate MCP format
91
108
 
92
- ## Complete Example
109
+ ### Request Parameter Handling
110
+
111
+ FastMCP carefully handles different types of parameters in OpenAPI requests:
112
+
113
+ #### Query Parameters
114
+
115
+ By default, FastMCP will only include query parameters that have non-empty values. Parameters with `None` values or empty strings (`""`) are automatically filtered out of requests. This ensures that API servers don't receive unnecessary empty parameters that might cause issues.
93
116
 
117
+ For example, if you call a tool with these parameters:
94
118
  ```python
119
+ await client.call_tool("search_products", {
120
+ "category": "electronics", # Will be included
121
+ "min_price": 100, # Will be included
122
+ "max_price": None, # Will be excluded
123
+ "brand": "", # Will be excluded
124
+ })
125
+ ```
126
+
127
+ The resulting HTTP request will only include `category=electronics&min_price=100`.
128
+
129
+ #### Path Parameters
130
+
131
+ For path parameters, which are typically required by REST APIs, FastMCP filters out `None` values and checks that all required path parameters are provided. If a required path parameter is missing or `None`, an error will be raised.
132
+
133
+ ```python
134
+ # This will work
135
+ await client.call_tool("get_product", {"product_id": 123})
136
+
137
+ # This will raise ValueError: "Missing required path parameters: {'product_id'}"
138
+ await client.call_tool("get_product", {"product_id": None})
139
+ ```
140
+
141
+ ## Complete Example
142
+
143
+ ```python [expandable]
95
144
  import asyncio
145
+
96
146
  import httpx
147
+
97
148
  from fastmcp import FastMCP
98
149
 
99
150
  # Sample OpenAPI spec for a Pet Store API
100
151
  petstore_spec = {
101
152
  "openapi": "3.0.0",
153
+ "info": {
154
+ "title": "Pet Store API",
155
+ "version": "1.0.0",
156
+ "description": "A sample API for managing pets",
157
+ },
102
158
  "paths": {
103
159
  "/pets": {
104
160
  "get": {
105
161
  "operationId": "listPets",
106
- "summary": "List all pets"
162
+ "summary": "List all pets",
163
+ "responses": {"200": {"description": "A list of pets"}},
107
164
  },
108
165
  "post": {
109
166
  "operationId": "createPet",
110
- "summary": "Create a new pet"
111
- }
167
+ "summary": "Create a new pet",
168
+ "responses": {"201": {"description": "Pet created successfully"}},
169
+ },
112
170
  },
113
171
  "/pets/{petId}": {
114
172
  "get": {
@@ -119,38 +177,50 @@ petstore_spec = {
119
177
  "name": "petId",
120
178
  "in": "path",
121
179
  "required": True,
122
- "schema": {"type": "string"}
180
+ "schema": {"type": "string"},
123
181
  }
124
- ]
182
+ ],
183
+ "responses": {
184
+ "200": {"description": "Pet details"},
185
+ "404": {"description": "Pet not found"},
186
+ },
125
187
  }
126
- }
127
- }
188
+ },
189
+ },
128
190
  }
129
191
 
130
- async def main():
192
+
193
+ async def check_mcp(mcp: FastMCP):
194
+ # List what components were created
195
+ tools = await mcp.get_tools()
196
+ resources = await mcp.get_resources()
197
+ templates = await mcp.get_resource_templates()
198
+
199
+ print(
200
+ f"{len(tools)} Tool(s): {', '.join([t.name for t in tools.values()])}"
201
+ ) # Should include createPet
202
+ print(
203
+ f"{len(resources)} Resource(s): {', '.join([r.name for r in resources.values()])}"
204
+ ) # Should include listPets
205
+ print(
206
+ f"{len(templates)} Resource Template(s): {', '.join([t.name for t in templates.values()])}"
207
+ ) # Should include getPet
208
+
209
+ return mcp
210
+
211
+
212
+ if __name__ == "__main__":
131
213
  # Client for the Pet Store API
132
214
  client = httpx.AsyncClient(base_url="https://petstore.example.com/api")
133
-
215
+
134
216
  # Create the MCP server
135
- mcp = await FastMCP.from_openapi(
136
- openapi_spec=petstore_spec,
137
- client=client,
138
- name="PetStore"
217
+ mcp = FastMCP.from_openapi(
218
+ openapi_spec=petstore_spec, client=client, name="PetStore"
139
219
  )
140
-
141
- # List what components were created
142
- tools = await mcp.list_tools()
143
- resources = await mcp.list_resources()
144
- templates = await mcp.list_resource_templates()
145
-
146
- print(f"Tools: {len(tools)}") # Should include createPet
147
- print(f"Resources: {len(resources)}") # Should include listPets
148
- print(f"Templates: {len(templates)}") # Should include getPet
149
-
220
+
221
+ asyncio.run(check_mcp(mcp))
222
+
150
223
  # Start the MCP server
151
224
  mcp.run()
152
-
153
- if __name__ == "__main__":
154
- asyncio.run(main())
155
225
  ```
156
226
 
@@ -0,0 +1,38 @@
1
+ ---
2
+ title: Testing MCP Servers
3
+ sidebarTitle: Testing
4
+ description: Learn how to test your FastMCP servers effectively
5
+ icon: vial
6
+ ---
7
+
8
+
9
+ Testing your MCP servers thoroughly is essential for ensuring they work correctly when deployed. FastMCP makes this easy through a variety of testing patterns.
10
+
11
+ ## In-Memory Testing
12
+
13
+ The most efficient way to test an MCP server is to pass your FastMCP server instance directly to a Client. This enables in-memory testing without having to start a separate server process, which is particularly useful because managing an MCP server programmatically can be challenging.
14
+
15
+ Here is an example of using a `Client` to test a server with pytest:
16
+
17
+ ```python
18
+ import pytest
19
+ from fastmcp import FastMCP, Client
20
+
21
+ @pytest.fixture
22
+ def mcp_server():
23
+ server = FastMCP("TestServer")
24
+
25
+ @server.tool()
26
+ def greet(name: str) -> str:
27
+ return f"Hello, {name}!"
28
+
29
+ return server
30
+
31
+ async def test_tool_functionality(mcp_server):
32
+ # Pass the server directly to the Client constructor
33
+ async with Client(mcp_server) as client:
34
+ result = await client.call_tool("greet", {"name": "World"})
35
+ assert "Hello, World!" in str(result[0])
36
+ ```
37
+
38
+ This pattern creates a direct connection between the client and server, allowing you to test your server's functionality efficiently.
@@ -1,16 +1,16 @@
1
1
  ---
2
2
  title: MCP Context
3
3
  sidebarTitle: Context
4
- description: Access MCP capabilities like logging, progress, and resources within your tools.
4
+ description: Access MCP capabilities like logging, progress, and resources within your MCP objects.
5
5
  icon: rectangle-code
6
6
  ---
7
7
  import { VersionBadge } from '/snippets/version-badge.mdx'
8
8
 
9
- When defining FastMCP [tools](/servers/tools), your functions might need to interact with the underlying MCP session or access server capabilities. FastMCP provides the `Context` object for this purpose.
9
+ When defining FastMCP [tools](/servers/tools), [resources](/servers/resources), resource templates, or [prompts](/servers/prompts), your functions might need to interact with the underlying MCP session or access server capabilities. FastMCP provides the `Context` object for this purpose.
10
10
 
11
11
  ## What Is Context?
12
12
 
13
- The `Context` object provides a clean interface to access MCP features within your tool functions, including:
13
+ The `Context` object provides a clean interface to access MCP features within your functions, including:
14
14
 
15
15
  - **Logging**: Send debug, info, warning, and error messages back to the client
16
16
  - **Progress Reporting**: Update the client on the progress of long-running operations
@@ -19,9 +19,9 @@ The `Context` object provides a clean interface to access MCP features within yo
19
19
  - **Request Information**: Access metadata about the current request
20
20
  - **Server Access**: When needed, access the underlying FastMCP server instance
21
21
 
22
- ## Accessing Context
22
+ ## Accessing the Context
23
23
 
24
- To use the context object within your tool function, simply add a parameter to your function signature and type-hint it as `Context`. FastMCP will automatically inject the context instance when your tool is called.
24
+ To use the context object within any of your functions, simply add a parameter to your function signature and type-hint it as `Context`. FastMCP will automatically inject the context instance when your function is called.
25
25
 
26
26
  ```python
27
27
  from fastmcp import FastMCP, Context
@@ -65,15 +65,15 @@ async def process_file(file_uri: str, ctx: Context) -> str:
65
65
 
66
66
  - The parameter name (e.g., `ctx`, `context`) doesn't matter, only the type hint `Context` is important.
67
67
  - The context parameter can be placed anywhere in your function's signature.
68
- - The context is optional - tools that don't need it can omit the parameter.
69
- - Context is only available within tool functions during a request; attempting to use context methods outside a request will raise errors.
70
- - Context methods are async, so your tool function usually needs to be async as well.
68
+ - The context is optional - functions that don't need it can omit the parameter.
69
+ - Context is only available during a request; attempting to use context methods outside a request will raise errors.
70
+ - Context methods are async, so your function usually needs to be async as well.
71
71
 
72
72
  ## Context Capabilities
73
73
 
74
74
  ### Logging
75
75
 
76
- Send log messages back to the MCP client. This is useful for debugging and providing visibility into tool execution during a request.
76
+ Send log messages back to the MCP client. This is useful for debugging and providing visibility into function execution during a request.
77
77
 
78
78
  ```python
79
79
  @mcp.tool()
@@ -97,14 +97,14 @@ async def analyze_data(data: list[float], ctx: Context) -> dict:
97
97
  **Available Logging Methods:**
98
98
 
99
99
  - **`ctx.debug(message: str)`**: Low-level details useful for debugging
100
- - **`ctx.info(message: str)`**: General information about tool execution
100
+ - **`ctx.info(message: str)`**: General information about execution
101
101
  - **`ctx.warning(message: str)`**: Potential issues that didn't prevent execution
102
102
  - **`ctx.error(message: str)`**: Errors that occurred during execution
103
103
  - **`ctx.log(level: Literal["debug", "info", "warning", "error"], message: str, logger_name: str | None = None)`**: Generic log method supporting custom logger names
104
104
 
105
105
  ### Progress Reporting
106
106
 
107
- For long-running tools, notify the client about the progress of the operation. This allows clients to display progress indicators and provide a better user experience.
107
+ For long-running operations, notify the client about the progress. This allows clients to display progress indicators and provide a better user experience.
108
108
 
109
109
  ```python
110
110
  @mcp.tool()
@@ -137,7 +137,7 @@ Progress reporting requires the client to have sent a `progressToken` in the ini
137
137
 
138
138
  ### Resource Access
139
139
 
140
- Read data from resources registered with your FastMCP server. This allows tools to access files, configuration, or dynamically generated content.
140
+ Read data from resources registered with your FastMCP server. This allows functions to access files, configuration, or dynamically generated content.
141
141
 
142
142
  ```python
143
143
  @mcp.tool()
@@ -177,7 +177,7 @@ The returned content is typically accessed via `content_list[0].content` and can
177
177
 
178
178
  <VersionBadge version="2.0.0" />
179
179
 
180
- Request the client's LLM to generate text based on provided messages. This is useful when your tool needs to leverage the LLM's capabilities to process data or generate responses.
180
+ Request the client's LLM to generate text based on provided messages. This is useful when your function needs to leverage the LLM's capabilities to process data or generate responses.
181
181
 
182
182
  ```python
183
183
  @mcp.tool()
@@ -279,6 +279,60 @@ async def advanced_tool(ctx: Context) -> str:
279
279
  Direct use of `session` or `request_context` requires understanding the low-level MCP Python SDK and may be less stable than using the methods provided directly on the `Context` object.
280
280
  </Warning>
281
281
 
282
- ## Using Context in Other Components
282
+ ## Using Context in Different Components
283
283
 
284
- Currently, Context is primarily designed for use within tool functions. Support for Context in other components like resources and prompts is planned for future releases.
284
+ All FastMCP components (tools, resources, templates, and prompts) can use the Context object following the same pattern - simply add a parameter with the `Context` type annotation.
285
+
286
+ ### Context in Resources and Templates
287
+
288
+ Resources and resource templates can access context to customize their behavior:
289
+
290
+ ```python
291
+ @mcp.resource("resource://user-data")
292
+ async def get_user_data(ctx: Context) -> dict:
293
+ """Fetch personalized user data based on the request context."""
294
+ user_id = ctx.client_id or "anonymous"
295
+ await ctx.info(f"Fetching data for user {user_id}")
296
+
297
+ # Example of using context for dynamic resource generation
298
+ return {
299
+ "user_id": user_id,
300
+ "last_access": datetime.now().isoformat(),
301
+ "request_id": ctx.request_id
302
+ }
303
+
304
+ @mcp.resource("resource://users/{user_id}/profile")
305
+ async def get_user_profile(user_id: str, ctx: Context) -> dict:
306
+ """Fetch user profile from database with context-aware logging."""
307
+ await ctx.info(f"Fetching profile for user {user_id}")
308
+
309
+ # Example of using context in a template resource
310
+ # In a real implementation, you might query a database
311
+ return {
312
+ "id": user_id,
313
+ "name": f"User {user_id}",
314
+ "request_id": ctx.request_id
315
+ }
316
+ ```
317
+
318
+ ### Context in Prompts
319
+
320
+ Prompts can use context to generate more dynamic templates:
321
+
322
+ ```python
323
+ @mcp.prompt()
324
+ async def data_analysis_request(dataset: str, ctx: Context) -> str:
325
+ """Generate a request to analyze data with contextual information."""
326
+ await ctx.info(f"Generating data analysis prompt for {dataset}")
327
+
328
+ # Could use context to read configuration or personalize the prompt
329
+ return f"""Please analyze the following dataset: {dataset}
330
+
331
+ Request initiated at: {datetime.now().isoformat()}
332
+ Request ID: {ctx.request_id}
333
+ """
334
+ ```
335
+
336
+ <VersionBadge version="2.3.0" />
337
+
338
+ All FastMCP objects now support context injection using the same consistent pattern, making it easy to add session-aware capabilities to all aspects of your MCP server.
@@ -20,7 +20,7 @@ Prompts provide parameterized message templates for LLMs. When a client requests
20
20
 
21
21
  This allows you to define consistent, reusable templates that LLMs can use across different clients and contexts.
22
22
 
23
- ## Defining Prompts
23
+ ## Prompts
24
24
 
25
25
  ### The `@prompt` Decorator
26
26
 
@@ -171,33 +171,24 @@ async def data_based_prompt(data_id: str) -> str:
171
171
 
172
172
  Use `async def` when your prompt function performs I/O operations like network requests, database queries, file I/O, or external service calls.
173
173
 
174
- ### The MCP Session
174
+ ### Accessing MCP Context
175
175
 
176
- Prompts can access the MCP features via the `Context` object, just like tools.
176
+ <VersionBadge version="2.2.5" />
177
177
 
178
- ```python
179
- from fastmcp import Context
178
+ Prompts can access additional MCP information and features through the `Context` object. To access it, add a parameter to your prompt function with a type annotation of `Context`:
179
+
180
+ ```python {6}
181
+ from fastmcp import FastMCP, Context
182
+
183
+ mcp = FastMCP(name="PromptServer")
180
184
 
181
185
  @mcp.prompt()
182
186
  async def generate_report_request(report_type: str, ctx: Context) -> str:
183
- """Generates a request for a report based on available data."""
184
- # Log the request
185
- await ctx.info(f"Generating prompt for report type: {report_type}")
186
-
187
- # Could potentially use ctx.read_resource to fetch data
188
- # Or ctx.sample to get additional input from the LLM
189
-
190
- return f"Please create a {report_type} report based on the available data."
187
+ """Generates a request for a report."""
188
+ return f"Please create a {report_type} report. Request ID: {ctx.request_id}"
191
189
  ```
192
190
 
193
- Using the `ctx` parameter (based on its `Context` type hint), you can access:
194
-
195
- - **Logging:** `ctx.debug()`, `ctx.info()`, etc.
196
- - **Resource Access:** `ctx.read_resource(uri)`
197
- - **LLM Sampling:** `ctx.sample(...)`
198
- - **Request Info:** `ctx.request_id`, `ctx.client_id`
199
-
200
- Refer to the [Context documentation](/servers/context) for more details on these capabilities.
191
+ For full documentation on the Context object and all its capabilities, see the [Context documentation](/servers/context).
201
192
 
202
193
  ## Server Behavior
203
194