diff --git a/docs/docs.json b/docs/docs.json index 7e7031f8a..e1ee9d4f3 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -65,6 +65,7 @@ "patterns/proxy", "patterns/composition", "patterns/decorating-methods", + "patterns/http-requests", "patterns/openapi", "patterns/fastapi", "patterns/contrib", diff --git a/docs/patterns/http-requests.mdx b/docs/patterns/http-requests.mdx new file mode 100644 index 000000000..59356acd7 --- /dev/null +++ b/docs/patterns/http-requests.mdx @@ -0,0 +1,79 @@ +--- +title: HTTP Requests +sidebarTitle: HTTP Requests +description: Accessing and using HTTP requests in FastMCP servers +icon: network-wired +--- +import { VersionBadge } from '/snippets/version-badge.mdx' + + + +## Overview + +When running FastMCP as a web server, your MCP tools, resources, and prompts might need to access the underlying HTTP request information, such as headers, client IP, or query parameters. + +FastMCP provides a clean way to access HTTP request information through a dependency function. + +## Accessing HTTP Requests + +The recommended way to access the current HTTP request is through the `get_http_request()` dependency function: + +```python {2, 3, 11} +from fastmcp import FastMCP +from fastmcp.server.dependencies import get_http_request +from starlette.requests import Request + +mcp = FastMCP(name="HTTPRequestDemo") + +@mcp.tool() +async def user_agent_info() -> dict: + """Return information about the user agent.""" + # Get the HTTP request + request: Request = get_http_request() + + # Access request data + user_agent = request.headers.get("user-agent", "Unknown") + client_ip = request.client.host if request.client else "Unknown" + + return { + "user_agent": user_agent, + "client_ip": client_ip, + "path": request.url.path, + } +``` + +This approach works anywhere within a request's execution flow, not just within your MCP function. It's useful when: + +1. You need access to HTTP information in helper functions +2. You're calling nested functions that need HTTP request data +3. You're working with middleware or other request processing code + +## Important Notes + +- HTTP requests are only available when FastMCP is running as part of a web application +- Accessing the HTTP request outside of a web request context will raise a `RuntimeError` +- The `get_http_request()` function returns a standard [Starlette Request](https://www.starlette.io/requests/) object + +## Common Use Cases + +### Accessing Request Headers + +```python +from fastmcp.server.dependencies import get_http_request + +@mcp.tool() +async def get_auth_info() -> dict: + """Get authentication information from request headers.""" + request = get_http_request() + + # Get authorization header + auth_header = request.headers.get("authorization", "") + + # Check for Bearer token + is_bearer = auth_header.startswith("Bearer ") + + return { + "has_auth": bool(auth_header), + "auth_type": "Bearer" if is_bearer else "Other" if auth_header else "None" + } +``` diff --git a/docs/servers/context.mdx b/docs/servers/context.mdx index e7c11ce22..377650018 100644 --- a/docs/servers/context.mdx +++ b/docs/servers/context.mdx @@ -21,6 +21,8 @@ The `Context` object provides a clean interface to access MCP features within yo ## Accessing the Context +### Via Dependency Injection + To use the context object within any of your functions, simply add a parameter to your function signature and type-hint it as `Context`. FastMCP will automatically inject the context instance when your function is called. **Key Points:** @@ -32,7 +34,7 @@ To use the context object within any of your functions, simply add a parameter t - The type hint can be a union (`Context | None`) or use `Annotated[]` and it will still work properly. - Context is only available during a request; attempting to use context methods outside a request will raise errors. If you need to debug or call your context methods outside of a request, you can type your variable as `Context | None=None` to avoid missing argument errors. -### Tools +#### Tools ```python from fastmcp import FastMCP, Context @@ -46,7 +48,7 @@ async def process_file(file_uri: str, ctx: Context) -> str: return "Processed file" ``` -### Resources and Templates +#### Resources and Templates @@ -64,7 +66,7 @@ async def get_user_profile(user_id: str, ctx: Context) -> dict: return {"id": user_id} ``` -### Prompts +#### Prompts @@ -77,6 +79,38 @@ async def data_analysis_request(dataset: str, ctx: Context) -> str: ``` +### Via Dependency Function + + + +While the simplest way to access context is through function parameter injection as shown above, there are cases where you need to access the context in code that may not be easy to modify to accept a context parameter, or that is nested deeper within your function calls. + +FastMCP provides dependency functions that allow you to retrieve the active context from anywhere within a server request's execution flow: + +```python {2,9} +from fastmcp import FastMCP, Context +from fastmcp.server.dependencies import get_context + +mcp = FastMCP(name="DependencyDemo") + +# Utility function that needs context but doesn't receive it as a parameter +async def process_data(data: list[float]) -> dict: + # Get the active context - only works when called within a request + ctx = get_context() + await ctx.info(f"Processing {len(data)} data points") + +@mcp.tool() +async def analyze_dataset(dataset_name: str) -> dict: + # Call utility function that uses context internally + data = load_data(dataset_name) + await process_data(data) +``` + +**Important Notes:** + +- The `get_context` function should only be used within the context of a server request. Calling it outside of a request will raise a `RuntimeError`. +- The `get_context` function is server-only and should not be used in client code. + ## Context Capabilities ### Logging @@ -263,7 +297,7 @@ async def request_info(ctx: Context) -> dict: For advanced use cases, you can access the underlying MCP session, FastMCP server, and HTTP requests. -#### Accessing FastMCP and Sessions +#### FastMCP Server and Sessions ```python @mcp.tool() @@ -279,10 +313,16 @@ async def advanced_tool(ctx: Context) -> str: return f"Server: {server_name}" ``` -#### Accessing HTTP Requests +#### HTTP Requests + +The `ctx.get_http_request()` method is deprecated and will be removed in a future version. +Please use the `get_http_request()` dependency function instead. +See the [HTTP Requests pattern](/patterns/http-requests) for more details. + + For web applications, you can access the underlying HTTP request: ```python @@ -307,9 +347,7 @@ async def handle_web_request(ctx: Context) -> dict: - **`ctx.fastmcp -> FastMCP`**: Access the server instance the context belongs to - **`ctx.session`**: Access the raw `mcp.server.session.ServerSession` object - **`ctx.request_context`**: Access the raw `mcp.shared.context.RequestContext` object -- **`ctx.get_http_request() -> Request`**: Access the active Starlette request object (when running with a web server) Direct use of `session` or `request_context` requires understanding the low-level MCP Python SDK and may be less stable than using the methods provided directly on the `Context` object. -