fastmcp 2.5.0__tar.gz → 2.5.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.5.0 → fastmcp-2.5.1}/PKG-INFO +1 -1
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/patterns/http-requests.mdx +25 -17
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/servers/openapi.mdx +2 -8
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/client/transports.py +5 -34
- fastmcp-2.5.1/src/fastmcp/server/dependencies.py +67 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/server/openapi.py +3 -22
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/client/test_openapi.py +0 -1
- fastmcp-2.5.0/src/fastmcp/server/dependencies.py +0 -35
- {fastmcp-2.5.0 → fastmcp-2.5.1}/.cursor/rules/core-mcp-objects.mdc +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/.github/ISSUE_TEMPLATE/enhancement.yml +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/.github/labeler.yml +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/.github/release.yml +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/.github/workflows/labeler.yml +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/.github/workflows/publish.yml +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/.github/workflows/run-static.yml +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/.github/workflows/run-tests.yml +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/.gitignore +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/.pre-commit-config.yaml +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/AGENTS.md +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/LICENSE +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/README.md +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/Windows_Notes.md +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/assets/demo-inspector.png +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/clients/advanced-features.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/clients/client.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/clients/transports.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/deployment/asgi.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/deployment/authentication.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/deployment/cli.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/deployment/running-server.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/docs.json +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/getting-started/installation.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/getting-started/quickstart.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/getting-started/welcome.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/patterns/contrib.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/patterns/decorating-methods.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/patterns/fastapi.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/patterns/testing.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/servers/composition.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/servers/context.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/servers/fastmcp.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/servers/prompts.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/servers/proxy.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/servers/resources.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/servers/tools.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/snippets/version-badge.mdx +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/docs/style.css +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/complex_inputs.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/desktop.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/echo.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/in_memory_proxy_example.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/memory.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/mount_example.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/sampling.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/screenshot.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/serializer.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/simple_echo.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/smart_home/README.md +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/smart_home/pyproject.toml +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/smart_home/src/smart_home/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/smart_home/src/smart_home/__main__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/smart_home/src/smart_home/hub.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/smart_home/src/smart_home/lights/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/smart_home/src/smart_home/lights/hue_utils.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/smart_home/src/smart_home/lights/server.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/smart_home/src/smart_home/py.typed +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/smart_home/src/smart_home/settings.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/smart_home/uv.lock +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/tags_example.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/examples/text_me.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/justfile +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/pyproject.toml +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/cli/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/cli/claude.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/cli/cli.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/cli/run.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/client/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/client/base.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/client/client.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/client/logging.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/client/progress.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/client/roots.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/client/sampling.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/contrib/README.md +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/contrib/bulk_tool_caller/README.md +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/contrib/bulk_tool_caller/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/contrib/bulk_tool_caller/example.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/contrib/mcp_mixin/README.md +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/contrib/mcp_mixin/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/contrib/mcp_mixin/example.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/contrib/mcp_mixin/mcp_mixin.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/exceptions.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/low_level/README.md +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/low_level/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/prompts/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/prompts/prompt.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/prompts/prompt_manager.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/py.typed +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/resources/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/resources/resource.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/resources/resource_manager.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/resources/template.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/resources/types.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/server/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/server/context.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/server/http.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/server/proxy.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/server/server.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/settings.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/tools/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/tools/tool.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/tools/tool_manager.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/utilities/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/utilities/cache.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/utilities/decorators.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/utilities/exceptions.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/utilities/json_schema.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/utilities/logging.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/utilities/mcp_config.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/utilities/openapi.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/utilities/tests.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/src/fastmcp/utilities/types.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/cli/test_cli.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/cli/test_run.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/client/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/client/test_client.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/client/test_logs.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/client/test_progress.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/client/test_roots.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/client/test_sampling.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/client/test_sse.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/client/test_streamable_http.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/conftest.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/contrib/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/contrib/test_bulk_tool_caller.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/contrib/test_mcp_mixin.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/deprecated/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/deprecated/test_deprecated.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/deprecated/test_mount_separators.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/deprecated/test_resource_prefixes.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/deprecated/test_route_type_ignore.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/prompts/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/prompts/test_prompt.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/prompts/test_prompt_manager.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/resources/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/resources/test_file_resources.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/resources/test_function_resources.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/resources/test_resource_manager.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/resources/test_resource_template.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/resources/test_resources.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/http/test_custom_routes.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/http/test_http_dependencies.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/http/test_http_middleware.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/openapi/test_openapi.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/openapi/test_openapi_path_parameters.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/openapi/test_route_map_fn.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/test_app_state.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/test_auth_integration.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/test_context.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/test_file_server.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/test_import_server.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/test_lifespan.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/test_logging.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/test_mount.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/test_proxy.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/test_resource_prefix_formats.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/test_run_server.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/test_server.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/test_server_interactions.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/server/test_tool_annotations.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/test_examples.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/test_servers/fastmcp_server.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/test_servers/sse.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/test_servers/stdio.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/tools/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/tools/test_tool.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/tools/test_tool_manager.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/utilities/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/utilities/openapi/__init__.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/utilities/openapi/conftest.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/utilities/openapi/test_openapi.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/utilities/openapi/test_openapi_advanced.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/utilities/openapi/test_openapi_fastapi.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/utilities/test_cache.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/utilities/test_decorated_function.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/utilities/test_json_schema.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/utilities/test_logging.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/utilities/test_mcp_config.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/utilities/test_tests.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/utilities/test_typeadapter.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/tests/utilities/test_types.py +0 -0
- {fastmcp-2.5.0 → fastmcp-2.5.1}/uv.lock +0 -0
|
@@ -23,7 +23,7 @@ from fastmcp import FastMCP
|
|
|
23
23
|
from fastmcp.server.dependencies import get_http_request
|
|
24
24
|
from starlette.requests import Request
|
|
25
25
|
|
|
26
|
-
mcp = FastMCP(name="
|
|
26
|
+
mcp = FastMCP(name="HTTP Request Demo")
|
|
27
27
|
|
|
28
28
|
@mcp.tool()
|
|
29
29
|
async def user_agent_info() -> dict:
|
|
@@ -48,32 +48,40 @@ This approach works anywhere within a request's execution flow, not just within
|
|
|
48
48
|
2. You're calling nested functions that need HTTP request data
|
|
49
49
|
3. You're working with middleware or other request processing code
|
|
50
50
|
|
|
51
|
-
##
|
|
52
|
-
|
|
53
|
-
- HTTP requests are only available when FastMCP is running as part of a web application
|
|
54
|
-
- Accessing the HTTP request outside of a web request context will raise a `RuntimeError`
|
|
55
|
-
- The `get_http_request()` function returns a standard [Starlette Request](https://www.starlette.io/requests/) object
|
|
51
|
+
## Accessing HTTP Headers Only
|
|
56
52
|
|
|
57
|
-
|
|
53
|
+
If you only need request headers and want to avoid potential errors, you can use the `get_http_headers()` helper:
|
|
58
54
|
|
|
59
|
-
|
|
55
|
+
```python {2}
|
|
56
|
+
from fastmcp import FastMCP
|
|
57
|
+
from fastmcp.server.dependencies import get_http_headers
|
|
60
58
|
|
|
61
|
-
|
|
62
|
-
from fastmcp.server.dependencies import get_http_request
|
|
59
|
+
mcp = FastMCP(name="Headers Demo")
|
|
63
60
|
|
|
64
61
|
@mcp.tool()
|
|
65
|
-
async def
|
|
66
|
-
"""
|
|
67
|
-
|
|
62
|
+
async def safe_header_info() -> dict:
|
|
63
|
+
"""Safely get header information without raising errors."""
|
|
64
|
+
# Get headers (returns empty dict if no request context)
|
|
65
|
+
headers = get_http_headers()
|
|
68
66
|
|
|
69
67
|
# Get authorization header
|
|
70
|
-
auth_header =
|
|
71
|
-
|
|
72
|
-
# Check for Bearer token
|
|
68
|
+
auth_header = headers.get("authorization", "")
|
|
73
69
|
is_bearer = auth_header.startswith("Bearer ")
|
|
74
70
|
|
|
75
71
|
return {
|
|
72
|
+
"user_agent": headers.get("user-agent", "Unknown"),
|
|
73
|
+
"content_type": headers.get("content-type", "Unknown"),
|
|
76
74
|
"has_auth": bool(auth_header),
|
|
77
|
-
"auth_type": "Bearer" if is_bearer else "Other" if auth_header else "None"
|
|
75
|
+
"auth_type": "Bearer" if is_bearer else "Other" if auth_header else "None",
|
|
76
|
+
"headers_count": len(headers)
|
|
78
77
|
}
|
|
79
78
|
```
|
|
79
|
+
|
|
80
|
+
By default, `get_http_headers()` excludes problematic headers like `content-length`. To include all headers, use `get_http_headers(include_all=True)`.
|
|
81
|
+
|
|
82
|
+
## Important Notes
|
|
83
|
+
|
|
84
|
+
- HTTP requests are only available when FastMCP is running as part of a web application
|
|
85
|
+
- Accessing the HTTP request with `get_http_request()` outside of a web request context will raise a `RuntimeError`
|
|
86
|
+
- The `get_http_headers()` function **never raises errors** - it returns an empty dict when no request context is available
|
|
87
|
+
- The `get_http_request()` function returns a standard [Starlette Request](https://www.starlette.io/requests/) object
|
|
@@ -51,13 +51,7 @@ FastMCP analyzes your API specification and automatically creates MCP components
|
|
|
51
51
|
| `GET` without path params | `GET /stats` | **Resource** |
|
|
52
52
|
| `POST`, `PUT`, `PATCH`, `DELETE`, etc. | `POST /users` | **Tool** |
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
### Custom Route Maps
|
|
57
|
-
|
|
58
|
-
<VersionBadge version="2.5.0" />
|
|
59
|
-
|
|
60
|
-
FastMCP uses an ordered list of `RouteMap` objects to determine how to map OpenAPI routes to various MCP component types.
|
|
54
|
+
Interally, FastMCP uses an ordered list of `RouteMap` objects to determine how to map OpenAPI routes to various MCP component types.
|
|
61
55
|
|
|
62
56
|
Each `RouteMap` specifies a combination of methods, patterns, and tags, as well as a corresponding MCP component type. Each OpenAPI route is checked against each `RouteMap` in order, and the first one that matches every criteria is used to determine its converted MCP type. A special type, `EXCLUDE`, can be used to exclude routes from the MCP server entirely.
|
|
63
57
|
|
|
@@ -66,7 +60,7 @@ Each `RouteMap` specifies a combination of methods, patterns, and tags, as well
|
|
|
66
60
|
- **Tags**: A set of OpenAPI tags that must all be present. An empty set (`{}`) means no tag filtering, so the route matches regardless of its tags.
|
|
67
61
|
- **MCP type**: What MCP component type to create (`TOOL`, `RESOURCE`, `RESOURCE_TEMPLATE`, or `EXCLUDE`)
|
|
68
62
|
|
|
69
|
-
To illustrate this in practice, here are FastMCP's default
|
|
63
|
+
To illustrate this in practice, here are FastMCP's default rules as a list of `RouteMap` objects:
|
|
70
64
|
|
|
71
65
|
```python
|
|
72
66
|
from fastmcp.server.openapi import RouteMap, MCPType
|
|
@@ -25,7 +25,7 @@ from pydantic import AnyUrl
|
|
|
25
25
|
from typing_extensions import Unpack
|
|
26
26
|
|
|
27
27
|
from fastmcp.server import FastMCP as FastMCPServer
|
|
28
|
-
from fastmcp.server.dependencies import
|
|
28
|
+
from fastmcp.server.dependencies import get_http_headers
|
|
29
29
|
from fastmcp.server.server import FastMCP
|
|
30
30
|
from fastmcp.utilities.logging import get_logger
|
|
31
31
|
from fastmcp.utilities.mcp_config import MCPConfig, infer_transport_type_from_url
|
|
@@ -35,11 +35,6 @@ if TYPE_CHECKING:
|
|
|
35
35
|
|
|
36
36
|
logger = get_logger(__name__)
|
|
37
37
|
|
|
38
|
-
# these headers, when forwarded to the remote server, can cause issues
|
|
39
|
-
EXCLUDE_HEADERS = {
|
|
40
|
-
"content-length",
|
|
41
|
-
}
|
|
42
|
-
|
|
43
38
|
|
|
44
39
|
class SessionKwargs(TypedDict, total=False):
|
|
45
40
|
"""Keyword arguments for the MCP ClientSession constructor."""
|
|
@@ -138,23 +133,12 @@ class SSETransport(ClientTransport):
|
|
|
138
133
|
async def connect_session(
|
|
139
134
|
self, **session_kwargs: Unpack[SessionKwargs]
|
|
140
135
|
) -> AsyncIterator[ClientSession]:
|
|
141
|
-
client_kwargs: dict[str, Any] = {
|
|
142
|
-
"headers": self.headers,
|
|
143
|
-
}
|
|
136
|
+
client_kwargs: dict[str, Any] = {}
|
|
144
137
|
|
|
145
138
|
# load headers from an active HTTP request, if available. This will only be true
|
|
146
139
|
# if the client is used in a FastMCP Proxy, in which case the MCP client headers
|
|
147
140
|
# need to be forwarded to the remote server.
|
|
148
|
-
|
|
149
|
-
active_request = get_http_request()
|
|
150
|
-
for name, value in active_request.headers.items():
|
|
151
|
-
name = name.lower()
|
|
152
|
-
if name not in self.headers and name not in {
|
|
153
|
-
h.lower() for h in EXCLUDE_HEADERS
|
|
154
|
-
}:
|
|
155
|
-
client_kwargs["headers"][name] = str(value)
|
|
156
|
-
except RuntimeError:
|
|
157
|
-
client_kwargs["headers"] = self.headers
|
|
141
|
+
client_kwargs["headers"] = get_http_headers() | self.headers
|
|
158
142
|
|
|
159
143
|
# sse_read_timeout has a default value set, so we can't pass None without overriding it
|
|
160
144
|
# instead we simply leave the kwarg out if it's not provided
|
|
@@ -201,25 +185,12 @@ class StreamableHttpTransport(ClientTransport):
|
|
|
201
185
|
async def connect_session(
|
|
202
186
|
self, **session_kwargs: Unpack[SessionKwargs]
|
|
203
187
|
) -> AsyncIterator[ClientSession]:
|
|
204
|
-
client_kwargs: dict[str, Any] = {
|
|
205
|
-
"headers": self.headers,
|
|
206
|
-
}
|
|
188
|
+
client_kwargs: dict[str, Any] = {}
|
|
207
189
|
|
|
208
190
|
# load headers from an active HTTP request, if available. This will only be true
|
|
209
191
|
# if the client is used in a FastMCP Proxy, in which case the MCP client headers
|
|
210
192
|
# need to be forwarded to the remote server.
|
|
211
|
-
|
|
212
|
-
active_request = get_http_request()
|
|
213
|
-
for name, value in active_request.headers.items():
|
|
214
|
-
name = name.lower()
|
|
215
|
-
if name not in self.headers and name not in {
|
|
216
|
-
h.lower() for h in EXCLUDE_HEADERS
|
|
217
|
-
}:
|
|
218
|
-
client_kwargs["headers"][name] = str(value)
|
|
219
|
-
|
|
220
|
-
except RuntimeError:
|
|
221
|
-
client_kwargs["headers"] = self.headers
|
|
222
|
-
print(client_kwargs)
|
|
193
|
+
client_kwargs["headers"] = get_http_headers() | self.headers
|
|
223
194
|
|
|
224
195
|
# sse_read_timeout has a default value set, so we can't pass None without overriding it
|
|
225
196
|
# instead we simply leave the kwarg out if it's not provided
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, ParamSpec, TypeVar
|
|
4
|
+
|
|
5
|
+
from starlette.requests import Request
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from fastmcp.server.context import Context
|
|
9
|
+
|
|
10
|
+
P = ParamSpec("P")
|
|
11
|
+
R = TypeVar("R")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# --- Context ---
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_context() -> Context:
|
|
18
|
+
from fastmcp.server.context import _current_context
|
|
19
|
+
|
|
20
|
+
context = _current_context.get()
|
|
21
|
+
if context is None:
|
|
22
|
+
raise RuntimeError("No active context found.")
|
|
23
|
+
return context
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# --- HTTP Request ---
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_http_request() -> Request:
|
|
30
|
+
from fastmcp.server.http import _current_http_request
|
|
31
|
+
|
|
32
|
+
request = _current_http_request.get()
|
|
33
|
+
if request is None:
|
|
34
|
+
raise RuntimeError("No active HTTP request found.")
|
|
35
|
+
return request
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_http_headers(include_all: bool = False) -> dict[str, str]:
|
|
39
|
+
"""
|
|
40
|
+
Extract headers from the current HTTP request if available.
|
|
41
|
+
|
|
42
|
+
Never raises an exception, even if there is no active HTTP request (in which case
|
|
43
|
+
an empty dict is returned).
|
|
44
|
+
|
|
45
|
+
By default, strips problematic headers like `content-length` that cause issues if forwarded to downstream clients.
|
|
46
|
+
If `include_all` is True, all headers are returned.
|
|
47
|
+
"""
|
|
48
|
+
if include_all:
|
|
49
|
+
exclude_headers = set()
|
|
50
|
+
else:
|
|
51
|
+
exclude_headers = {"content-length"}
|
|
52
|
+
|
|
53
|
+
# ensure all lowercase!
|
|
54
|
+
# (just in case)
|
|
55
|
+
exclude_headers = {h.lower() for h in exclude_headers}
|
|
56
|
+
|
|
57
|
+
headers = {}
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
request = get_http_request()
|
|
61
|
+
for name, value in request.headers.items():
|
|
62
|
+
lower_name = name.lower()
|
|
63
|
+
if lower_name not in exclude_headers:
|
|
64
|
+
headers[lower_name] = str(value)
|
|
65
|
+
return headers
|
|
66
|
+
except RuntimeError:
|
|
67
|
+
return {}
|
|
@@ -18,7 +18,7 @@ from pydantic.networks import AnyUrl
|
|
|
18
18
|
|
|
19
19
|
from fastmcp.exceptions import ToolError
|
|
20
20
|
from fastmcp.resources import Resource, ResourceTemplate
|
|
21
|
-
from fastmcp.server.dependencies import
|
|
21
|
+
from fastmcp.server.dependencies import get_http_headers
|
|
22
22
|
from fastmcp.server.server import FastMCP
|
|
23
23
|
from fastmcp.tools.tool import Tool, _convert_to_content
|
|
24
24
|
from fastmcp.utilities import openapi
|
|
@@ -60,25 +60,6 @@ def _slugify(text: str) -> str:
|
|
|
60
60
|
return slug
|
|
61
61
|
|
|
62
62
|
|
|
63
|
-
def _get_mcp_client_headers() -> dict[str, str]:
|
|
64
|
-
"""
|
|
65
|
-
Extract headers from the current MCP client HTTP request if available.
|
|
66
|
-
|
|
67
|
-
These headers will take precedence over OpenAPI-defined headers when both are present.
|
|
68
|
-
|
|
69
|
-
Returns:
|
|
70
|
-
Dictionary of header name-value pairs (lowercased names), or empty dict if no HTTP request is active.
|
|
71
|
-
"""
|
|
72
|
-
try:
|
|
73
|
-
http_request = get_http_request()
|
|
74
|
-
return {
|
|
75
|
-
name.lower(): str(value) for name, value in http_request.headers.items()
|
|
76
|
-
}
|
|
77
|
-
except RuntimeError:
|
|
78
|
-
# No active HTTP request (e.g., STDIO transport), return empty dict
|
|
79
|
-
return {}
|
|
80
|
-
|
|
81
|
-
|
|
82
63
|
# Type definitions for the mapping functions
|
|
83
64
|
RouteMapFn = Callable[[HTTPRoute, "MCPType"], "MCPType | None"]
|
|
84
65
|
ComponentFn = Callable[
|
|
@@ -423,7 +404,7 @@ class OpenAPITool(Tool):
|
|
|
423
404
|
headers.update(openapi_headers)
|
|
424
405
|
|
|
425
406
|
# Add headers from the current MCP client HTTP request (these take precedence)
|
|
426
|
-
mcp_headers =
|
|
407
|
+
mcp_headers = get_http_headers()
|
|
427
408
|
headers.update(mcp_headers)
|
|
428
409
|
|
|
429
410
|
# Prepare request body
|
|
@@ -574,7 +555,7 @@ class OpenAPIResource(Resource):
|
|
|
574
555
|
|
|
575
556
|
# Prepare headers from MCP client request if available
|
|
576
557
|
headers = {}
|
|
577
|
-
mcp_headers =
|
|
558
|
+
mcp_headers = get_http_headers()
|
|
578
559
|
headers.update(mcp_headers)
|
|
579
560
|
|
|
580
561
|
response = await self._client.request(
|
|
@@ -185,7 +185,6 @@ class TestClientHeaders:
|
|
|
185
185
|
Test that client headers are passed through the proxy to the remove server.
|
|
186
186
|
"""
|
|
187
187
|
async with Client(transport=StreamableHttpTransport(proxy_server)) as client:
|
|
188
|
-
await client.ping()
|
|
189
188
|
result = await client.read_resource("resource://get_headers_headers_get")
|
|
190
189
|
assert isinstance(result[0], TextResourceContents)
|
|
191
190
|
headers = json.loads(result[0].text)
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import TYPE_CHECKING, ParamSpec, TypeVar
|
|
4
|
-
|
|
5
|
-
from starlette.requests import Request
|
|
6
|
-
|
|
7
|
-
if TYPE_CHECKING:
|
|
8
|
-
from fastmcp.server.context import Context
|
|
9
|
-
|
|
10
|
-
P = ParamSpec("P")
|
|
11
|
-
R = TypeVar("R")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# --- Context ---
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def get_context() -> Context:
|
|
18
|
-
from fastmcp.server.context import _current_context
|
|
19
|
-
|
|
20
|
-
context = _current_context.get()
|
|
21
|
-
if context is None:
|
|
22
|
-
raise RuntimeError("No active context found.")
|
|
23
|
-
return context
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
# --- HTTP Request ---
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def get_http_request() -> Request:
|
|
30
|
-
from fastmcp.server.http import _current_http_request
|
|
31
|
-
|
|
32
|
-
request = _current_http_request.get()
|
|
33
|
-
if request is None:
|
|
34
|
-
raise RuntimeError("No active HTTP request found.")
|
|
35
|
-
return request
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|