fastmcp 2.2.0__tar.gz → 2.2.2__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.
- fastmcp-2.2.2/.github/ISSUE_TEMPLATE/bug.yml +63 -0
- fastmcp-2.2.2/.github/ISSUE_TEMPLATE/config.yml +8 -0
- fastmcp-2.2.2/.github/ISSUE_TEMPLATE/enhancement.yml +38 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/.github/workflows/run-tests.yml +0 -1
- {fastmcp-2.2.0 → fastmcp-2.2.2}/.pre-commit-config.yaml +0 -1
- {fastmcp-2.2.0 → fastmcp-2.2.2}/PKG-INFO +9 -2
- {fastmcp-2.2.0 → fastmcp-2.2.2}/README.md +7 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/clients/client.mdx +9 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/docs.json +2 -1
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/getting-started/quickstart.mdx +3 -3
- fastmcp-2.2.2/docs/patterns/contrib.mdx +42 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/pyproject.toml +1 -1
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/cli/cli.py +1 -1
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/client/client.py +14 -21
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/client/transports.py +2 -1
- fastmcp-2.2.2/src/fastmcp/contrib/README.md +19 -0
- fastmcp-2.2.2/src/fastmcp/contrib/bulk_tool_caller/README.md +35 -0
- fastmcp-2.2.2/src/fastmcp/contrib/bulk_tool_caller/__init__.py +3 -0
- fastmcp-2.2.2/src/fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py +135 -0
- fastmcp-2.2.2/src/fastmcp/contrib/bulk_tool_caller/example.py +17 -0
- fastmcp-2.2.2/src/fastmcp/contrib/mcp_mixin/README.md +39 -0
- fastmcp-2.2.2/src/fastmcp/contrib/mcp_mixin/__init__.py +8 -0
- fastmcp-2.2.2/src/fastmcp/contrib/mcp_mixin/example.py +52 -0
- fastmcp-2.2.2/src/fastmcp/contrib/mcp_mixin/mcp_mixin.py +208 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/server/proxy.py +34 -4
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/server/server.py +3 -1
- fastmcp-2.2.2/tests/cli/test_run.py +22 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/client/test_client.py +30 -0
- fastmcp-2.2.2/tests/contrib/__init__.py +1 -0
- fastmcp-2.2.2/tests/contrib/test_bulk_tool_caller.py +221 -0
- fastmcp-2.2.2/tests/contrib/test_mcp_mixin.py +255 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/uv.lock +5 -16
- fastmcp-2.2.0/tests/cli/test_run.py +0 -77
- {fastmcp-2.2.0 → fastmcp-2.2.2}/.cursor/rules/core-mcp-objects.mdc +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/.github/release.yml +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/.github/workflows/publish.yml +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/.github/workflows/run-static.yml +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/.gitignore +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/LICENSE +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/Windows_Notes.md +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/assets/demo-inspector.png +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/clients/transports.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/getting-started/installation.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/getting-started/welcome.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/patterns/composition.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/patterns/decorating-methods.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/patterns/fastapi.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/patterns/openapi.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/patterns/proxy.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/servers/context.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/servers/fastmcp.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/servers/prompts.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/servers/resources.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/servers/tools.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/snippets/version-badge.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/docs/style.css +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/complex_inputs.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/desktop.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/echo.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/memory.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/mount_example.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/readme-quickstart.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/sampling.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/screenshot.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/simple_echo.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/smart_home/README.md +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/smart_home/pyproject.toml +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/smart_home/src/smart_home/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/smart_home/src/smart_home/__main__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/smart_home/src/smart_home/hub.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/smart_home/src/smart_home/lights/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/smart_home/src/smart_home/lights/hue_utils.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/smart_home/src/smart_home/lights/server.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/smart_home/src/smart_home/py.typed +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/smart_home/src/smart_home/settings.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/smart_home/uv.lock +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/examples/text_me.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/justfile +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/cli/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/cli/claude.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/client/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/client/base.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/client/roots.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/client/sampling.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/exceptions.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/prompts/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/prompts/prompt.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/prompts/prompt_manager.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/py.typed +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/resources/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/resources/resource.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/resources/resource_manager.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/resources/template.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/resources/types.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/server/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/server/context.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/server/openapi.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/settings.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/tools/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/tools/tool.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/tools/tool_manager.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/utilities/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/utilities/decorators.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/utilities/func_metadata.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/utilities/logging.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/utilities/openapi.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/src/fastmcp/utilities/types.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/client/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/client/test_roots.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/client/test_sampling.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/conftest.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/prompts/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/prompts/test_base.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/prompts/test_prompt_manager.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/resources/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/resources/test_file_resources.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/resources/test_function_resources.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/resources/test_resource_manager.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/resources/test_resource_template.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/resources/test_resources.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/server/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/server/test_file_server.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/server/test_import_server.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/server/test_lifespan.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/server/test_mount.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/server/test_openapi.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/server/test_proxy.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/server/test_run_server.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/server/test_server.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/test_servers/fastmcp_server.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/test_servers/sse.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/test_servers/stdio.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/tools/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/tools/test_tool_manager.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/utilities/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/utilities/openapi/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/utilities/openapi/conftest.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/utilities/openapi/test_openapi.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/utilities/openapi/test_openapi_advanced.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/utilities/openapi/test_openapi_fastapi.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/utilities/test_decorated_function.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/utilities/test_func_metadata.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.2}/tests/utilities/test_logging.py +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: 🐛 Bug Report
|
|
2
|
+
description: Report a bug or unexpected behavior in FastMCP
|
|
3
|
+
labels: [bug, pending]
|
|
4
|
+
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: Thank you for contributing to FastMCP! 🙏
|
|
9
|
+
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: description
|
|
12
|
+
attributes:
|
|
13
|
+
label: Description
|
|
14
|
+
description: |
|
|
15
|
+
Please explain what you're experiencing and what you would expect to happen instead.
|
|
16
|
+
|
|
17
|
+
Provide as much detail as possible to help us understand and solve your problem quickly.
|
|
18
|
+
validations:
|
|
19
|
+
required: true
|
|
20
|
+
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: example
|
|
23
|
+
attributes:
|
|
24
|
+
label: Example Code
|
|
25
|
+
description: >
|
|
26
|
+
If applicable, please provide a self-contained,
|
|
27
|
+
[minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example)
|
|
28
|
+
demonstrating the bug.
|
|
29
|
+
|
|
30
|
+
placeholder: |
|
|
31
|
+
from fastmcp import FastMCP
|
|
32
|
+
|
|
33
|
+
...
|
|
34
|
+
render: Python
|
|
35
|
+
|
|
36
|
+
- type: textarea
|
|
37
|
+
id: version
|
|
38
|
+
attributes:
|
|
39
|
+
label: Version Information
|
|
40
|
+
description: |
|
|
41
|
+
Please provide information about your FastMCP version, MCP version, Python version, and OS.
|
|
42
|
+
|
|
43
|
+
To get this information, run the following command in your terminal and paste the output below:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
fastmcp version
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
If there is other information that would be helpful, please include it as well.
|
|
50
|
+
render: Text
|
|
51
|
+
validations:
|
|
52
|
+
required: true
|
|
53
|
+
|
|
54
|
+
- type: textarea
|
|
55
|
+
id: additional_context
|
|
56
|
+
attributes:
|
|
57
|
+
label: Additional Context
|
|
58
|
+
description: |
|
|
59
|
+
Add any other context about the problem here. This could include:
|
|
60
|
+
- The full error message and traceback (if applicable)
|
|
61
|
+
- Information about your environment (e.g., virtual environment, installed packages)
|
|
62
|
+
- Steps to reproduce the issue
|
|
63
|
+
- Any recent changes in your code or setup that might be relevant
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: FastMCP Documentation
|
|
4
|
+
url: https://gofastmcp.com
|
|
5
|
+
about: Please review the documentation before opening an issue.
|
|
6
|
+
- name: MCP Python SDK
|
|
7
|
+
url: https://github.com/modelcontextprotocol/python-sdk/issues
|
|
8
|
+
about: Issues related to the low-level MCP Python SDK, including the FastMCP 1.0 module that is included in the `mcp` package, should be filed on the official MCP repository.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: 💡 Enhancement Request
|
|
2
|
+
description: Suggest an idea or improvement for FastMCP
|
|
3
|
+
labels: [enhancement, pending]
|
|
4
|
+
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: Thank you for contributing to FastMCP! We value your ideas for improving the framework. 💡
|
|
9
|
+
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: description
|
|
12
|
+
attributes:
|
|
13
|
+
label: Enhancement Description
|
|
14
|
+
description: |
|
|
15
|
+
Please describe the enhancement you'd like to see in FastMCP.
|
|
16
|
+
|
|
17
|
+
- What problem would this solve?
|
|
18
|
+
- How would this improve your workflow or experience with FastMCP?
|
|
19
|
+
- Are there any alternative solutions you've considered?
|
|
20
|
+
validations:
|
|
21
|
+
required: true
|
|
22
|
+
|
|
23
|
+
- type: textarea
|
|
24
|
+
id: use_case
|
|
25
|
+
attributes:
|
|
26
|
+
label: Use Case
|
|
27
|
+
description: |
|
|
28
|
+
Describe a specific use case or scenario where this enhancement would be beneficial.
|
|
29
|
+
If possible, provide an example of how you envision using this feature.
|
|
30
|
+
|
|
31
|
+
- type: textarea
|
|
32
|
+
id: example
|
|
33
|
+
attributes:
|
|
34
|
+
label: Proposed Implementation
|
|
35
|
+
description: >
|
|
36
|
+
If you have ideas about how this enhancement could be implemented,
|
|
37
|
+
please share them here. Code snippets, pseudocode, or general approaches are welcome.
|
|
38
|
+
render: Python
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastmcp
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
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
|
|
@@ -17,11 +17,11 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
17
17
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
18
|
Classifier: Typing :: Typed
|
|
19
19
|
Requires-Python: >=3.10
|
|
20
|
-
Requires-Dist: dotenv>=0.9.9
|
|
21
20
|
Requires-Dist: exceptiongroup>=1.2.2
|
|
22
21
|
Requires-Dist: httpx>=0.28.1
|
|
23
22
|
Requires-Dist: mcp<2.0.0,>=1.6.0
|
|
24
23
|
Requires-Dist: openapi-pydantic>=0.5.1
|
|
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
27
|
Requires-Dist: websockets>=15.0.1
|
|
@@ -95,6 +95,7 @@ FastMCP handles the complex protocol details and server management, letting you
|
|
|
95
95
|
- [Proxy Servers](#proxy-servers)
|
|
96
96
|
- [Composing MCP Servers](#composing-mcp-servers)
|
|
97
97
|
- [OpenAPI \& FastAPI Generation](#openapi--fastapi-generation)
|
|
98
|
+
- [Handling `stderr`](#handling-stderr)
|
|
98
99
|
- [Running Your Server](#running-your-server)
|
|
99
100
|
- [Development Mode (Recommended for Building \& Testing)](#development-mode-recommended-for-building--testing)
|
|
100
101
|
- [Claude Desktop Integration (For Regular Use)](#claude-desktop-integration-for-regular-use)
|
|
@@ -695,6 +696,12 @@ mcp_server = FastMCP.from_openapi(openapi_spec, client=http_client)
|
|
|
695
696
|
if __name__ == "__main__":
|
|
696
697
|
mcp_server.run()
|
|
697
698
|
```
|
|
699
|
+
|
|
700
|
+
### Handling `stderr`
|
|
701
|
+
The MCP spec allows for the server to write anything it wants to `stderr`, and it
|
|
702
|
+
doesn't specify the format in any way. FastMCP will forward the server's `stderr`
|
|
703
|
+
to the client's `stderr`.
|
|
704
|
+
|
|
698
705
|
## Running Your Server
|
|
699
706
|
|
|
700
707
|
Choose the method that best suits your needs:
|
|
@@ -66,6 +66,7 @@ FastMCP handles the complex protocol details and server management, letting you
|
|
|
66
66
|
- [Proxy Servers](#proxy-servers)
|
|
67
67
|
- [Composing MCP Servers](#composing-mcp-servers)
|
|
68
68
|
- [OpenAPI \& FastAPI Generation](#openapi--fastapi-generation)
|
|
69
|
+
- [Handling `stderr`](#handling-stderr)
|
|
69
70
|
- [Running Your Server](#running-your-server)
|
|
70
71
|
- [Development Mode (Recommended for Building \& Testing)](#development-mode-recommended-for-building--testing)
|
|
71
72
|
- [Claude Desktop Integration (For Regular Use)](#claude-desktop-integration-for-regular-use)
|
|
@@ -666,6 +667,12 @@ mcp_server = FastMCP.from_openapi(openapi_spec, client=http_client)
|
|
|
666
667
|
if __name__ == "__main__":
|
|
667
668
|
mcp_server.run()
|
|
668
669
|
```
|
|
670
|
+
|
|
671
|
+
### Handling `stderr`
|
|
672
|
+
The MCP spec allows for the server to write anything it wants to `stderr`, and it
|
|
673
|
+
doesn't specify the format in any way. FastMCP will forward the server's `stderr`
|
|
674
|
+
to the client's `stderr`.
|
|
675
|
+
|
|
669
676
|
## Running Your Server
|
|
670
677
|
|
|
671
678
|
Choose the method that best suits your needs:
|
|
@@ -226,6 +226,15 @@ MCP allows servers to make requests *back* to the client for certain capabilitie
|
|
|
226
226
|
)
|
|
227
227
|
```
|
|
228
228
|
|
|
229
|
+
### Utility Methods
|
|
230
|
+
|
|
231
|
+
* **`ping()`**: Sends a ping request to the server to verify connectivity.
|
|
232
|
+
```python
|
|
233
|
+
async def check_connection():
|
|
234
|
+
async with client:
|
|
235
|
+
await client.ping()
|
|
236
|
+
print("Server is reachable")
|
|
237
|
+
```
|
|
229
238
|
|
|
230
239
|
### Error Handling
|
|
231
240
|
|
|
@@ -32,7 +32,7 @@ from fastmcp import FastMCP
|
|
|
32
32
|
|
|
33
33
|
mcp = FastMCP("My MCP Server")
|
|
34
34
|
|
|
35
|
-
@mcp.tool
|
|
35
|
+
@mcp.tool()
|
|
36
36
|
def greet(name: str) -> str:
|
|
37
37
|
return f"Hello, {name}!"
|
|
38
38
|
```
|
|
@@ -48,7 +48,7 @@ from fastmcp import FastMCP, Client
|
|
|
48
48
|
|
|
49
49
|
mcp = FastMCP("My MCP Server")
|
|
50
50
|
|
|
51
|
-
@mcp.tool
|
|
51
|
+
@mcp.tool()
|
|
52
52
|
def greet(name: str) -> str:
|
|
53
53
|
return f"Hello, {name}!"
|
|
54
54
|
|
|
@@ -75,7 +75,7 @@ from fastmcp import FastMCP, Client
|
|
|
75
75
|
|
|
76
76
|
mcp = FastMCP("My MCP Server")
|
|
77
77
|
|
|
78
|
-
@mcp.tool
|
|
78
|
+
@mcp.tool()
|
|
79
79
|
def greet(name: str) -> str:
|
|
80
80
|
return f"Hello, {name}!"
|
|
81
81
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Contrib Modules"
|
|
3
|
+
description: "Community-contributed modules extending FastMCP"
|
|
4
|
+
icon: "cubes"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
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
|
+
|
|
10
|
+
Contrib modules provide additional features, integrations, or patterns that complement the core FastMCP library. They offer a way for the community to share useful extensions while keeping the core library focused and maintainable.
|
|
11
|
+
|
|
12
|
+
The available modules can be viewed in the [contrib directory](https://github.com/jlowin/fastmcp/tree/main/src/contrib).
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
To use a contrib module, import it from the `fastmcp.contrib` package:
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from fastmcp.contrib import my_module
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Important Considerations
|
|
23
|
+
|
|
24
|
+
- **Stability**: Modules in `contrib` may have different testing requirements or stability guarantees compared to the core library.
|
|
25
|
+
- **Compatibility**: Changes to core FastMCP might break modules in `contrib` without explicit warnings in the main changelog.
|
|
26
|
+
- **Dependencies**: Contrib modules may have additional dependencies not required by the core library. These dependencies are typically documented in the module's README or separate requirements files.
|
|
27
|
+
|
|
28
|
+
## Contributing
|
|
29
|
+
|
|
30
|
+
We welcome contributions to the `contrib` package! If you have a module that extends FastMCP in a useful way, consider contributing it:
|
|
31
|
+
|
|
32
|
+
1. Create a new directory in `src/fastmcp/contrib/` for your module
|
|
33
|
+
3. Add proper tests for your module in `tests/contrib/`
|
|
34
|
+
2. Include comprehensive documentation in a README.md file, including usage and examples, as well as any additional dependencies or installation instructions
|
|
35
|
+
5. Submit a pull request
|
|
36
|
+
|
|
37
|
+
The ideal contrib module:
|
|
38
|
+
- Solves a specific use case or integration need
|
|
39
|
+
- Follows FastMCP coding standards
|
|
40
|
+
- Includes thorough documentation and examples
|
|
41
|
+
- Has comprehensive tests
|
|
42
|
+
- Specifies any additional dependencies
|
|
@@ -186,7 +186,7 @@ def version(ctx: Context):
|
|
|
186
186
|
"MCP version": importlib.metadata.version("mcp"),
|
|
187
187
|
"Python version": platform.python_version(),
|
|
188
188
|
"Platform": platform.platform(),
|
|
189
|
-
"FastMCP root path":
|
|
189
|
+
"FastMCP root path": Path(fastmcp.__file__).resolve().parents[1],
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
g = Table.grid(padding=(0, 1))
|
|
@@ -45,7 +45,8 @@ class Client:
|
|
|
45
45
|
):
|
|
46
46
|
self.transport = infer_transport(transport)
|
|
47
47
|
self._session: ClientSession | None = None
|
|
48
|
-
self.
|
|
48
|
+
self._session_cm: AbstractAsyncContextManager[ClientSession] | None = None
|
|
49
|
+
self._nesting_counter: int = 0
|
|
49
50
|
|
|
50
51
|
self._session_kwargs: SessionKwargs = {
|
|
51
52
|
"sampling_callback": None,
|
|
@@ -85,29 +86,21 @@ class Client:
|
|
|
85
86
|
return self._session is not None
|
|
86
87
|
|
|
87
88
|
async def __aenter__(self):
|
|
88
|
-
if self.
|
|
89
|
-
#
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
self._session = await self._session_cms[-1].__aenter__()
|
|
96
|
-
return self
|
|
97
|
-
except Exception as e:
|
|
98
|
-
# Ensure cleanup if __aenter__ fails partially
|
|
99
|
-
self._session = None
|
|
100
|
-
if self._session_cms:
|
|
101
|
-
self._session_cms.pop()
|
|
102
|
-
raise ConnectionError(
|
|
103
|
-
f"Failed to connect using {self.transport}: {e}"
|
|
104
|
-
) from e
|
|
89
|
+
if self._nesting_counter == 0:
|
|
90
|
+
# create new session
|
|
91
|
+
self._session_cm = self.transport.connect_session(**self._session_kwargs)
|
|
92
|
+
self._session = await self._session_cm.__aenter__()
|
|
93
|
+
|
|
94
|
+
self._nesting_counter += 1
|
|
95
|
+
return self
|
|
105
96
|
|
|
106
97
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
107
|
-
|
|
108
|
-
|
|
98
|
+
self._nesting_counter -= 1
|
|
99
|
+
|
|
100
|
+
if self._nesting_counter == 0 and self._session_cm is not None:
|
|
101
|
+
await self._session_cm.__aexit__(exc_type, exc_val, exc_tb)
|
|
102
|
+
self._session_cm = None
|
|
109
103
|
self._session = None
|
|
110
|
-
self._session_cms.pop()
|
|
111
104
|
|
|
112
105
|
# --- MCP Client Methods ---
|
|
113
106
|
async def ping(self) -> None:
|
|
@@ -3,6 +3,7 @@ import contextlib
|
|
|
3
3
|
import datetime
|
|
4
4
|
import os
|
|
5
5
|
import shutil
|
|
6
|
+
import sys
|
|
6
7
|
from collections.abc import AsyncIterator
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
from typing import (
|
|
@@ -185,7 +186,7 @@ class PythonStdioTransport(StdioTransport):
|
|
|
185
186
|
args: list[str] | None = None,
|
|
186
187
|
env: dict[str, str] | None = None,
|
|
187
188
|
cwd: str | None = None,
|
|
188
|
-
python_cmd: str =
|
|
189
|
+
python_cmd: str = sys.executable,
|
|
189
190
|
):
|
|
190
191
|
"""
|
|
191
192
|
Initialize a Python transport.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# FastMCP Contrib Modules
|
|
2
|
+
|
|
3
|
+
This directory holds community-contributed modules for FastMCP. These modules extend FastMCP's functionality but are not officially maintained by the core team.
|
|
4
|
+
|
|
5
|
+
**Guarantees:**
|
|
6
|
+
* Modules in `contrib` may have different testing requirements or stability guarantees compared to the core library.
|
|
7
|
+
* Changes to the core FastMCP library might break modules in `contrib` without explicit warnings in the main changelog.
|
|
8
|
+
|
|
9
|
+
Use these modules at your own discretion. Contributions are welcome, but please include tests and documentation.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
To use a contrib module, import it from the `fastmcp.contrib` package.
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from fastmcp.contrib import my_module
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Note that the contrib modules may have different dependencies than the core library, which can be noted in their respective README's or even separate requirements / dependency files.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Bulk Tool Caller
|
|
2
|
+
|
|
3
|
+
This module provides the `BulkToolCaller` class, which extends the `MCPMixin` to offer tools for performing multiple tool calls in a single request to a FastMCP server. This can be useful for optimizing interactions with the server by reducing the overhead of individual tool calls.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
To use the `BulkToolCaller`, see the example [example.py](./example.py) file. The `BulkToolCaller` can be instantiated and then registered with a FastMCP server URL. It provides methods to call multiple tools in bulk, either different tools or the same tool with different arguments.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## Provided Tools
|
|
11
|
+
|
|
12
|
+
The `BulkToolCaller` provides the following tools:
|
|
13
|
+
|
|
14
|
+
### `call_tools_bulk`
|
|
15
|
+
|
|
16
|
+
Calls multiple different tools registered on the MCP server in a single request.
|
|
17
|
+
|
|
18
|
+
- **Arguments:**
|
|
19
|
+
- `tool_calls` (list of `CallToolRequest`): A list of objects, where each object specifies the `tool` name and `arguments` for an individual tool call.
|
|
20
|
+
- `continue_on_error` (bool, optional): If `True`, continue executing subsequent tool calls even if a previous one resulted in an error. Defaults to `True`.
|
|
21
|
+
|
|
22
|
+
- **Returns:**
|
|
23
|
+
A list of `CallToolRequestResult` objects, each containing the result (`isError`, `content`) and the original `tool` name and `arguments` for each call.
|
|
24
|
+
|
|
25
|
+
### `call_tool_bulk`
|
|
26
|
+
|
|
27
|
+
Calls a single tool registered on the MCP server multiple times with different arguments in a single request.
|
|
28
|
+
|
|
29
|
+
- **Arguments:**
|
|
30
|
+
- `tool` (str): The name of the tool to call.
|
|
31
|
+
- `tool_arguments` (list of dict): A list of dictionaries, where each dictionary contains the arguments for an individual run of the tool.
|
|
32
|
+
- `continue_on_error` (bool, optional): If `True`, continue executing subsequent tool calls even if a previous one resulted in an error. Defaults to `True`.
|
|
33
|
+
|
|
34
|
+
- **Returns:**
|
|
35
|
+
A list of `CallToolRequestResult` objects, each containing the result (`isError`, `content`) and the original `tool` name and `arguments` for each call.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from mcp.types import CallToolResult
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
from fastmcp import FastMCP
|
|
7
|
+
from fastmcp.client import Client
|
|
8
|
+
from fastmcp.client.transports import FastMCPTransport
|
|
9
|
+
from fastmcp.contrib.mcp_mixin.mcp_mixin import (
|
|
10
|
+
_DEFAULT_SEPARATOR_TOOL,
|
|
11
|
+
MCPMixin,
|
|
12
|
+
mcp_tool,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CallToolRequest(BaseModel):
|
|
17
|
+
"""A class to represent a request to call a tool with specific arguments."""
|
|
18
|
+
|
|
19
|
+
tool: str = Field(description="The name of the tool to call.")
|
|
20
|
+
arguments: dict[str, Any] = Field(
|
|
21
|
+
description="A dictionary containing the arguments for the tool call."
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class CallToolRequestResult(CallToolResult):
|
|
26
|
+
"""
|
|
27
|
+
A class to represent the result of a bulk tool call.
|
|
28
|
+
It extends CallToolResult to include information about the requested tool call.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
tool: str = Field(description="The name of the tool that was called.")
|
|
32
|
+
arguments: dict[str, Any] = Field(
|
|
33
|
+
description="The arguments used for the tool call."
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def from_call_tool_result(
|
|
38
|
+
cls, result: CallToolResult, tool: str, arguments: dict[str, Any]
|
|
39
|
+
) -> "CallToolRequestResult":
|
|
40
|
+
"""
|
|
41
|
+
Create a CallToolRequestResult from a CallToolResult.
|
|
42
|
+
"""
|
|
43
|
+
return cls(
|
|
44
|
+
tool=tool,
|
|
45
|
+
arguments=arguments,
|
|
46
|
+
isError=result.isError,
|
|
47
|
+
content=result.content,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class BulkToolCaller(MCPMixin):
|
|
52
|
+
"""
|
|
53
|
+
A class to provide a "bulk tool call" tool for a FastMCP server
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def register_tools(
|
|
57
|
+
self,
|
|
58
|
+
mcp_server: "FastMCP",
|
|
59
|
+
prefix: str | None = None,
|
|
60
|
+
separator: str = _DEFAULT_SEPARATOR_TOOL,
|
|
61
|
+
) -> None:
|
|
62
|
+
"""
|
|
63
|
+
Register the tools provided by this class with the given MCP server.
|
|
64
|
+
"""
|
|
65
|
+
self.connection = FastMCPTransport(mcp_server)
|
|
66
|
+
|
|
67
|
+
super().register_tools(mcp_server=mcp_server)
|
|
68
|
+
|
|
69
|
+
@mcp_tool()
|
|
70
|
+
async def call_tools_bulk(
|
|
71
|
+
self, tool_calls: list[CallToolRequest], continue_on_error: bool = True
|
|
72
|
+
) -> list[CallToolRequestResult]:
|
|
73
|
+
"""
|
|
74
|
+
Call multiple tools registered on this MCP server in a single request. Each call can
|
|
75
|
+
be for a different tool and can include different arguments. Useful for speeding up
|
|
76
|
+
what would otherwise take several individual tool calls.
|
|
77
|
+
"""
|
|
78
|
+
results = []
|
|
79
|
+
|
|
80
|
+
for tool_call in tool_calls:
|
|
81
|
+
result = await self._call_tool(tool_call.tool, tool_call.arguments)
|
|
82
|
+
|
|
83
|
+
results.append(result)
|
|
84
|
+
|
|
85
|
+
if result.isError and not continue_on_error:
|
|
86
|
+
return results
|
|
87
|
+
|
|
88
|
+
return results
|
|
89
|
+
|
|
90
|
+
@mcp_tool()
|
|
91
|
+
async def call_tool_bulk(
|
|
92
|
+
self,
|
|
93
|
+
tool: str,
|
|
94
|
+
tool_arguments: list[dict[str, str | int | float | bool | None]],
|
|
95
|
+
continue_on_error: bool = True,
|
|
96
|
+
) -> list[CallToolRequestResult]:
|
|
97
|
+
"""
|
|
98
|
+
Call a single tool registered on this MCP server multiple times with a single request.
|
|
99
|
+
Each call can include different arguments. Useful for speeding up what would otherwise
|
|
100
|
+
take several individual tool calls.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
tool: The name of the tool to call.
|
|
104
|
+
tool_arguments: A list of dictionaries, where each dictionary contains the arguments for an individual run of the tool.
|
|
105
|
+
"""
|
|
106
|
+
results = []
|
|
107
|
+
|
|
108
|
+
for tool_call_arguments in tool_arguments:
|
|
109
|
+
result = await self._call_tool(tool, tool_call_arguments)
|
|
110
|
+
|
|
111
|
+
results.append(result)
|
|
112
|
+
|
|
113
|
+
if result.isError and not continue_on_error:
|
|
114
|
+
return results
|
|
115
|
+
|
|
116
|
+
return results
|
|
117
|
+
|
|
118
|
+
async def _call_tool(
|
|
119
|
+
self, tool: str, arguments: dict[str, Any]
|
|
120
|
+
) -> CallToolRequestResult:
|
|
121
|
+
"""
|
|
122
|
+
Helper method to call a tool with the provided arguments.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
async with Client(self.connection) as client:
|
|
126
|
+
result = await client.call_tool(
|
|
127
|
+
name=tool, arguments=arguments, _return_raw_result=True
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
return CallToolRequestResult(
|
|
131
|
+
tool=tool,
|
|
132
|
+
arguments=arguments,
|
|
133
|
+
isError=result.isError,
|
|
134
|
+
content=result.content,
|
|
135
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Sample code for FastMCP using MCPMixin."""
|
|
2
|
+
|
|
3
|
+
from fastmcp import FastMCP
|
|
4
|
+
from fastmcp.contrib.bulk_tool_caller import BulkToolCaller
|
|
5
|
+
|
|
6
|
+
mcp = FastMCP()
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@mcp.tool()
|
|
10
|
+
def echo_tool(text: str) -> str:
|
|
11
|
+
"""Echo the input text"""
|
|
12
|
+
return text
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
bulk_tool_caller = BulkToolCaller()
|
|
16
|
+
|
|
17
|
+
bulk_tool_caller.register_tools(mcp)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# MCP Mixin
|
|
2
|
+
|
|
3
|
+
This module provides the `MCPMixin` base class and associated decorators (`@mcp_tool`, `@mcp_resource`, `@mcp_prompt`).
|
|
4
|
+
|
|
5
|
+
It allows developers to easily define classes whose methods can be registered as tools, resources, or prompts with a `FastMCP` server instance using the `register_all()`, `register_tools()`, `register_resources()`, or `register_prompts()` methods provided by the mixin.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
Inherit from `MCPMixin` and use the decorators on the methods you want to register.
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
from fastmcp import FastMCP
|
|
13
|
+
from fastmcp.contrib.mcp_mixin import MCPMixin, mcp_tool, mcp_resource
|
|
14
|
+
|
|
15
|
+
class MyComponent(MCPMixin):
|
|
16
|
+
@mcp_tool(name="my_tool", description="Does something cool.")
|
|
17
|
+
def tool_method(self):
|
|
18
|
+
return "Tool executed!"
|
|
19
|
+
|
|
20
|
+
@mcp_resource(uri="component://data")
|
|
21
|
+
def resource_method(self):
|
|
22
|
+
return {"data": "some data"}
|
|
23
|
+
|
|
24
|
+
mcp_server = FastMCP()
|
|
25
|
+
component = MyComponent()
|
|
26
|
+
|
|
27
|
+
# Register all decorated methods with a prefix
|
|
28
|
+
# Useful if you will have multiple instantiated objects of the same class
|
|
29
|
+
# and want to avoid name collisions.
|
|
30
|
+
component.register_all(mcp_server, prefix="my_comp")
|
|
31
|
+
|
|
32
|
+
# Register without a prefix
|
|
33
|
+
# component.register_all(mcp_server)
|
|
34
|
+
|
|
35
|
+
# Now 'my_comp_my_tool' tool and 'my_comp+component://data' resource are registered (if prefix used)
|
|
36
|
+
# Or 'my_tool' and 'component://data' are registered (if no prefix used)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The `prefix` argument in registration methods is optional. If omitted, methods are registered with their original decorated names/URIs. Individual separators (`tools_separator`, `resources_separator`, `prompts_separator`) can also be provided to `register_all` to change the separator for specific types.
|