fastmcp 2.2.2__tar.gz → 2.2.4__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 (145) hide show
  1. {fastmcp-2.2.2 → fastmcp-2.2.4}/PKG-INFO +20 -20
  2. {fastmcp-2.2.2 → fastmcp-2.2.4}/README.md +19 -19
  3. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/clients/transports.mdx +4 -0
  4. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/patterns/contrib.mdx +3 -0
  5. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/patterns/proxy.mdx +11 -9
  6. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/servers/fastmcp.mdx +6 -0
  7. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/servers/prompts.mdx +4 -0
  8. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/servers/resources.mdx +72 -3
  9. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/servers/tools.mdx +10 -3
  10. fastmcp-2.2.4/docs/snippets/version-badge.mdx +13 -0
  11. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/style.css +15 -18
  12. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/cli/cli.py +36 -3
  13. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/resources/template.py +6 -3
  14. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/server/openapi.py +13 -59
  15. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/tools/tool.py +6 -1
  16. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/utilities/func_metadata.py +16 -4
  17. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/resources/test_resource_template.py +146 -2
  18. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/server/test_openapi.py +137 -56
  19. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/server/test_server.py +73 -0
  20. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/tools/test_tool_manager.py +14 -20
  21. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/utilities/test_func_metadata.py +68 -0
  22. fastmcp-2.2.2/docs/snippets/version-badge.mdx +0 -8
  23. {fastmcp-2.2.2 → fastmcp-2.2.4}/.cursor/rules/core-mcp-objects.mdc +0 -0
  24. {fastmcp-2.2.2 → fastmcp-2.2.4}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
  25. {fastmcp-2.2.2 → fastmcp-2.2.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  26. {fastmcp-2.2.2 → fastmcp-2.2.4}/.github/ISSUE_TEMPLATE/enhancement.yml +0 -0
  27. {fastmcp-2.2.2 → fastmcp-2.2.4}/.github/release.yml +0 -0
  28. {fastmcp-2.2.2 → fastmcp-2.2.4}/.github/workflows/publish.yml +0 -0
  29. {fastmcp-2.2.2 → fastmcp-2.2.4}/.github/workflows/run-static.yml +0 -0
  30. {fastmcp-2.2.2 → fastmcp-2.2.4}/.github/workflows/run-tests.yml +0 -0
  31. {fastmcp-2.2.2 → fastmcp-2.2.4}/.gitignore +0 -0
  32. {fastmcp-2.2.2 → fastmcp-2.2.4}/.pre-commit-config.yaml +0 -0
  33. {fastmcp-2.2.2 → fastmcp-2.2.4}/LICENSE +0 -0
  34. {fastmcp-2.2.2 → fastmcp-2.2.4}/Windows_Notes.md +0 -0
  35. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/assets/demo-inspector.png +0 -0
  36. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/clients/client.mdx +0 -0
  37. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/docs.json +0 -0
  38. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/getting-started/installation.mdx +0 -0
  39. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/getting-started/quickstart.mdx +0 -0
  40. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/getting-started/welcome.mdx +0 -0
  41. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/patterns/composition.mdx +0 -0
  42. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/patterns/decorating-methods.mdx +0 -0
  43. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/patterns/fastapi.mdx +0 -0
  44. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/patterns/openapi.mdx +0 -0
  45. {fastmcp-2.2.2 → fastmcp-2.2.4}/docs/servers/context.mdx +0 -0
  46. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/complex_inputs.py +0 -0
  47. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/desktop.py +0 -0
  48. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/echo.py +0 -0
  49. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/memory.py +0 -0
  50. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/mount_example.py +0 -0
  51. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/readme-quickstart.py +0 -0
  52. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/sampling.py +0 -0
  53. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/screenshot.py +0 -0
  54. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/simple_echo.py +0 -0
  55. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/smart_home/README.md +0 -0
  56. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/smart_home/pyproject.toml +0 -0
  57. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/smart_home/src/smart_home/__init__.py +0 -0
  58. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/smart_home/src/smart_home/__main__.py +0 -0
  59. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/smart_home/src/smart_home/hub.py +0 -0
  60. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/smart_home/src/smart_home/lights/__init__.py +0 -0
  61. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/smart_home/src/smart_home/lights/hue_utils.py +0 -0
  62. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/smart_home/src/smart_home/lights/server.py +0 -0
  63. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/smart_home/src/smart_home/py.typed +0 -0
  64. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/smart_home/src/smart_home/settings.py +0 -0
  65. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/smart_home/uv.lock +0 -0
  66. {fastmcp-2.2.2 → fastmcp-2.2.4}/examples/text_me.py +0 -0
  67. {fastmcp-2.2.2 → fastmcp-2.2.4}/justfile +0 -0
  68. {fastmcp-2.2.2 → fastmcp-2.2.4}/pyproject.toml +0 -0
  69. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/__init__.py +0 -0
  70. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/cli/__init__.py +0 -0
  71. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/cli/claude.py +0 -0
  72. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/client/__init__.py +0 -0
  73. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/client/base.py +0 -0
  74. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/client/client.py +0 -0
  75. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/client/roots.py +0 -0
  76. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/client/sampling.py +0 -0
  77. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/client/transports.py +0 -0
  78. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/contrib/README.md +0 -0
  79. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/contrib/bulk_tool_caller/README.md +0 -0
  80. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/contrib/bulk_tool_caller/__init__.py +0 -0
  81. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py +0 -0
  82. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/contrib/bulk_tool_caller/example.py +0 -0
  83. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/contrib/mcp_mixin/README.md +0 -0
  84. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/contrib/mcp_mixin/__init__.py +0 -0
  85. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/contrib/mcp_mixin/example.py +0 -0
  86. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/contrib/mcp_mixin/mcp_mixin.py +0 -0
  87. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/exceptions.py +0 -0
  88. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/prompts/__init__.py +0 -0
  89. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/prompts/prompt.py +0 -0
  90. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/prompts/prompt_manager.py +0 -0
  91. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/py.typed +0 -0
  92. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/resources/__init__.py +0 -0
  93. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/resources/resource.py +0 -0
  94. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/resources/resource_manager.py +0 -0
  95. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/resources/types.py +0 -0
  96. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/server/__init__.py +0 -0
  97. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/server/context.py +0 -0
  98. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/server/proxy.py +0 -0
  99. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/server/server.py +0 -0
  100. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/settings.py +0 -0
  101. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/tools/__init__.py +0 -0
  102. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/tools/tool_manager.py +0 -0
  103. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/utilities/__init__.py +0 -0
  104. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/utilities/decorators.py +0 -0
  105. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/utilities/logging.py +0 -0
  106. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/utilities/openapi.py +0 -0
  107. {fastmcp-2.2.2 → fastmcp-2.2.4}/src/fastmcp/utilities/types.py +0 -0
  108. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/__init__.py +0 -0
  109. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/cli/test_run.py +0 -0
  110. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/client/__init__.py +0 -0
  111. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/client/test_client.py +0 -0
  112. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/client/test_roots.py +0 -0
  113. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/client/test_sampling.py +0 -0
  114. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/conftest.py +0 -0
  115. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/contrib/__init__.py +0 -0
  116. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/contrib/test_bulk_tool_caller.py +0 -0
  117. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/contrib/test_mcp_mixin.py +0 -0
  118. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/prompts/__init__.py +0 -0
  119. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/prompts/test_base.py +0 -0
  120. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/prompts/test_prompt_manager.py +0 -0
  121. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/resources/__init__.py +0 -0
  122. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/resources/test_file_resources.py +0 -0
  123. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/resources/test_function_resources.py +0 -0
  124. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/resources/test_resource_manager.py +0 -0
  125. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/resources/test_resources.py +0 -0
  126. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/server/__init__.py +0 -0
  127. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/server/test_file_server.py +0 -0
  128. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/server/test_import_server.py +0 -0
  129. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/server/test_lifespan.py +0 -0
  130. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/server/test_mount.py +0 -0
  131. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/server/test_proxy.py +0 -0
  132. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/server/test_run_server.py +0 -0
  133. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/test_servers/fastmcp_server.py +0 -0
  134. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/test_servers/sse.py +0 -0
  135. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/test_servers/stdio.py +0 -0
  136. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/tools/__init__.py +0 -0
  137. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/utilities/__init__.py +0 -0
  138. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/utilities/openapi/__init__.py +0 -0
  139. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/utilities/openapi/conftest.py +0 -0
  140. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/utilities/openapi/test_openapi.py +0 -0
  141. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/utilities/openapi/test_openapi_advanced.py +0 -0
  142. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/utilities/openapi/test_openapi_fastapi.py +0 -0
  143. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/utilities/test_decorated_function.py +0 -0
  144. {fastmcp-2.2.2 → fastmcp-2.2.4}/tests/utilities/test_logging.py +0 -0
  145. {fastmcp-2.2.2 → fastmcp-2.2.4}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastmcp
3
- Version: 2.2.2
3
+ Version: 2.2.4
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
@@ -141,7 +141,7 @@ FastMCP aims to be:
141
141
  ### Servers
142
142
  - **Create** servers with minimal boilerplate using intuitive decorators
143
143
  - **Proxy** existing servers to modify configuration or transport
144
- - **Compose** servers by into complex applications
144
+ - **Compose** servers into complex applications
145
145
  - **Generate** servers from OpenAPI specs or FastAPI objects
146
146
 
147
147
  ### Clients
@@ -361,32 +361,32 @@ The `Context` object provides:
361
361
 
362
362
  ### Images
363
363
 
364
- Easily handle image input and output using the `fastmcp.Image` helper class.
364
+ Easily handle image outputs using the `fastmcp.Image` helper class.
365
+
366
+ <Tip>
367
+ The below code requires the `pillow` library to be installed.
368
+ </Tip>
365
369
 
366
370
  ```python
367
- from fastmcp import FastMCP, Image
368
- from PIL import Image as PILImage
369
- import io
371
+ from mcp.server.fastmcp import FastMCP, Image
372
+ from io import BytesIO
373
+ try:
374
+ from PIL import Image as PILImage
375
+ except ImportError:
376
+ raise ImportError("Please install the `pillow` library to run this example.")
370
377
 
371
- mcp = FastMCP("Image Demo")
378
+ mcp = FastMCP("My App")
372
379
 
373
380
  @mcp.tool()
374
- def create_thumbnail(image_data: Image) -> Image:
375
- """Creates a 100x100 thumbnail from the provided image."""
376
- img = PILImage.open(io.BytesIO(image_data.data)) # Assumes image_data received as Image with bytes
377
- img.thumbnail((100, 100))
378
- buffer = io.BytesIO()
381
+ def create_thumbnail(image_path: str) -> Image:
382
+ """Create a thumbnail from an image"""
383
+ img = PILImage.open(image_path)
384
+ img.thumbnail((100, 100))
385
+ buffer = BytesIO()
379
386
  img.save(buffer, format="PNG")
380
- # Return a new Image object with the thumbnail data
381
387
  return Image(data=buffer.getvalue(), format="png")
382
-
383
- @mcp.tool()
384
- def load_image_from_disk(path: str) -> Image:
385
- """Loads an image from the specified path."""
386
- # Handles reading file and detecting format based on extension
387
- return Image(path=path)
388
388
  ```
389
- FastMCP handles the conversion to/from the base64-encoded format required by the MCP protocol.
389
+ Return the `Image` helper class from your tool to send an image to the client. The `Image` helper class handles the conversion to/from the base64-encoded format required by the MCP protocol. It works with either a path to an image file, or a bytes object.
390
390
 
391
391
 
392
392
  ### MCP Clients
@@ -112,7 +112,7 @@ FastMCP aims to be:
112
112
  ### Servers
113
113
  - **Create** servers with minimal boilerplate using intuitive decorators
114
114
  - **Proxy** existing servers to modify configuration or transport
115
- - **Compose** servers by into complex applications
115
+ - **Compose** servers into complex applications
116
116
  - **Generate** servers from OpenAPI specs or FastAPI objects
117
117
 
118
118
  ### Clients
@@ -332,32 +332,32 @@ The `Context` object provides:
332
332
 
333
333
  ### Images
334
334
 
335
- Easily handle image input and output using the `fastmcp.Image` helper class.
335
+ Easily handle image outputs using the `fastmcp.Image` helper class.
336
+
337
+ <Tip>
338
+ The below code requires the `pillow` library to be installed.
339
+ </Tip>
336
340
 
337
341
  ```python
338
- from fastmcp import FastMCP, Image
339
- from PIL import Image as PILImage
340
- import io
342
+ from mcp.server.fastmcp import FastMCP, Image
343
+ from io import BytesIO
344
+ try:
345
+ from PIL import Image as PILImage
346
+ except ImportError:
347
+ raise ImportError("Please install the `pillow` library to run this example.")
341
348
 
342
- mcp = FastMCP("Image Demo")
349
+ mcp = FastMCP("My App")
343
350
 
344
351
  @mcp.tool()
345
- def create_thumbnail(image_data: Image) -> Image:
346
- """Creates a 100x100 thumbnail from the provided image."""
347
- img = PILImage.open(io.BytesIO(image_data.data)) # Assumes image_data received as Image with bytes
348
- img.thumbnail((100, 100))
349
- buffer = io.BytesIO()
352
+ def create_thumbnail(image_path: str) -> Image:
353
+ """Create a thumbnail from an image"""
354
+ img = PILImage.open(image_path)
355
+ img.thumbnail((100, 100))
356
+ buffer = BytesIO()
350
357
  img.save(buffer, format="PNG")
351
- # Return a new Image object with the thumbnail data
352
358
  return Image(data=buffer.getvalue(), format="png")
353
-
354
- @mcp.tool()
355
- def load_image_from_disk(path: str) -> Image:
356
- """Loads an image from the specified path."""
357
- # Handles reading file and detecting format based on extension
358
- return Image(path=path)
359
359
  ```
360
- FastMCP handles the conversion to/from the base64-encoded format required by the MCP protocol.
360
+ Return the `Image` helper class from your tool to send an image to the client. The `Image` helper class handles the conversion to/from the base64-encoded format required by the MCP protocol. It works with either a path to an image file, or a bytes object.
361
361
 
362
362
 
363
363
  ### MCP Clients
@@ -5,6 +5,10 @@ description: Understand the different ways FastMCP Clients can connect to server
5
5
  icon: link
6
6
  ---
7
7
 
8
+ import { VersionBadge } from "/snippets/version-badge.mdx"
9
+
10
+ <VersionBadge version="2.0.0" />
11
+
8
12
  The FastMCP `Client` relies on a `ClientTransport` object to handle the specifics of connecting to and communicating with an MCP server. FastMCP provides several built-in transport implementations for common connection methods.
9
13
 
10
14
  While the `Client` often infers the correct transport automatically (see [Client Overview](/clients/client#transport-inference)), you can also instantiate transports explicitly for more control.
@@ -4,6 +4,9 @@ description: "Community-contributed modules extending FastMCP"
4
4
  icon: "cubes"
5
5
  ---
6
6
 
7
+ import { VersionBadge } from "/snippets/version-badge.mdx"
8
+
9
+ <VersionBadge version="2.2.1" />
7
10
 
8
11
  FastMCP includes a `contrib` package that holds community-contributed modules. These modules extend FastMCP's functionality but aren't officially maintained by the core team.
9
12
 
@@ -14,18 +14,20 @@ FastMCP provides a powerful proxying capability that allows one FastMCP server i
14
14
 
15
15
  Proxying means setting up a FastMCP server that doesn't implement its own tools or resources directly. Instead, when it receives a request (like `tools/call` or `resources/read`), it forwards that request to a *backend* MCP server, receives the response, and then relays that response back to the original client.
16
16
 
17
+
17
18
  ```mermaid
18
19
  sequenceDiagram
19
- participant Client
20
- participant ProxyServer as FastMCP Proxy Server
21
- participant BackendServer as Backend MCP Server
22
-
23
- Client->>ProxyServer: Request (e.g., stdio)
24
- ProxyServer->>BackendServer: Request (e.g., sse)
25
- BackendServer-->>ProxyServer: Response (e.g., sse)
26
- ProxyServer-->>Client: Response (e.g., stdio)
20
+ participant ClientApp as Your Client (e.g., Claude Desktop)
21
+ participant FastMCPProxy as FastMCP Proxy Server
22
+ participant BackendServer as Backend MCP Server (e.g., remote SSE)
23
+
24
+ ClientApp->>FastMCPProxy: MCP Request (e.g. stdio)
25
+ Note over FastMCPProxy, BackendServer: Proxy forwards the request
26
+ FastMCPProxy->>BackendServer: MCP Request (e.g. sse)
27
+ BackendServer-->>FastMCPProxy: MCP Response (e.g. sse)
28
+ Note over ClientApp, FastMCPProxy: Proxy relays the response
29
+ FastMCPProxy-->>ClientApp: MCP Response (e.g. stdio)
27
30
  ```
28
-
29
31
  ### Use Cases
30
32
 
31
33
  - **Transport Bridging**: Expose a server running on one transport (e.g., a remote SSE server) via a different transport (e.g., local Stdio for Claude Desktop).
@@ -5,6 +5,8 @@ description: Learn about the core FastMCP server class and how to run it.
5
5
  icon: server
6
6
  ---
7
7
 
8
+ import { VersionBadge } from "/snippets/version-badge.mdx"
9
+
8
10
  The central piece of a FastMCP application is the `FastMCP` server class. This class acts as the main container for your application's tools, resources, and prompts, and manages communication with MCP clients.
9
11
 
10
12
  ## Creating a Server
@@ -225,6 +227,8 @@ The CLI can dynamically find and run FastMCP server objects in your files, but i
225
227
 
226
228
  ## Composing Servers
227
229
 
230
+ <VersionBadge version="2.2.0" />
231
+
228
232
  FastMCP supports composing multiple servers together using `import_server` (static copy) and `mount` (live link). This allows you to organize large applications into modular components or reuse existing servers.
229
233
 
230
234
  See the [Server Composition](/patterns/composition) guide for full details, best practices, and examples.
@@ -246,6 +250,8 @@ main.mount("sub", sub)
246
250
 
247
251
  ## Proxying Servers
248
252
 
253
+ <VersionBadge version="2.0.0" />
254
+
249
255
  FastMCP can act as a proxy for any MCP server (local or remote) using `FastMCP.from_client`, letting you bridge transports or add a frontend to existing servers. For example, you can expose a remote SSE server locally via stdio, or vice versa.
250
256
 
251
257
  See the [Proxying Servers](/patterns/proxy) guide for details and advanced usage.
@@ -5,6 +5,8 @@ description: Create reusable, parameterized prompt templates for MCP clients.
5
5
  icon: message-lines
6
6
  ---
7
7
 
8
+ import { VersionBadge } from "/snippets/version-badge.mdx"
9
+
8
10
  Prompts are reusable message templates that help LLMs generate structured, purposeful responses. FastMCP simplifies defining these templates, primarily using the `@mcp.prompt` decorator.
9
11
 
10
12
  ## What Are Prompts?
@@ -201,6 +203,8 @@ Refer to the [Context documentation](/servers/context) for more details on these
201
203
 
202
204
  ### Duplicate Prompts
203
205
 
206
+ <VersionBadge version="2.1.0" />
207
+
204
208
  You can configure how the FastMCP server handles attempts to register multiple prompts with the same name. Use the `on_duplicate_prompts` setting during `FastMCP` initialization.
205
209
 
206
210
  ```python
@@ -5,6 +5,8 @@ description: Expose data sources and dynamic content generators to your MCP clie
5
5
  icon: database
6
6
  ---
7
7
 
8
+ import { VersionBadge } from "/snippets/version-badge.mdx"
9
+
8
10
  Resources represent data or files that an MCP client can read, and resource templates extend this concept by allowing clients to request dynamically generated resources based on parameters passed in the URI.
9
11
 
10
12
  FastMCP simplifies defining both static and dynamic resources, primarily using the `@mcp.resource` decorator.
@@ -183,6 +185,8 @@ Use these when the content is static or sourced directly from a file/URL, bypass
183
185
 
184
186
  #### Custom Resource Keys
185
187
 
188
+ <VersionBadge version="2.2.0" />
189
+
186
190
  When adding resources directly with `mcp.add_resource()`, you can optionally provide a custom storage key:
187
191
 
188
192
  ```python
@@ -201,6 +205,10 @@ Note that this parameter is only available when using `add_resource()` directly
201
205
 
202
206
  Resource Templates allow clients to request resources whose content depends on parameters embedded in the URI. Define a template using the **same `@mcp.resource` decorator**, but include `{parameter_name}` placeholders in the URI string and add corresponding arguments to your function signature.
203
207
 
208
+ Resource templates generate a new resource for each unique set of parameters, which means that resources can be dynamically created on-demand. For example, if the resource template `"user://profile/{name}"` is registered, MCP clients could request `"user://profile/ford"` or `"user://profile/marvin"` to retrieve either of those two user profiles as resources, without having to register each resource individually.
209
+
210
+ Here is a complete example that shows how to define two resource templates:
211
+
204
212
  ```python
205
213
  from fastmcp import FastMCP
206
214
 
@@ -233,11 +241,68 @@ def get_repo_info(owner: str, repo: str) -> dict:
233
241
  }
234
242
  ```
235
243
 
236
- With these templates defined, clients can request:
244
+ With these two templates defined, clients can request a variety of resources:
237
245
  - `weather://london/current` → Returns weather for London
238
- - `repos://fastmcp/docs/info` → Returns info about the fastmcp/docs repository
246
+ - `weather://paris/current` → Returns weather for Paris
247
+ - `repos://jlowin/fastmcp/info` → Returns info about the jlowin/fastmcp repository
248
+ - `repos://prefecthq/prefect/info` → Returns info about the prefecthq/prefect repository
249
+
250
+ ### Wildcard Parameters
251
+
252
+ <VersionBadge version="2.2.3" />
253
+
254
+ <Warning>
255
+ Please note: the Model Context Protocol URI standard follows RFC 6570, which does not include support for wildcard parameters. FastMCP extends the template syntax to support wildcards (`{param*}`), and because template matching happens entirely in the FastMCP server, it is not expected that these wildcards will cause compatibility issues with other MCP implementations. However, this can not be guaranteed.
256
+ </Warning>
257
+
258
+ Resource templates support wildcard parameters that can match multiple path segments. While standard parameters (`{param}`) only match a single path segment and don't cross "/" boundaries, wildcard parameters (`{param*}`) can capture multiple segments including slashes. Wildcards capture all subsequent path segments *up until* the defined part of the URI template (whether literal or another parameter). This allows you to have multiple wildcard parameters in a single URI template.
259
+
260
+ ```python {15, 23}
261
+ from fastmcp import FastMCP
262
+
263
+ mcp = FastMCP(name="DataServer")
264
+
265
+
266
+ # Standard parameter only matches one segment
267
+ @mcp.resource("files://{filename}")
268
+ def get_file(filename: str) -> str:
269
+ """Retrieves a file by name."""
270
+ # Will only match files://<single-segment>
271
+ return f"File content for: {filename}"
239
272
 
240
- ### Parameters and Default Values
273
+
274
+ # Wildcard parameter can match multiple segments
275
+ @mcp.resource("path://{filepath*}")
276
+ def get_path_content(filepath: str) -> str:
277
+ """Retrieves content at a specific path."""
278
+ # Can match path://docs/server/resources.mdx
279
+ return f"Content at path: {filepath}"
280
+
281
+
282
+ # Mixing standard and wildcard parameters
283
+ @mcp.resource("repo://{owner}/{path*}/template.py")
284
+ def get_template_file(owner: str, path: str) -> dict:
285
+ """Retrieves a file from a specific repository and path, but
286
+ only if the resource ends with `template.py`"""
287
+ # Can match repo://jlowin/fastmcp/src/resources/template.py
288
+ return {
289
+ "owner": owner,
290
+ "path": path + "/template.py",
291
+ "content": f"File at {path}/template.py in {owner}'s repository"
292
+ }
293
+ ```
294
+
295
+ Wildcard parameters are useful when:
296
+
297
+ - Working with file paths or hierarchical data
298
+ - Creating APIs that need to capture variable-length path segments
299
+ - Building URL-like patterns similar to REST APIs
300
+
301
+ Note that like regular parameters, each wildcard parameter must still be a named parameter in your function signature, and all required function parameters must appear in the URI template.
302
+
303
+ ### Default Values
304
+
305
+ <VersionBadge version="2.2.0" />
241
306
 
242
307
  When creating resource templates, FastMCP enforces two rules for the relationship between URI template parameters and function parameters:
243
308
 
@@ -315,6 +380,8 @@ Templates provide a powerful way to expose parameterized data access points foll
315
380
 
316
381
  ### Custom Template Keys
317
382
 
383
+ <VersionBadge version="2.2.0" />
384
+
318
385
  Similar to resources, you can provide custom keys when directly adding templates:
319
386
 
320
387
  ```python
@@ -337,6 +404,8 @@ This allows accessing the same template implementation through different URI pat
337
404
 
338
405
  ### Duplicate Resources
339
406
 
407
+ <VersionBadge version="2.1.0" />
408
+
340
409
  You can configure how the FastMCP server handles attempts to register multiple resources or templates with the same URI. Use the `on_duplicate_resources` setting during `FastMCP` initialization.
341
410
 
342
411
  ```python
@@ -209,13 +209,18 @@ FastMCP automatically converts the value returned by your function into the appr
209
209
  - **`str`**: Sent as `TextContent`.
210
210
  - **`dict`, `list`, Pydantic `BaseModel`**: Serialized to a JSON string and sent as `TextContent`.
211
211
  - **`bytes`**: Base64 encoded and sent as `BlobResourceContents` (often within an `EmbeddedResource`).
212
- - **`fastmcp.utilities.types.Image`**: A helper class to easily return image data. Sent as `ImageContent`.
212
+ - **`fastmcp.Image`**: A helper class for easily returning image data. Sent as `ImageContent`.
213
213
  - **`None`**: Results in an empty response (no content is sent back to the client).
214
214
 
215
215
  ```python
216
- from fastmcp.utilities.types import Image
217
- from PIL import Image as PILImage
216
+ from fastmcp import FastMCP, Image
218
217
  import io
218
+ try:
219
+ from PIL import Image as PILImage
220
+ except ImportError:
221
+ raise ImportError("Please install the `pillow` library to run this example.")
222
+
223
+ mcp = FastMCP("Image Demo")
219
224
 
220
225
  @mcp.tool()
221
226
  def generate_image(width: int, height: int, color: str) -> Image:
@@ -306,6 +311,8 @@ For full documentation on the Context object and all its capabilities, see the [
306
311
 
307
312
  ### Duplicate Tools
308
313
 
314
+ <VersionBadge version="2.1.0" />
315
+
309
316
  You can control how the FastMCP server behaves if you try to register multiple tools with the same name. This is configured using the `on_duplicate_tools` argument when creating the `FastMCP` instance.
310
317
 
311
318
  ```python
@@ -0,0 +1,13 @@
1
+ export const VersionBadge = ({ version }) => {
2
+ return (
3
+ <code className="version-badge-container">
4
+ <div className="version-badge">
5
+ <span className="version-badge-label">New in version:</span>&nbsp;
6
+ <span className="version-badge-version">{version}</span>
7
+ </div>
8
+ </code>
9
+
10
+
11
+
12
+ );
13
+ };
@@ -14,16 +14,18 @@ h6 code:not(pre code) {
14
14
 
15
15
  /* Version badge -- display a badge with the current version of the documentation */
16
16
  .version-badge {
17
- display: inline-flex;
17
+ display: inline-block;
18
18
  align-items: center;
19
19
  gap: 0.3em;
20
- padding: 0.32em 1em;
21
- font-size: 0.92em;
22
- font-weight: 600;
23
- letter-spacing: 0.01em;
24
- color: #7417e5;
25
- background: #f3e8ff;
26
- border: 1.5px solid #c084fc;
20
+ padding: 0.2em 0.8em;
21
+ font-size: 1.1em;
22
+ font-weight: 400;
23
+
24
+ font-family: "Inter", sans-serif;
25
+ letter-spacing: 0.025em;
26
+ color: #ff5400;
27
+ background: #ffeee6;
28
+ border: 1px solid rgb(255, 84, 0, 0.5);
27
29
  border-radius: 6px;
28
30
  box-shadow: none;
29
31
  vertical-align: middle;
@@ -31,6 +33,11 @@ h6 code:not(pre code) {
31
33
  transition: box-shadow 0.2s, transform 0.15s;
32
34
  }
33
35
 
36
+ .version-badge-container {
37
+ margin: 0;
38
+ padding: 0;
39
+ }
40
+
34
41
  .version-badge:hover {
35
42
  box-shadow: 0 2px 8px 0 rgba(160, 132, 252, 0.1);
36
43
  transform: translateY(-1px) scale(1.03);
@@ -41,13 +48,3 @@ h6 code:not(pre code) {
41
48
  background: #312e81;
42
49
  border: 1.5px solid #a78bfa;
43
50
  }
44
-
45
- .badge-emoji {
46
- font-size: 1.15em;
47
- line-height: 1;
48
- text-shadow: 0 1px 2px #fff, 0 0px 2px #c084fc;
49
- }
50
-
51
- .dark .badge-emoji {
52
- text-shadow: 0 1px 2px #312e81, 0 0px 2px #a78bfa;
53
- }
@@ -223,6 +223,27 @@ def dev(
223
223
  help="Additional packages to install",
224
224
  ),
225
225
  ] = [],
226
+ inspector_version: Annotated[
227
+ str | None,
228
+ typer.Option(
229
+ "--inspector-version",
230
+ help="Version of the MCP Inspector to use",
231
+ ),
232
+ ] = None,
233
+ ui_port: Annotated[
234
+ int | None,
235
+ typer.Option(
236
+ "--ui-port",
237
+ help="Port for the MCP Inspector UI",
238
+ ),
239
+ ] = None,
240
+ server_port: Annotated[
241
+ int | None,
242
+ typer.Option(
243
+ "--server-port",
244
+ help="Port for the MCP Inspector Proxy server",
245
+ ),
246
+ ] = None,
226
247
  ) -> None:
227
248
  """Run a MCP server with the MCP Inspector."""
228
249
  file, server_object = _parse_file_path(file_spec)
@@ -234,6 +255,8 @@ def dev(
234
255
  "server_object": server_object,
235
256
  "with_editable": str(with_editable) if with_editable else None,
236
257
  "with_packages": with_packages,
258
+ "ui_port": ui_port,
259
+ "server_port": server_port,
237
260
  },
238
261
  )
239
262
 
@@ -243,7 +266,11 @@ def dev(
243
266
  if hasattr(server, "dependencies"):
244
267
  with_packages = list(set(with_packages + server.dependencies))
245
268
 
246
- uv_cmd = _build_uv_command(file_spec, with_editable, with_packages)
269
+ env_vars = {}
270
+ if ui_port:
271
+ env_vars["CLIENT_PORT"] = str(ui_port)
272
+ if server_port:
273
+ env_vars["SERVER_PORT"] = str(server_port)
247
274
 
248
275
  # Get the correct npx command
249
276
  npx_cmd = _get_npx_command()
@@ -254,13 +281,19 @@ def dev(
254
281
  )
255
282
  sys.exit(1)
256
283
 
284
+ inspector_cmd = "@modelcontextprotocol/inspector"
285
+ if inspector_version:
286
+ inspector_cmd += f"@{inspector_version}"
287
+
288
+ uv_cmd = _build_uv_command(file_spec, with_editable, with_packages)
289
+
257
290
  # Run the MCP Inspector command with shell=True on Windows
258
291
  shell = sys.platform == "win32"
259
292
  process = subprocess.run(
260
- [npx_cmd, "@modelcontextprotocol/inspector"] + uv_cmd,
293
+ [npx_cmd, inspector_cmd] + uv_cmd,
261
294
  check=True,
262
295
  shell=shell,
263
- env=dict(os.environ.items()), # Convert to list of tuples for env update
296
+ env=dict(os.environ.items()) | env_vars,
264
297
  )
265
298
  sys.exit(process.returncode)
266
299
  except subprocess.CalledProcessError as e:
@@ -24,13 +24,16 @@ from fastmcp.utilities.types import _convert_set_defaults
24
24
 
25
25
 
26
26
  def build_regex(template: str) -> re.Pattern:
27
- # Escape all non-brace characters, then restore {var} placeholders
28
27
  parts = re.split(r"(\{[^}]+\})", template)
29
28
  pattern = ""
30
29
  for part in parts:
31
30
  if part.startswith("{") and part.endswith("}"):
32
31
  name = part[1:-1]
33
- pattern += f"(?P<{name}>[^/]+)"
32
+ if name.endswith("*"):
33
+ name = name[:-1]
34
+ pattern += f"(?P<{name}>.+)"
35
+ else:
36
+ pattern += f"(?P<{name}>[^/]+)"
34
37
  else:
35
38
  pattern += re.escape(part)
36
39
  return re.compile(f"^{pattern}$")
@@ -92,7 +95,7 @@ class ResourceTemplate(BaseModel):
92
95
  raise ValueError("You must provide a name for lambda functions")
93
96
 
94
97
  # Validate that URI params match function params
95
- uri_params = set(re.findall(r"{(\w+)}", uri_template))
98
+ uri_params = set(re.findall(r"{(\w+)(?:\*)?}", uri_template))
96
99
  if not uri_params:
97
100
  raise ValueError("URI template must contain at least one parameter")
98
101
 
@@ -257,7 +257,7 @@ class OpenAPIResource(Resource):
257
257
  self._client = client
258
258
  self._route = route
259
259
 
260
- async def read(self) -> str:
260
+ async def read(self) -> str | bytes:
261
261
  """Fetch the resource data by making an HTTP request."""
262
262
  try:
263
263
  # Extract path parameters from the URI if present
@@ -297,15 +297,16 @@ class OpenAPIResource(Resource):
297
297
  # Raise for 4xx/5xx responses
298
298
  response.raise_for_status()
299
299
 
300
- # Return response content based on mime type
301
- if self.mime_type == "application/json":
302
- try:
303
- return response.json()
304
- except (json.JSONDecodeError, ValueError):
305
- # Fallback to returning the text
306
- return response.text
307
- else:
300
+ # Determine content type and return appropriate format
301
+ content_type = response.headers.get("content-type", "").lower()
302
+
303
+ if "application/json" in content_type:
304
+ result = response.json()
305
+ return json.dumps(result)
306
+ elif any(ct in content_type for ct in ["text/", "application/xml"]):
308
307
  return response.text
308
+ else:
309
+ return response.content
309
310
 
310
311
  except httpx.HTTPStatusError as e:
311
312
  # Handle HTTP errors (4xx, 5xx)
@@ -343,59 +344,13 @@ class OpenAPIResourceTemplate(ResourceTemplate):
343
344
  uri_template=uri_template,
344
345
  name=name,
345
346
  description=description,
346
- fn=self._create_resource_fn,
347
+ fn=lambda **kwargs: None,
347
348
  parameters=parameters,
348
349
  tags=tags,
349
350
  )
350
351
  self._client = client
351
352
  self._route = route
352
353
 
353
- async def _create_resource_fn(self, **kwargs):
354
- """Create a resource with parameters."""
355
- # Prepare the path with parameters
356
- path = self._route.path
357
- for param_name, param_value in kwargs.items():
358
- path = path.replace(f"{{{param_name}}}", str(param_value))
359
-
360
- try:
361
- response = await self._client.request(
362
- method=self._route.method,
363
- url=path,
364
- timeout=30.0, # Default timeout
365
- )
366
-
367
- # Raise for 4xx/5xx responses
368
- response.raise_for_status()
369
-
370
- # Determine the mime type from the response
371
- content_type = response.headers.get("content-type", "application/json")
372
- mime_type = content_type.split(";")[0].strip()
373
-
374
- # Return the appropriate data
375
- if mime_type == "application/json":
376
- try:
377
- return response.json()
378
- except (json.JSONDecodeError, ValueError):
379
- return response.text
380
- else:
381
- return response.text
382
-
383
- except httpx.HTTPStatusError as e:
384
- error_message = (
385
- f"HTTP error {e.response.status_code}: {e.response.reason_phrase}"
386
- )
387
- try:
388
- error_data = e.response.json()
389
- error_message += f" - {error_data}"
390
- except (json.JSONDecodeError, ValueError):
391
- if e.response.text:
392
- error_message += f" - {e.response.text}"
393
-
394
- raise ValueError(error_message)
395
-
396
- except httpx.RequestError as e:
397
- raise ValueError(f"Request error: {str(e)}")
398
-
399
354
  async def create_resource(self, uri: str, params: dict[str, Any]) -> Resource:
400
355
  """Create a resource with the given parameters."""
401
356
  # Generate a URI for this resource instance
@@ -409,9 +364,8 @@ class OpenAPIResourceTemplate(ResourceTemplate):
409
364
  route=self._route,
410
365
  uri=uri,
411
366
  name=f"{self.name}-{'-'.join(uri_parts)}",
412
- description=self.description
413
- or f"Resource for {self._route.path}", # Provide default if None
414
- mime_type="application/json", # Default, will be updated when read
367
+ description=self.description or f"Resource for {self._route.path}",
368
+ mime_type="application/json",
415
369
  tags=set(self._route.tags or []),
416
370
  )
417
371
 
@@ -76,7 +76,12 @@ class Tool(BaseModel):
76
76
  fn_callable,
77
77
  skip_names=[context_kwarg] if context_kwarg is not None else [],
78
78
  )
79
- parameters = func_arg_metadata.arg_model.model_json_schema()
79
+ try:
80
+ parameters = func_arg_metadata.arg_model.model_json_schema()
81
+ except Exception as e:
82
+ raise TypeError(
83
+ f'Unable to parse parameters for function "{fn.__name__}": {e}'
84
+ ) from e
80
85
 
81
86
  return cls(
82
87
  fn=fn_callable,