fastmcp 2.2.0__tar.gz → 2.2.1__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.1/.github/ISSUE_TEMPLATE/bug.yml +63 -0
- fastmcp-2.2.1/.github/ISSUE_TEMPLATE/config.yml +8 -0
- fastmcp-2.2.1/.github/ISSUE_TEMPLATE/enhancement.yml +38 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/.github/workflows/run-tests.yml +0 -1
- {fastmcp-2.2.0 → fastmcp-2.2.1}/.pre-commit-config.yaml +0 -1
- {fastmcp-2.2.0 → fastmcp-2.2.1}/PKG-INFO +9 -2
- {fastmcp-2.2.0 → fastmcp-2.2.1}/README.md +7 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/getting-started/quickstart.mdx +3 -3
- {fastmcp-2.2.0 → fastmcp-2.2.1}/pyproject.toml +1 -1
- fastmcp-2.2.1/src/contrib/README.md +9 -0
- fastmcp-2.2.1/src/contrib/bulk_tool_caller/README.md +35 -0
- fastmcp-2.2.1/src/contrib/bulk_tool_caller/__init__.py +3 -0
- fastmcp-2.2.1/src/contrib/bulk_tool_caller/bulk_tool_caller.py +131 -0
- fastmcp-2.2.1/src/contrib/bulk_tool_caller/example.py +17 -0
- fastmcp-2.2.1/src/contrib/mcp_mixin/README.md +39 -0
- fastmcp-2.2.1/src/contrib/mcp_mixin/__init__.py +8 -0
- fastmcp-2.2.1/src/contrib/mcp_mixin/example.py +52 -0
- fastmcp-2.2.1/src/contrib/mcp_mixin/mcp_mixin.py +208 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/server/server.py +3 -1
- fastmcp-2.2.1/tests/cli/test_run.py +22 -0
- fastmcp-2.2.1/tests/contrib/__init__.py +1 -0
- fastmcp-2.2.1/tests/contrib/test_bulk_tool_caller.py +221 -0
- fastmcp-2.2.1/tests/contrib/test_mcp_mixin.py +255 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/uv.lock +5 -16
- fastmcp-2.2.0/tests/cli/test_run.py +0 -77
- {fastmcp-2.2.0 → fastmcp-2.2.1}/.cursor/rules/core-mcp-objects.mdc +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/.github/release.yml +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/.github/workflows/publish.yml +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/.github/workflows/run-static.yml +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/.gitignore +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/LICENSE +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/Windows_Notes.md +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/assets/demo-inspector.png +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/clients/client.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/clients/transports.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/docs.json +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/getting-started/installation.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/getting-started/welcome.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/patterns/composition.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/patterns/decorating-methods.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/patterns/fastapi.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/patterns/openapi.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/patterns/proxy.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/servers/context.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/servers/fastmcp.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/servers/prompts.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/servers/resources.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/servers/tools.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/snippets/version-badge.mdx +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/docs/style.css +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/complex_inputs.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/desktop.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/echo.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/memory.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/mount_example.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/readme-quickstart.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/sampling.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/screenshot.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/simple_echo.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/smart_home/README.md +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/smart_home/pyproject.toml +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/smart_home/src/smart_home/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/smart_home/src/smart_home/__main__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/smart_home/src/smart_home/hub.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/smart_home/src/smart_home/lights/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/smart_home/src/smart_home/lights/hue_utils.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/smart_home/src/smart_home/lights/server.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/smart_home/src/smart_home/py.typed +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/smart_home/src/smart_home/settings.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/smart_home/uv.lock +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/examples/text_me.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/justfile +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/cli/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/cli/claude.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/cli/cli.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/client/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/client/base.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/client/client.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/client/roots.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/client/sampling.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/client/transports.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/exceptions.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/prompts/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/prompts/prompt.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/prompts/prompt_manager.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/py.typed +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/resources/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/resources/resource.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/resources/resource_manager.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/resources/template.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/resources/types.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/server/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/server/context.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/server/openapi.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/server/proxy.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/settings.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/tools/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/tools/tool.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/tools/tool_manager.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/utilities/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/utilities/decorators.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/utilities/func_metadata.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/utilities/logging.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/utilities/openapi.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/src/fastmcp/utilities/types.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/client/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/client/test_client.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/client/test_roots.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/client/test_sampling.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/conftest.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/prompts/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/prompts/test_base.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/prompts/test_prompt_manager.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/resources/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/resources/test_file_resources.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/resources/test_function_resources.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/resources/test_resource_manager.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/resources/test_resource_template.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/resources/test_resources.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/server/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/server/test_file_server.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/server/test_import_server.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/server/test_lifespan.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/server/test_mount.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/server/test_openapi.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/server/test_proxy.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/server/test_run_server.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/server/test_server.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/test_servers/fastmcp_server.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/test_servers/sse.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/test_servers/stdio.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/tools/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/tools/test_tool_manager.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/utilities/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/utilities/openapi/__init__.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/utilities/openapi/conftest.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/utilities/openapi/test_openapi.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/utilities/openapi/test_openapi_advanced.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/utilities/openapi/test_openapi_fastapi.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/utilities/test_decorated_function.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/tests/utilities/test_func_metadata.py +0 -0
- {fastmcp-2.2.0 → fastmcp-2.2.1}/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.1
|
|
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:
|
|
@@ -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,9 @@
|
|
|
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.
|
|
@@ -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,131 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from mcp.types import CallToolResult
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
from contrib.mcp_mixin.mcp_mixin import _DEFAULT_SEPARATOR_TOOL, MCPMixin, mcp_tool
|
|
7
|
+
from fastmcp import FastMCP
|
|
8
|
+
from fastmcp.client import Client
|
|
9
|
+
from fastmcp.client.transports import FastMCPTransport
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CallToolRequest(BaseModel):
|
|
13
|
+
"""A class to represent a request to call a tool with specific arguments."""
|
|
14
|
+
|
|
15
|
+
tool: str = Field(description="The name of the tool to call.")
|
|
16
|
+
arguments: dict[str, Any] = Field(
|
|
17
|
+
description="A dictionary containing the arguments for the tool call."
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CallToolRequestResult(CallToolResult):
|
|
22
|
+
"""
|
|
23
|
+
A class to represent the result of a bulk tool call.
|
|
24
|
+
It extends CallToolResult to include information about the requested tool call.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
tool: str = Field(description="The name of the tool that was called.")
|
|
28
|
+
arguments: dict[str, Any] = Field(
|
|
29
|
+
description="The arguments used for the tool call."
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
@classmethod
|
|
33
|
+
def from_call_tool_result(
|
|
34
|
+
cls, result: CallToolResult, tool: str, arguments: dict[str, Any]
|
|
35
|
+
) -> "CallToolRequestResult":
|
|
36
|
+
"""
|
|
37
|
+
Create a CallToolRequestResult from a CallToolResult.
|
|
38
|
+
"""
|
|
39
|
+
return cls(
|
|
40
|
+
tool=tool,
|
|
41
|
+
arguments=arguments,
|
|
42
|
+
isError=result.isError,
|
|
43
|
+
content=result.content,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class BulkToolCaller(MCPMixin):
|
|
48
|
+
"""
|
|
49
|
+
A class to provide a "bulk tool call" tool for a FastMCP server
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def register_tools(
|
|
53
|
+
self,
|
|
54
|
+
mcp_server: "FastMCP",
|
|
55
|
+
prefix: str | None = None,
|
|
56
|
+
separator: str = _DEFAULT_SEPARATOR_TOOL,
|
|
57
|
+
) -> None:
|
|
58
|
+
"""
|
|
59
|
+
Register the tools provided by this class with the given MCP server.
|
|
60
|
+
"""
|
|
61
|
+
self.connection = FastMCPTransport(mcp_server)
|
|
62
|
+
|
|
63
|
+
super().register_tools(mcp_server=mcp_server)
|
|
64
|
+
|
|
65
|
+
@mcp_tool()
|
|
66
|
+
async def call_tools_bulk(
|
|
67
|
+
self, tool_calls: list[CallToolRequest], continue_on_error: bool = True
|
|
68
|
+
) -> list[CallToolRequestResult]:
|
|
69
|
+
"""
|
|
70
|
+
Call multiple tools registered on this MCP server in a single request. Each call can
|
|
71
|
+
be for a different tool and can include different arguments. Useful for speeding up
|
|
72
|
+
what would otherwise take several individual tool calls.
|
|
73
|
+
"""
|
|
74
|
+
results = []
|
|
75
|
+
|
|
76
|
+
for tool_call in tool_calls:
|
|
77
|
+
result = await self._call_tool(tool_call.tool, tool_call.arguments)
|
|
78
|
+
|
|
79
|
+
results.append(result)
|
|
80
|
+
|
|
81
|
+
if result.isError and not continue_on_error:
|
|
82
|
+
return results
|
|
83
|
+
|
|
84
|
+
return results
|
|
85
|
+
|
|
86
|
+
@mcp_tool()
|
|
87
|
+
async def call_tool_bulk(
|
|
88
|
+
self,
|
|
89
|
+
tool: str,
|
|
90
|
+
tool_arguments: list[dict[str, str | int | float | bool | None]],
|
|
91
|
+
continue_on_error: bool = True,
|
|
92
|
+
) -> list[CallToolRequestResult]:
|
|
93
|
+
"""
|
|
94
|
+
Call a single tool registered on this MCP server multiple times with a single request.
|
|
95
|
+
Each call can include different arguments. Useful for speeding up what would otherwise
|
|
96
|
+
take several individual tool calls.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
tool: The name of the tool to call.
|
|
100
|
+
tool_arguments: A list of dictionaries, where each dictionary contains the arguments for an individual run of the tool.
|
|
101
|
+
"""
|
|
102
|
+
results = []
|
|
103
|
+
|
|
104
|
+
for tool_call_arguments in tool_arguments:
|
|
105
|
+
result = await self._call_tool(tool, tool_call_arguments)
|
|
106
|
+
|
|
107
|
+
results.append(result)
|
|
108
|
+
|
|
109
|
+
if result.isError and not continue_on_error:
|
|
110
|
+
return results
|
|
111
|
+
|
|
112
|
+
return results
|
|
113
|
+
|
|
114
|
+
async def _call_tool(
|
|
115
|
+
self, tool: str, arguments: dict[str, Any]
|
|
116
|
+
) -> CallToolRequestResult:
|
|
117
|
+
"""
|
|
118
|
+
Helper method to call a tool with the provided arguments.
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
async with Client(self.connection) as client:
|
|
122
|
+
result = await client.call_tool(
|
|
123
|
+
name=tool, arguments=arguments, _return_raw_result=True
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
return CallToolRequestResult(
|
|
127
|
+
tool=tool,
|
|
128
|
+
arguments=arguments,
|
|
129
|
+
isError=result.isError,
|
|
130
|
+
content=result.content,
|
|
131
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Sample code for FastMCP using MCPMixin."""
|
|
2
|
+
|
|
3
|
+
from contrib.bulk_tool_caller import BulkToolCaller
|
|
4
|
+
from fastmcp import FastMCP
|
|
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 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.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Sample code for FastMCP using MCPMixin."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
|
|
5
|
+
from contrib.mcp_mixin import (
|
|
6
|
+
MCPMixin,
|
|
7
|
+
mcp_prompt,
|
|
8
|
+
mcp_resource,
|
|
9
|
+
mcp_tool,
|
|
10
|
+
)
|
|
11
|
+
from fastmcp import FastMCP
|
|
12
|
+
|
|
13
|
+
mcp = FastMCP()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Sample(MCPMixin):
|
|
17
|
+
def __init__(self, name):
|
|
18
|
+
self.name = name
|
|
19
|
+
|
|
20
|
+
@mcp_tool()
|
|
21
|
+
def first_tool(self):
|
|
22
|
+
"""First tool description."""
|
|
23
|
+
return f"Executed tool {self.name}."
|
|
24
|
+
|
|
25
|
+
@mcp_resource(uri="test://test")
|
|
26
|
+
def first_resource(self):
|
|
27
|
+
"""First resource description."""
|
|
28
|
+
return f"Executed resource {self.name}."
|
|
29
|
+
|
|
30
|
+
@mcp_prompt()
|
|
31
|
+
def first_prompt(self):
|
|
32
|
+
"""First prompt description."""
|
|
33
|
+
return f"here's a prompt! {self.name}."
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
first_sample = Sample("First")
|
|
37
|
+
second_sample = Sample("Second")
|
|
38
|
+
|
|
39
|
+
first_sample.register_all(mcp_server=mcp, prefix="first")
|
|
40
|
+
second_sample.register_all(mcp_server=mcp, prefix="second")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async def list_components():
|
|
44
|
+
print("MCP Server running with registered components...")
|
|
45
|
+
print("Tools:", list(await mcp.get_tools()))
|
|
46
|
+
print("Resources:", list(await mcp.get_resources()))
|
|
47
|
+
print("Prompts:", list(await mcp.get_prompts()))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
asyncio.run(list_components())
|
|
52
|
+
mcp.run()
|