fastmcp 2.5.1__tar.gz → 2.5.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.5.1 → fastmcp-2.5.2}/PKG-INFO +1 -1
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/clients/client.mdx +24 -13
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/clients/transports.mdx +58 -1
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/deployment/cli.mdx +6 -3
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/patterns/http-requests.mdx +1 -1
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/cli/cli.py +1 -3
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/client/client.py +83 -15
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/client/transports.py +179 -15
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/resources/template.py +1 -1
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/server/dependencies.py +17 -6
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/server/server.py +43 -16
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/settings.py +7 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/tools/tool.py +4 -2
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/client/test_openapi.py +22 -4
- fastmcp-2.5.2/tests/client/test_stdio.py +127 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/test_mount.py +76 -1
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/test_proxy.py +9 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/.cursor/rules/core-mcp-objects.mdc +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/.github/ISSUE_TEMPLATE/enhancement.yml +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/.github/labeler.yml +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/.github/release.yml +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/.github/workflows/labeler.yml +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/.github/workflows/publish.yml +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/.github/workflows/run-static.yml +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/.github/workflows/run-tests.yml +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/.gitignore +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/.pre-commit-config.yaml +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/AGENTS.md +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/LICENSE +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/README.md +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/Windows_Notes.md +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/assets/demo-inspector.png +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/clients/advanced-features.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/deployment/asgi.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/deployment/authentication.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/deployment/running-server.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/docs.json +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/getting-started/installation.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/getting-started/quickstart.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/getting-started/welcome.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/patterns/contrib.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/patterns/decorating-methods.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/patterns/fastapi.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/patterns/testing.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/servers/composition.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/servers/context.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/servers/fastmcp.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/servers/openapi.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/servers/prompts.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/servers/proxy.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/servers/resources.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/servers/tools.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/snippets/version-badge.mdx +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/docs/style.css +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/complex_inputs.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/desktop.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/echo.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/in_memory_proxy_example.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/memory.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/mount_example.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/sampling.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/screenshot.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/serializer.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/simple_echo.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/smart_home/README.md +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/smart_home/pyproject.toml +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/smart_home/src/smart_home/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/smart_home/src/smart_home/__main__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/smart_home/src/smart_home/hub.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/smart_home/src/smart_home/lights/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/smart_home/src/smart_home/lights/hue_utils.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/smart_home/src/smart_home/lights/server.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/smart_home/src/smart_home/py.typed +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/smart_home/src/smart_home/settings.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/smart_home/uv.lock +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/tags_example.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/examples/text_me.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/justfile +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/pyproject.toml +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/cli/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/cli/claude.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/cli/run.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/client/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/client/base.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/client/logging.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/client/progress.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/client/roots.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/client/sampling.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/contrib/README.md +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/contrib/bulk_tool_caller/README.md +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/contrib/bulk_tool_caller/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/contrib/bulk_tool_caller/example.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/contrib/mcp_mixin/README.md +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/contrib/mcp_mixin/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/contrib/mcp_mixin/example.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/contrib/mcp_mixin/mcp_mixin.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/exceptions.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/low_level/README.md +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/low_level/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/prompts/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/prompts/prompt.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/prompts/prompt_manager.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/py.typed +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/resources/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/resources/resource.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/resources/resource_manager.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/resources/types.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/server/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/server/context.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/server/http.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/server/openapi.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/server/proxy.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/tools/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/tools/tool_manager.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/utilities/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/utilities/cache.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/utilities/decorators.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/utilities/exceptions.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/utilities/json_schema.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/utilities/logging.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/utilities/mcp_config.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/utilities/openapi.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/utilities/tests.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/src/fastmcp/utilities/types.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/cli/test_cli.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/cli/test_run.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/client/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/client/test_client.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/client/test_logs.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/client/test_progress.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/client/test_roots.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/client/test_sampling.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/client/test_sse.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/client/test_streamable_http.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/conftest.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/contrib/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/contrib/test_bulk_tool_caller.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/contrib/test_mcp_mixin.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/deprecated/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/deprecated/test_deprecated.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/deprecated/test_mount_separators.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/deprecated/test_resource_prefixes.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/deprecated/test_route_type_ignore.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/prompts/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/prompts/test_prompt.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/prompts/test_prompt_manager.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/resources/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/resources/test_file_resources.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/resources/test_function_resources.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/resources/test_resource_manager.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/resources/test_resource_template.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/resources/test_resources.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/http/test_custom_routes.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/http/test_http_dependencies.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/http/test_http_middleware.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/openapi/test_openapi.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/openapi/test_openapi_path_parameters.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/openapi/test_route_map_fn.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/test_app_state.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/test_auth_integration.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/test_context.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/test_file_server.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/test_import_server.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/test_lifespan.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/test_logging.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/test_resource_prefix_formats.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/test_run_server.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/test_server.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/test_server_interactions.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/server/test_tool_annotations.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/test_examples.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/test_servers/fastmcp_server.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/test_servers/sse.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/test_servers/stdio.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/tools/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/tools/test_tool.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/tools/test_tool_manager.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/utilities/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/utilities/openapi/__init__.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/utilities/openapi/conftest.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/utilities/openapi/test_openapi.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/utilities/openapi/test_openapi_advanced.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/utilities/openapi/test_openapi_fastapi.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/utilities/test_cache.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/utilities/test_decorated_function.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/utilities/test_json_schema.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/utilities/test_logging.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/utilities/test_mcp_config.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/utilities/test_tests.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/utilities/test_typeadapter.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/tests/utilities/test_types.py +0 -0
- {fastmcp-2.5.1 → fastmcp-2.5.2}/uv.lock +0 -0
|
@@ -18,18 +18,6 @@ The FastMCP Client architecture separates the protocol logic (`Client`) from the
|
|
|
18
18
|
- **`Client`**: Handles sending MCP requests (like `tools/call`, `resources/read`), receiving responses, and managing callbacks.
|
|
19
19
|
- **`Transport`**: Responsible for establishing and maintaining the connection to the server (e.g., via WebSockets, SSE, Stdio, or in-memory).
|
|
20
20
|
|
|
21
|
-
```python
|
|
22
|
-
from fastmcp import Client, FastMCP
|
|
23
|
-
from fastmcp.client import (
|
|
24
|
-
RootsHandler,
|
|
25
|
-
RootsList,
|
|
26
|
-
LogHandler,
|
|
27
|
-
MessageHandler,
|
|
28
|
-
SamplingHandler,
|
|
29
|
-
ProgressHandler # For handling progress notifications
|
|
30
|
-
)
|
|
31
|
-
```
|
|
32
|
-
|
|
33
21
|
### Transports
|
|
34
22
|
|
|
35
23
|
Clients must be initialized with a `transport`. You can either provide an already instantiated transport object, or provide a transport source and let FastMCP attempt to infer the correct transport to use.
|
|
@@ -282,7 +270,7 @@ These methods are especially useful for debugging or when you need to access met
|
|
|
282
270
|
|
|
283
271
|
### Additional Features
|
|
284
272
|
|
|
285
|
-
#### Pinging the
|
|
273
|
+
#### Pinging the Server
|
|
286
274
|
|
|
287
275
|
The client can be used to ping the server to verify connectivity.
|
|
288
276
|
|
|
@@ -292,6 +280,29 @@ async with client:
|
|
|
292
280
|
print("Server is reachable")
|
|
293
281
|
```
|
|
294
282
|
|
|
283
|
+
#### Session Management
|
|
284
|
+
|
|
285
|
+
When using stdio transports, clients support a `keep_alive` feature (enabled by default) that maintains subprocess sessions between connection contexts. You can manually control this behavior using the client's `close()` method.
|
|
286
|
+
|
|
287
|
+
When `keep_alive=False`, the client will automatically close the session when the context manager exits.
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
from fastmcp import Client
|
|
291
|
+
|
|
292
|
+
client = Client("my_mcp_server.py") # keep_alive=True by default
|
|
293
|
+
|
|
294
|
+
async def example():
|
|
295
|
+
async with client:
|
|
296
|
+
await client.ping()
|
|
297
|
+
|
|
298
|
+
async with client:
|
|
299
|
+
await client.ping() # Same subprocess as above
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
<Note>
|
|
303
|
+
For detailed examples and configuration options, see [Session Management in Transports](/clients/transports#session-management).
|
|
304
|
+
</Note>
|
|
305
|
+
|
|
295
306
|
#### Timeouts
|
|
296
307
|
|
|
297
308
|
<VersionBadge version="2.3.4" />
|
|
@@ -160,6 +160,63 @@ client = Client(transport)
|
|
|
160
160
|
|
|
161
161
|
These transports manage an MCP server running as a subprocess, communicating with it via standard input (stdin) and standard output (stdout). This is the standard mechanism used by clients like Claude Desktop.
|
|
162
162
|
|
|
163
|
+
### Session Management
|
|
164
|
+
|
|
165
|
+
All stdio transports support a `keep_alive` parameter (default: `True`) that controls session persistence across multiple client context managers:
|
|
166
|
+
|
|
167
|
+
- **`keep_alive=True` (default)**: The subprocess and session are maintained between client context exits and re-entries. This improves performance when making multiple separate connections to the same server.
|
|
168
|
+
- **`keep_alive=False`**: A new subprocess is started for each client context, ensuring complete isolation between sessions.
|
|
169
|
+
|
|
170
|
+
When `keep_alive=True`, you can manually close the session using `await client.close()` if needed. This will terminate the subprocess and require a new one to be started on the next connection.
|
|
171
|
+
|
|
172
|
+
<CodeGroup>
|
|
173
|
+
```python keep_alive=True
|
|
174
|
+
from fastmcp import Client
|
|
175
|
+
|
|
176
|
+
# Client with keep_alive=True (default)
|
|
177
|
+
client = Client("my_mcp_server.py")
|
|
178
|
+
|
|
179
|
+
async def example():
|
|
180
|
+
# First session
|
|
181
|
+
async with client:
|
|
182
|
+
await client.ping()
|
|
183
|
+
|
|
184
|
+
# Second session - uses the same subprocess
|
|
185
|
+
async with client:
|
|
186
|
+
await client.ping()
|
|
187
|
+
|
|
188
|
+
# Manually close the session
|
|
189
|
+
await client.close()
|
|
190
|
+
|
|
191
|
+
# Third session - will start a new subprocess
|
|
192
|
+
async with client:
|
|
193
|
+
await client.ping()
|
|
194
|
+
|
|
195
|
+
asyncio.run(example())
|
|
196
|
+
```
|
|
197
|
+
```python keep_alive=False
|
|
198
|
+
from fastmcp import Client
|
|
199
|
+
|
|
200
|
+
# Client with keep_alive=False
|
|
201
|
+
client = Client("my_mcp_server.py", keep_alive=False)
|
|
202
|
+
|
|
203
|
+
async def example():
|
|
204
|
+
# First session
|
|
205
|
+
async with client:
|
|
206
|
+
await client.ping()
|
|
207
|
+
|
|
208
|
+
# Second session - will start a new subprocess
|
|
209
|
+
async with client:
|
|
210
|
+
await client.ping()
|
|
211
|
+
|
|
212
|
+
# Third session - will start a new subprocess
|
|
213
|
+
async with client:
|
|
214
|
+
await client.ping()
|
|
215
|
+
|
|
216
|
+
asyncio.run(example())
|
|
217
|
+
```
|
|
218
|
+
</CodeGroup>
|
|
219
|
+
|
|
163
220
|
### Python Stdio
|
|
164
221
|
|
|
165
222
|
- **Class:** `fastmcp.client.transports.PythonStdioTransport`
|
|
@@ -218,7 +275,7 @@ client = Client(node_server_script)
|
|
|
218
275
|
# Option 2: Explicit transport
|
|
219
276
|
transport = NodeStdioTransport(
|
|
220
277
|
script_path=node_server_script,
|
|
221
|
-
node_cmd="node" # Optional: specify path to Node executable
|
|
278
|
+
node_cmd="node", # Optional: specify path to Node executable
|
|
222
279
|
)
|
|
223
280
|
client = Client(transport)
|
|
224
281
|
|
|
@@ -148,9 +148,12 @@ Install a MCP server in the Claude desktop app.
|
|
|
148
148
|
fastmcp install server.py
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
|
|
152
|
+
Note that for security reasons, Claude runs every MCP server in a completely isolated environment. Therefore, all dependencies must be explicitly specified using the `--with` and/or `--with-editable` options (following `uv` conventions) or by attaching them to your server in code via the `dependencies` parameter.
|
|
153
|
+
<Warning>
|
|
154
|
+
- **`uv` must be installed and available in your system PATH**. Claude Desktop runs in its own isolated environment and needs `uv` to manage dependencies.
|
|
155
|
+
- **On macOS, it is recommended to install `uv` globally with Homebrew** so that Claude Desktop will detect it: `brew install uv`. Installing `uv` with other methods may not make it accessible to Claude Desktop.
|
|
156
|
+
</Warning>
|
|
154
157
|
|
|
155
158
|
<Warning>
|
|
156
159
|
The `install` command currently only sets up servers for STDIO transport. When installed in the Claude desktop app, your server will be run using STDIO regardless of any transport configuration in your code.
|
|
@@ -77,7 +77,7 @@ async def safe_header_info() -> dict:
|
|
|
77
77
|
}
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
By default, `get_http_headers()` excludes problematic headers like `content-length`. To include all headers, use `get_http_headers(include_all=True)`.
|
|
80
|
+
By default, `get_http_headers()` excludes problematic headers like `host` and `content-length`. To include all headers, use `get_http_headers(include_all=True)`.
|
|
81
81
|
|
|
82
82
|
## Important Notes
|
|
83
83
|
|
|
@@ -50,9 +50,7 @@ def _get_npx_command():
|
|
|
50
50
|
def _parse_env_var(env_var: str) -> tuple[str, str]:
|
|
51
51
|
"""Parse environment variable string in format KEY=VALUE."""
|
|
52
52
|
if "=" not in env_var:
|
|
53
|
-
logger.error(
|
|
54
|
-
f"Invalid environment variable format: {env_var}. Must be KEY=VALUE"
|
|
55
|
-
)
|
|
53
|
+
logger.error("Invalid environment variable format. Must be KEY=VALUE")
|
|
56
54
|
sys.exit(1)
|
|
57
55
|
key, value = env_var.split("=", 1)
|
|
58
56
|
return key.strip(), value.strip()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import datetime
|
|
2
2
|
from contextlib import AsyncExitStack, asynccontextmanager
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import Any, cast
|
|
4
|
+
from typing import Any, Generic, cast, overload
|
|
5
5
|
|
|
6
6
|
import anyio
|
|
7
7
|
import mcp.types
|
|
@@ -9,6 +9,7 @@ from exceptiongroup import catch
|
|
|
9
9
|
from mcp import ClientSession
|
|
10
10
|
from pydantic import AnyUrl
|
|
11
11
|
|
|
12
|
+
import fastmcp
|
|
12
13
|
from fastmcp.client.logging import (
|
|
13
14
|
LogHandler,
|
|
14
15
|
MessageHandler,
|
|
@@ -27,7 +28,18 @@ from fastmcp.server import FastMCP
|
|
|
27
28
|
from fastmcp.utilities.exceptions import get_catch_handlers
|
|
28
29
|
from fastmcp.utilities.mcp_config import MCPConfig
|
|
29
30
|
|
|
30
|
-
from .transports import
|
|
31
|
+
from .transports import (
|
|
32
|
+
ClientTransportT,
|
|
33
|
+
FastMCP1Server,
|
|
34
|
+
FastMCPTransport,
|
|
35
|
+
MCPConfigTransport,
|
|
36
|
+
NodeStdioTransport,
|
|
37
|
+
PythonStdioTransport,
|
|
38
|
+
SessionKwargs,
|
|
39
|
+
SSETransport,
|
|
40
|
+
StreamableHttpTransport,
|
|
41
|
+
infer_transport,
|
|
42
|
+
)
|
|
31
43
|
|
|
32
44
|
__all__ = [
|
|
33
45
|
"Client",
|
|
@@ -40,13 +52,13 @@ __all__ = [
|
|
|
40
52
|
]
|
|
41
53
|
|
|
42
54
|
|
|
43
|
-
class Client:
|
|
55
|
+
class Client(Generic[ClientTransportT]):
|
|
44
56
|
"""
|
|
45
57
|
MCP client that delegates connection management to a Transport instance.
|
|
46
58
|
|
|
47
59
|
The Client class is responsible for MCP protocol logic, while the Transport
|
|
48
|
-
handles connection establishment and management. Client provides methods
|
|
49
|
-
|
|
60
|
+
handles connection establishment and management. Client provides methods for
|
|
61
|
+
working with resources, prompts, tools and other MCP capabilities.
|
|
50
62
|
|
|
51
63
|
Args:
|
|
52
64
|
transport: Connection source specification, which can be:
|
|
@@ -62,24 +74,60 @@ class Client:
|
|
|
62
74
|
message_handler: Optional handler for protocol messages
|
|
63
75
|
progress_handler: Optional handler for progress notifications
|
|
64
76
|
timeout: Optional timeout for requests (seconds or timedelta)
|
|
77
|
+
init_timeout: Optional timeout for initial connection (seconds or timedelta).
|
|
78
|
+
Set to 0 to disable. If None, uses the value in the FastMCP global settings.
|
|
65
79
|
|
|
66
80
|
Examples:
|
|
67
|
-
```python
|
|
68
|
-
|
|
69
|
-
client = Client("http://localhost:8080")
|
|
81
|
+
```python # Connect to FastMCP server client =
|
|
82
|
+
Client("http://localhost:8080")
|
|
70
83
|
|
|
71
84
|
async with client:
|
|
72
|
-
# List available resources
|
|
73
|
-
resources = await client.list_resources()
|
|
85
|
+
# List available resources resources = await client.list_resources()
|
|
74
86
|
|
|
75
|
-
# Call a tool
|
|
76
|
-
|
|
87
|
+
# Call a tool result = await client.call_tool("my_tool", {"param":
|
|
88
|
+
"value"})
|
|
77
89
|
```
|
|
78
90
|
"""
|
|
79
91
|
|
|
92
|
+
@overload
|
|
93
|
+
def __new__(
|
|
94
|
+
cls,
|
|
95
|
+
transport: ClientTransportT,
|
|
96
|
+
**kwargs: Any,
|
|
97
|
+
) -> "Client[ClientTransportT]": ...
|
|
98
|
+
|
|
99
|
+
@overload
|
|
100
|
+
def __new__(
|
|
101
|
+
cls, transport: AnyUrl, **kwargs
|
|
102
|
+
) -> "Client[SSETransport|StreamableHttpTransport]": ...
|
|
103
|
+
|
|
104
|
+
@overload
|
|
105
|
+
def __new__(
|
|
106
|
+
cls, transport: FastMCP | FastMCP1Server, **kwargs
|
|
107
|
+
) -> "Client[FastMCPTransport]": ...
|
|
108
|
+
|
|
109
|
+
@overload
|
|
110
|
+
def __new__(
|
|
111
|
+
cls, transport: Path, **kwargs
|
|
112
|
+
) -> "Client[PythonStdioTransport|NodeStdioTransport]": ...
|
|
113
|
+
|
|
114
|
+
@overload
|
|
115
|
+
def __new__(
|
|
116
|
+
cls, transport: MCPConfig | dict[str, Any], **kwargs
|
|
117
|
+
) -> "Client[MCPConfigTransport]": ...
|
|
118
|
+
|
|
119
|
+
@overload
|
|
120
|
+
def __new__(
|
|
121
|
+
cls, transport: str, **kwargs
|
|
122
|
+
) -> "Client[PythonStdioTransport|NodeStdioTransport|SSETransport|StreamableHttpTransport]": ...
|
|
123
|
+
|
|
124
|
+
def __new__(cls, transport, **kwargs) -> "Client":
|
|
125
|
+
instance = super().__new__(cls)
|
|
126
|
+
return instance
|
|
127
|
+
|
|
80
128
|
def __init__(
|
|
81
129
|
self,
|
|
82
|
-
transport:
|
|
130
|
+
transport: ClientTransportT
|
|
83
131
|
| FastMCP
|
|
84
132
|
| AnyUrl
|
|
85
133
|
| Path
|
|
@@ -93,8 +141,9 @@ class Client:
|
|
|
93
141
|
message_handler: MessageHandler | None = None,
|
|
94
142
|
progress_handler: ProgressHandler | None = None,
|
|
95
143
|
timeout: datetime.timedelta | float | int | None = None,
|
|
144
|
+
init_timeout: datetime.timedelta | float | int | None = None,
|
|
96
145
|
):
|
|
97
|
-
self.transport = infer_transport(transport)
|
|
146
|
+
self.transport = cast(ClientTransportT, infer_transport(transport))
|
|
98
147
|
self._session: ClientSession | None = None
|
|
99
148
|
self._exit_stack: AsyncExitStack | None = None
|
|
100
149
|
self._nesting_counter: int = 0
|
|
@@ -111,6 +160,17 @@ class Client:
|
|
|
111
160
|
if isinstance(timeout, int | float):
|
|
112
161
|
timeout = datetime.timedelta(seconds=timeout)
|
|
113
162
|
|
|
163
|
+
# handle init handshake timeout
|
|
164
|
+
if init_timeout is None:
|
|
165
|
+
init_timeout = fastmcp.settings.settings.client_init_timeout
|
|
166
|
+
if isinstance(init_timeout, datetime.timedelta):
|
|
167
|
+
init_timeout = init_timeout.total_seconds()
|
|
168
|
+
elif not init_timeout:
|
|
169
|
+
init_timeout = None
|
|
170
|
+
else:
|
|
171
|
+
init_timeout = float(init_timeout)
|
|
172
|
+
self._init_timeout = init_timeout
|
|
173
|
+
|
|
114
174
|
self._session_kwargs: SessionKwargs = {
|
|
115
175
|
"sampling_callback": None,
|
|
116
176
|
"list_roots_callback": None,
|
|
@@ -134,6 +194,7 @@ class Client:
|
|
|
134
194
|
raise RuntimeError(
|
|
135
195
|
"Client is not connected. Use the 'async with client:' context manager first."
|
|
136
196
|
)
|
|
197
|
+
|
|
137
198
|
return self._session
|
|
138
199
|
|
|
139
200
|
@property
|
|
@@ -168,9 +229,11 @@ class Client:
|
|
|
168
229
|
self._session = session
|
|
169
230
|
# Initialize the session
|
|
170
231
|
try:
|
|
171
|
-
with anyio.fail_after(
|
|
232
|
+
with anyio.fail_after(self._init_timeout):
|
|
172
233
|
self._initialize_result = await self._session.initialize()
|
|
173
234
|
yield
|
|
235
|
+
except anyio.ClosedResourceError:
|
|
236
|
+
raise RuntimeError("Server session was closed unexpectedly")
|
|
174
237
|
except TimeoutError:
|
|
175
238
|
raise RuntimeError("Failed to initialize server session")
|
|
176
239
|
finally:
|
|
@@ -203,6 +266,11 @@ class Client:
|
|
|
203
266
|
finally:
|
|
204
267
|
self._exit_stack = None
|
|
205
268
|
|
|
269
|
+
async def close(self):
|
|
270
|
+
await self.transport.close()
|
|
271
|
+
self._session = None
|
|
272
|
+
self._initialize_result = None
|
|
273
|
+
|
|
206
274
|
# --- MCP Client Methods ---
|
|
207
275
|
|
|
208
276
|
async def ping(self) -> bool:
|