# Advanced Features Source: https://gofastmcp.com/clients/advanced-features Learn about the advanced features of the FastMCP Client. export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; In addition to basic server interaction, FastMCP clients can also handle more advanced features and server interaction patterns. The `Client` constructor accepts additional configuration to handle these server requests. To enable many of these features, you must provide an appropriate handler or callback function. For example. In most cases, if you do not provide a handler, FastMCP's default handler will emit a `DEBUG` level log. ## Logging and Notifications MCP servers can emit logs to clients. To process these logs, you can provide a `log_handler` to the client. The `log_handler` must be an async function that accepts a single argument, which is an instance of `fastmcp.client.logging.LogMessage`. This has attributes like `level`, `logger`, and `data`. ```python {2, 12} from fastmcp import Client from fastmcp.client.logging import LogMessage async def log_handler(message: LogMessage): level = message.level.upper() logger = message.logger or 'default' data = message.data print(f"[Server Log - {level}] {logger}: {data}") client_with_logging = Client( ..., log_handler=log_handler, ) ``` ## Progress Monitoring MCP servers can report progress during long-running operations. The client can set a progress handler to receive and process these updates. ```python {2, 13} from fastmcp import Client from fastmcp.client.progress import ProgressHandler async def my_progress_handler( progress: float, total: float | None, message: str | None ) -> None: print(f"Progress: {progress} / {total} ({message})") client = Client( ..., progress_handler=my_progress_handler ) ``` By default, FastMCP uses a handler that logs progress updates at the debug level. This default handler properly handles cases where `total` or `message` might be None. You can override the progress handler for specific tool calls: ```python # Client uses the default debug logger for progress client = Client(...) async with client: # Use default progress handler (debug logging) result1 = await client.call_tool("long_task", {"param": "value"}) # Override with custom progress handler just for this call result2 = await client.call_tool( "another_task", {"param": "value"}, progress_handler=my_progress_handler ) ``` A typical progress update includes: * Current progress value (e.g., 2 of 5 steps completed) * Total expected value (may be None) * Status message (may be None) ## LLM Sampling MCP Servers can request LLM completions from clients. The client can provide a `sampling_handler` to handle these requests. The sampling handler receives a list of messages and other parameters from the server, and should return a string completion. The following example uses the `marvin` library to generate a completion: ```python {8-17, 21} import marvin from fastmcp import Client from fastmcp.client.sampling import ( SamplingMessage, SamplingParams, RequestContext, ) async def sampling_handler( messages: list[SamplingMessage], params: SamplingParams, context: RequestContext ) -> str: return await marvin.say_async( message=[m.content.text for m in messages], instructions=params.systemPrompt, ) client = Client( ..., sampling_handler=sampling_handler, ) ``` ## Roots Roots are a way for clients to inform servers about the resources they have access to or certain boundaries on their access. The server can use this information to adjust behavior or provide more accurate responses. Servers can request roots from clients, and clients can notify servers when their roots change. To set the roots when creating a client, users can either provide a list of roots (which can be a list of strings) or an async function that returns a list of roots. ```python Static Roots {5} from fastmcp import Client client = Client( ..., roots=["/path/to/root1", "/path/to/root2"], ) ``` ```python Dynamic Roots Callback {4-6, 10} from fastmcp import Client from fastmcp.client.roots import RequestContext async def roots_callback(context: RequestContext) -> list[str]: print(f"Server requested roots (Request ID: {context.request_id})") return ["/path/to/root1", "/path/to/root2"] client = Client( ..., roots=roots_callback, ) ``` # Client Overview Source: https://gofastmcp.com/clients/client Learn how to use the FastMCP Client to interact with MCP servers. export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; The `fastmcp.Client` provides a high-level, asynchronous interface for interacting with any Model Context Protocol (MCP) server, whether it's built with FastMCP or another implementation. It simplifies communication by handling protocol details and connection management. ## FastMCP Client The FastMCP Client architecture separates the protocol logic (`Client`) from the connection mechanism (`Transport`). * **`Client`**: Handles sending MCP requests (like `tools/call`, `resources/read`), receiving responses, and managing callbacks. * **`Transport`**: Responsible for establishing and maintaining the connection to the server (e.g., via WebSockets, SSE, Stdio, or in-memory). ```python from fastmcp import Client, FastMCP from fastmcp.client import ( RootsHandler, RootsList, LogHandler, MessageHandler, SamplingHandler, ProgressHandler # For handling progress notifications ) ``` ### Transports 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. The following inference rules are used to determine the appropriate `ClientTransport` based on the input type: 1. **`ClientTransport` Instance**: If you provide an already instantiated transport object, it's used directly. 2. **`FastMCP` Instance**: Creates a `FastMCPTransport` for efficient in-memory communication (ideal for testing). This also works with a **FastMCP 1.0 server** created via `mcp.server.fastmcp.FastMCP`. 3. **`Path` or `str` pointing to an existing file**: * If it ends with `.py`: Creates a `PythonStdioTransport` to run the script using `python`. * If it ends with `.js`: Creates a `NodeStdioTransport` to run the script using `node`. 4. **`AnyUrl` or `str` pointing to a URL that begins with `http://` or `https://`**: * Creates a `StreamableHttpTransport` 5. **`MCPConfig` or dictionary matching MCPConfig schema**: Creates a client that connects to one or more MCP servers specified in the config. 6. **Other**: Raises a `ValueError` if the type cannot be inferred. ```python import asyncio from fastmcp import Client, FastMCP # Example transports (more details in Transports page) server_instance = FastMCP(name="TestServer") # In-memory server http_url = "https://example.com/mcp" # HTTP server URL server_script = "my_mcp_server.py" # Path to a Python server file # Client automatically infers the transport type client_in_memory = Client(server_instance) client_http = Client(http_url) client_stdio = Client(server_script) print(client_in_memory.transport) print(client_http.transport) print(client_stdio.transport) # Expected Output (types may vary slightly based on environment): # # # ``` You can also initialize a client from an MCP configuration dictionary or `MCPConfig` file: ```python from fastmcp import Client config = { "mcpServers": { "local": {"command": "python", "args": ["local_server.py"]}, "remote": {"url": "https://example.com/mcp"}, } } client_config = Client(config) ``` For more control over connection details (like headers for SSE, environment variables for Stdio), you can instantiate the specific `ClientTransport` class yourself and pass it to the `Client`. See the [Transports](/clients/transports) page for details. ### Multi-Server Clients FastMCP supports creating clients that connect to multiple MCP servers through a single client interface using a standard MCP configuration format (`MCPConfig`). This configuration approach makes it easy to connect to multiple specialized servers or create composable systems with a simple, declarative syntax. The MCP configuration format follows an emerging standard and may evolve as the specification matures. FastMCP will strive to maintain compatibility with future versions, but be aware that field names or structure might change. When you create a client with an `MCPConfig` containing multiple servers: 1. FastMCP creates a composite client that internally mounts all servers using their config names as prefixes 2. Tools and resources from each server are accessible with appropriate prefixes in the format `servername_toolname` and `protocol://servername/resource/path` 3. You interact with this as a single unified client, with requests automatically routed to the appropriate server ```python from fastmcp import Client # Create a standard MCP configuration with multiple servers config = { "mcpServers": { # A remote HTTP server "weather": { "url": "https://weather-api.example.com/mcp", "transport": "streamable-http" }, # A local server running via stdio "assistant": { "command": "python", "args": ["./my_assistant_server.py"], "env": {"DEBUG": "true"} } } } # Create a client that connects to both servers client = Client(config) async def main(): async with client: # Access tools from different servers with prefixes weather_data = await client.call_tool("weather_get_forecast", {"city": "London"}) response = await client.call_tool("assistant_answer_question", {"question": "What's the capital of France?"}) # Access resources with prefixed URIs weather_icons = await client.read_resource("weather://weather/icons/sunny") templates = await client.read_resource("resource://assistant/templates/list") print(f"Weather: {weather_data}") print(f"Assistant: {response}") if __name__ == "__main__": asyncio.run(main()) ``` If your configuration has only a single server, FastMCP will create a direct client to that server without any prefixing. ## Client Usage ### Connection Lifecycle The client operates asynchronously and must be used within an `async with` block. This context manager handles establishing the connection, initializing the MCP session, and cleaning up resources upon exit. ```python import asyncio from fastmcp import Client client = Client("my_mcp_server.py") # Assumes my_mcp_server.py exists async def main(): # Connection is established here async with client: print(f"Client connected: {client.is_connected()}") # Make MCP calls within the context tools = await client.list_tools() print(f"Available tools: {tools}") if any(tool.name == "greet" for tool in tools): result = await client.call_tool("greet", {"name": "World"}) print(f"Greet result: {result}") # Connection is closed automatically here print(f"Client connected: {client.is_connected()}") if __name__ == "__main__": asyncio.run(main()) ``` You can make multiple calls to the server within the same `async with` block using the established session. ### Client Methods The `Client` provides methods corresponding to standard MCP requests: The standard client methods return user-friendly representations that may change as the protocol evolves. For consistent access to the complete data structure, use the `*_mcp` methods described later. #### Tool Operations * **`list_tools()`**: Retrieves a list of tools available on the server. ```python tools = await client.list_tools() # tools -> list[mcp.types.Tool] ``` * **`call_tool(name: str, arguments: dict[str, Any] | None = None, timeout: float | None = None, progress_handler: ProgressHandler | None = None)`**: Executes a tool on the server. ```python result = await client.call_tool("add", {"a": 5, "b": 3}) # result -> list[mcp.types.TextContent | mcp.types.ImageContent | ...] print(result[0].text) # Assuming TextContent, e.g., '8' # With timeout (aborts if execution takes longer than 2 seconds) result = await client.call_tool("long_running_task", {"param": "value"}, timeout=2.0) # With progress handler (to track execution progress) result = await client.call_tool( "long_running_task", {"param": "value"}, progress_handler=my_progress_handler ) ``` * Arguments are passed as a dictionary. FastMCP servers automatically handle JSON string parsing for complex types if needed. * Returns a list of content objects (usually `TextContent` or `ImageContent`). * The optional `timeout` parameter limits the maximum execution time (in seconds) for this specific call, overriding any client-level timeout. * The optional `progress_handler` parameter receives progress updates during execution, overriding any client-level progress handler. #### Resource Operations * **`list_resources()`**: Retrieves a list of static resources. ```python resources = await client.list_resources() # resources -> list[mcp.types.Resource] ``` * **`list_resource_templates()`**: Retrieves a list of resource templates. ```python templates = await client.list_resource_templates() # templates -> list[mcp.types.ResourceTemplate] ``` * **`read_resource(uri: str | AnyUrl)`**: Reads the content of a resource or a resolved template. ```python # Read a static resource readme_content = await client.read_resource("file:///path/to/README.md") # readme_content -> list[mcp.types.TextResourceContents | mcp.types.BlobResourceContents] print(readme_content[0].text) # Assuming text # Read a resource generated from a template weather_content = await client.read_resource("data://weather/london") print(weather_content[0].text) # Assuming text JSON ``` #### Prompt Operations * **`list_prompts()`**: Retrieves available prompt templates. * **`get_prompt(name: str, arguments: dict[str, Any] | None = None)`**: Retrieves a rendered prompt message list. ### Raw MCP Protocol Objects The FastMCP client attempts to provide a "friendly" interface to the MCP protocol, but sometimes you may need access to the raw MCP protocol objects. Each of the main client methods that returns data has a corresponding `*_mcp` method that returns the raw MCP protocol objects directly. The standard client methods (without `_mcp`) return user-friendly representations of MCP data, while `*_mcp` methods will always return the complete MCP protocol objects. As the protocol evolves, changes to these user-friendly representations may occur and could potentially be breaking. If you need consistent, stable access to the full data structure, prefer using the `*_mcp` methods. ```python # Standard method - returns just the list of tools tools = await client.list_tools() # tools -> list[mcp.types.Tool] # Raw MCP method - returns the full protocol object result = await client.list_tools_mcp() # result -> mcp.types.ListToolsResult tools = result.tools ``` Available raw MCP methods: * **`list_tools_mcp()`**: Returns `mcp.types.ListToolsResult` * **`call_tool_mcp(name, arguments)`**: Returns `mcp.types.CallToolResult` * **`list_resources_mcp()`**: Returns `mcp.types.ListResourcesResult` * **`list_resource_templates_mcp()`**: Returns `mcp.types.ListResourceTemplatesResult` * **`read_resource_mcp(uri)`**: Returns `mcp.types.ReadResourceResult` * **`list_prompts_mcp()`**: Returns `mcp.types.ListPromptsResult` * **`get_prompt_mcp(name, arguments)`**: Returns `mcp.types.GetPromptResult` * **`complete_mcp(ref, argument)`**: Returns `mcp.types.CompleteResult` These methods are especially useful for debugging or when you need to access metadata or fields that aren't exposed by the simplified methods. ### Additional Features #### Pinging the server The client can be used to ping the server to verify connectivity. ```python async with client: await client.ping() print("Server is reachable") ``` #### Timeouts You can control request timeouts at both the client level and individual request level: ```python from fastmcp import Client from fastmcp.exceptions import McpError # Client with a global 5-second timeout for all requests client = Client( my_mcp_server, timeout=5.0 # Default timeout in seconds ) async with client: # This uses the global 5-second timeout result1 = await client.call_tool("quick_task", {"param": "value"}) # This specifies a 10-second timeout for this specific call result2 = await client.call_tool("slow_task", {"param": "value"}, timeout=10.0) try: # This will likely timeout result3 = await client.call_tool("medium_task", {"param": "value"}, timeout=0.01) except McpError as e: # Handle timeout error print(f"The task timed out: {e}") ``` Timeout behavior varies between transport types: * With **SSE** transport, the per-request (tool call) timeout **always** takes precedence, regardless of which is lower. * With **HTTP** transport, the **lower** of the two timeouts (client or tool call) takes precedence. For consistent behavior across all transports, we recommend explicitly setting timeouts at the individual tool call level when needed, rather than relying on client-level timeouts. #### Error Handling When a `call_tool` request results in an error on the server (e.g., the tool function raised an exception), the `client.call_tool()` method will raise a `fastmcp.client.ClientError`. ```python async def safe_call_tool(): async with client: try: # Assume 'divide' tool exists and might raise ZeroDivisionError result = await client.call_tool("divide", {"a": 10, "b": 0}) print(f"Result: {result}") except ClientError as e: print(f"Tool call failed: {e}") except ConnectionError as e: print(f"Connection failed: {e}") except Exception as e: print(f"An unexpected error occurred: {e}") # Example Output if division by zero occurs: # Tool call failed: Division by zero is not allowed. ``` Other errors, like connection failures, will raise standard Python exceptions (e.g., `ConnectionError`, `TimeoutError`). The client transport often has its own error-handling mechanisms, so you can not always trap errors like those raised by `call_tool` outside of the `async with` block. Instead, you can use `call_tool_mcp()` to get the raw `mcp.types.CallToolResult` object and handle errors yourself by checking its `isError` attribute. # Client Transports Source: https://gofastmcp.com/clients/transports Understand the different ways FastMCP Clients can connect to servers. export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; The FastMCP `Client` relies on a `ClientTransport` object to handle the specifics of connecting to and communicating with an MCP server. FastMCP provides several built-in transport implementations for common connection methods. While the `Client` often infers the correct transport automatically (see [Client Overview](/clients/client#transport-inference)), you can also instantiate transports explicitly for more control. Clients are lightweight objects, so don't hesitate to create new ones as needed. However, be mindful of the context management - each time you open a client context (`async with client:`), a new connection or process starts. For best performance, keep client contexts open while performing multiple operations rather than repeatedly opening and closing them. ## Choosing a Transport Choose the transport that best fits your use case: * **Connecting to Remote/Persistent Servers:** Use `StreamableHttpTransport` (recommended, default for HTTP URLs) or `SSETransport` (legacy option) for web-based deployments. * **Local Development/Testing:** Use `FastMCPTransport` for in-memory, same-process testing of your FastMCP servers. * **Running Local Servers:** Use `UvxStdioTransport` (Python/uv) or `NpxStdioTransport` (Node/npm) if you need to run MCP servers as packaged tools. ## Network Transports These transports connect to servers running over a network, typically long-running services accessible via URLs. ### Streamable HTTP Streamable HTTP is the recommended transport for web-based deployments, providing efficient bidirectional communication over HTTP. #### Overview * **Class:** `fastmcp.client.transports.StreamableHttpTransport` * **Inferred From:** URLs starting with `http://` or `https://` (default for HTTP URLs since v2.3.0) that do not contain `/sse/` in the path * **Server Compatibility:** Works with FastMCP servers running in `streamable-http` mode #### Basic Usage The simplest way to use Streamable HTTP is to let the transport be inferred from a URL: ```python from fastmcp import Client import asyncio # The Client automatically uses StreamableHttpTransport for HTTP URLs client = Client("https://example.com/mcp") async def main(): async with client: tools = await client.list_tools() print(f"Available tools: {tools}") asyncio.run(main()) ``` You can also explicitly instantiate the transport: ```python from fastmcp.client.transports import StreamableHttpTransport transport = StreamableHttpTransport(url="https://example.com/mcp") client = Client(transport) ``` #### Authentication with Headers For servers requiring authentication: ```python from fastmcp import Client from fastmcp.client.transports import StreamableHttpTransport # Create transport with authentication headers transport = StreamableHttpTransport( url="https://example.com/mcp", headers={"Authorization": "Bearer your-token-here"} ) client = Client(transport) ``` ### SSE (Server-Sent Events) Server-Sent Events (SSE) is a transport that allows servers to push data to clients over HTTP connections. While still supported, Streamable HTTP is now the recommended transport for new web-based deployments. #### Overview * **Class:** `fastmcp.client.transports.SSETransport` * **Inferred From:** HTTP URLs containing `/sse/` in the path * **Server Compatibility:** Works with FastMCP servers running in `sse` mode #### Basic Usage The simplest way to use SSE is to let the transport be inferred from a URL with `/sse/` in the path: ```python from fastmcp import Client import asyncio # The Client automatically uses SSETransport for URLs containing /sse/ in the path client = Client("https://example.com/sse") async def main(): async with client: tools = await client.list_tools() print(f"Available tools: {tools}") asyncio.run(main()) ``` You can also explicitly instantiate the transport for URLs that do not contain `/sse/` in the path or for more control: ```python from fastmcp.client.transports import SSETransport transport = SSETransport(url="https://example.com/sse") client = Client(transport) ``` #### Authentication with Headers SSE transport also supports custom headers for authentication: ```python from fastmcp import Client from fastmcp.client.transports import SSETransport # Create SSE transport with authentication headers transport = SSETransport( url="https://example.com/sse", headers={"Authorization": "Bearer your-token-here"} ) client = Client(transport) ``` #### When to Use SSE vs. Streamable HTTP * **Use Streamable HTTP when:** * Setting up new deployments (recommended default) * You need bidirectional streaming * You're connecting to FastMCP servers running in `streamable-http` mode * **Use SSE when:** * Connecting to legacy FastMCP servers running in `sse` mode * Working with infrastructure optimized for Server-Sent Events ## Local Transports 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. ### Python Stdio * **Class:** `fastmcp.client.transports.PythonStdioTransport` * **Inferred From:** Paths to `.py` files * **Use Case:** Running a Python-based MCP server script in a subprocess This is the most common way to interact with local FastMCP servers during development or when integrating with tools that expect to launch a server script. ```python from fastmcp import Client from fastmcp.client.transports import PythonStdioTransport server_script = "my_mcp_server.py" # Path to your server script # Option 1: Inferred transport client = Client(server_script) # Option 2: Explicit transport with custom configuration transport = PythonStdioTransport( script_path=server_script, python_cmd="/usr/bin/python3.11", # Optional: specify Python interpreter # args=["--some-server-arg"], # Optional: pass arguments to the script # env={"MY_VAR": "value"}, # Optional: set environment variables ) client = Client(transport) async def main(): async with client: tools = await client.list_tools() print(f"Connected via Python Stdio, found tools: {tools}") asyncio.run(main()) ``` The server script must include logic to start the MCP server and listen on stdio, typically via `mcp.run()` or `fastmcp.server.run()`. The Client only launches the script; it doesn't inject the server logic. ### Node.js Stdio * **Class:** `fastmcp.client.transports.NodeStdioTransport` * **Inferred From:** Paths to `.js` files * **Use Case:** Running a Node.js-based MCP server script in a subprocess Similar to the Python transport, but for JavaScript servers. ```python from fastmcp import Client from fastmcp.client.transports import NodeStdioTransport node_server_script = "my_mcp_server.js" # Path to your Node.js server script # Option 1: Inferred transport client = Client(node_server_script) # Option 2: Explicit transport transport = NodeStdioTransport( script_path=node_server_script, node_cmd="node" # Optional: specify path to Node executable ) client = Client(transport) async def main(): async with client: tools = await client.list_tools() print(f"Connected via Node.js Stdio, found tools: {tools}") asyncio.run(main()) ``` ### UVX Stdio (Experimental) * **Class:** `fastmcp.client.transports.UvxStdioTransport` * **Inferred From:** Not automatically inferred * **Use Case:** Running an MCP server packaged as a Python tool using [`uvx`](https://docs.astral.sh/uv/reference/cli/#uvx) This is useful for executing MCP servers distributed as command-line tools or packages without installing them into your environment. ```python from fastmcp import Client from fastmcp.client.transports import UvxStdioTransport # Run a hypothetical 'cloud-analyzer-mcp' tool via uvx transport = UvxStdioTransport( tool_name="cloud-analyzer-mcp", # from_package="cloud-analyzer-cli", # Optional: specify package if tool name differs # with_packages=["boto3", "requests"] # Optional: add dependencies ) client = Client(transport) async def main(): async with client: result = await client.call_tool("analyze_bucket", {"name": "my-data"}) print(f"Analysis result: {result}") asyncio.run(main()) ``` ### NPX Stdio (Experimental) * **Class:** `fastmcp.client.transports.NpxStdioTransport` * **Inferred From:** Not automatically inferred * **Use Case:** Running an MCP server packaged as an NPM package using `npx` Similar to `UvxStdioTransport`, but for the Node.js ecosystem. ```python from fastmcp import Client from fastmcp.client.transports import NpxStdioTransport # Run an MCP server from an NPM package transport = NpxStdioTransport( package="mcp-server-package", # args=["--port", "stdio"] # Optional: pass arguments to the package ) client = Client(transport) async def main(): async with client: result = await client.call_tool("get_npm_data", {}) print(f"Result: {result}") asyncio.run(main()) ``` ## In-Memory Transports ### FastMCP Transport * **Class:** `fastmcp.client.transports.FastMCPTransport` * **Inferred From:** An instance of `fastmcp.server.FastMCP` or a **FastMCP 1.0 server** (`mcp.server.fastmcp.FastMCP`) * **Use Case:** Connecting directly to a FastMCP server instance in the same Python process This is extremely useful for testing your FastMCP servers. ```python from fastmcp import FastMCP, Client import asyncio # 1. Create your FastMCP server instance server = FastMCP(name="InMemoryServer") @server.tool() def ping(): return "pong" # 2. Create a client pointing directly to the server instance client = Client(server) # Transport is automatically inferred async def main(): async with client: result = await client.call_tool("ping") print(f"In-memory call result: {result}") asyncio.run(main()) ``` Communication happens through efficient in-memory queues, making it very fast and ideal for unit testing. ## Configuration-Based Transports ### MCPConfig Transport * **Class:** `fastmcp.client.transports.MCPConfigTransport` * **Inferred From:** An instance of `MCPConfig` or a dictionary matching the MCPConfig schema * **Use Case:** Connecting to one or more MCP servers defined in a configuration object MCPConfig follows an emerging standard for MCP server configuration but is subject to change as the specification evolves. The standard supports both local servers (running via stdio) and remote servers (accessed via HTTP). ```python from fastmcp import Client # Configuration for multiple MCP servers (both local and remote) config = { "mcpServers": { # Remote HTTP server "weather": { "url": "https://weather-api.example.com/mcp", "transport": "streamable-http" }, # Local stdio server "assistant": { "command": "python", "args": ["./assistant_server.py"], "env": {"DEBUG": "true"} }, # Another remote server "calendar": { "url": "https://calendar-api.example.com/mcp", "transport": "streamable-http" } } } # Create a transport from the config (happens automatically with Client) client = Client(config) async def main(): async with client: # Tools are accessible with server name prefixes weather = await client.call_tool("weather_get_forecast", {"city": "London"}) answer = await client.call_tool("assistant_answer_question", {"query": "What is MCP?"}) events = await client.call_tool("calendar_list_events", {"date": "2023-06-01"}) # Resources use prefixed URI paths icons = await client.read_resource("weather://weather/icons/sunny") docs = await client.read_resource("resource://assistant/docs/mcp") asyncio.run(main()) ``` If your configuration has only a single server, the client will connect directly to that server without any prefixing. This makes it convenient to switch between single and multi-server configurations without changing your client code. The MCPConfig format is an emerging standard for MCP server configuration and may change as the MCP ecosystem evolves. While FastMCP aims to maintain compatibility with future versions, be aware that field names or structure might change. # Integrating FastMCP in ASGI Applications Source: https://gofastmcp.com/deployment/asgi Integrate FastMCP servers into existing Starlette, FastAPI, or other ASGI applications export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; While FastMCP provides standalone server capabilities, you can also integrate your FastMCP server into existing web applications. This approach is useful for: * Adding MCP functionality to an existing website or API * Mounting MCP servers under specific URL paths * Combining multiple services in a single application * Leveraging existing authentication and middleware Please note that all FastMCP servers have a `run()` method that can be used to start the server. This guide focuses on integration with broader ASGI frameworks. ## ASGI Server FastMCP servers can be created as [Starlette](https://www.starlette.io/) ASGI apps for straightforward hosting or integration into existing applications. The first step is to obtain a Starlette application instance from your FastMCP server using the `http_app()` method: The `http_app()` method is new in FastMCP 2.3.2. In older versions, use `sse_app()` for SSE transport or `streamable_http_app()` for Streamable HTTP transport. ```python from fastmcp import FastMCP mcp = FastMCP("MyServer") @mcp.tool() def hello(name: str) -> str: return f"Hello, {name}!" # Get a Starlette app instance for Streamable HTTP transport (recommended) http_app = mcp.http_app() # For legacy SSE transport (deprecated) sse_app = mcp.http_app(transport="sse") ``` Both approaches return a Starlette application that can be integrated with other ASGI-compatible web frameworks. The returned app stores the `FastMCP` instance on `app.state.fastmcp_server`, so you can access it from custom middleware or routes via `request.app.state.fastmcp_server`. The MCP server's endpoint is mounted at the root path `/mcp` for Streamable HTTP transport, and `/sse` for SSE transport, though you can change these paths by passing a `path` argument to the `http_app()` method: ```python # For Streamable HTTP transport http_app = mcp.http_app(path="/custom-mcp-path") # For SSE transport (deprecated) sse_app = mcp.http_app(path="/custom-sse-path", transport="sse") ``` ### Running the Server To run the FastMCP server, you can use the `uvicorn` ASGI server: ```python from fastmcp import FastMCP import uvicorn mcp = FastMCP("MyServer") http_app = mcp.http_app() if __name__ == "__main__": uvicorn.run(http_app, host="0.0.0.0", port=8000) ``` Or, from the command line: ```bash uvicorn path.to.your.app:http_app --host 0.0.0.0 --port 8000 ``` ### Custom Middleware You can add custom Starlette middleware to your FastMCP ASGI apps by passing a list of middleware instances to the app creation methods: ```python from fastmcp import FastMCP from starlette.middleware import Middleware from starlette.middleware.cors import CORSMiddleware # Create your FastMCP server mcp = FastMCP("MyServer") # Define custom middleware custom_middleware = [ Middleware(CORSMiddleware, allow_origins=["*"]), ] # Create ASGI app with custom middleware http_app = mcp.http_app(middleware=custom_middleware) ``` ## Starlette Integration You can mount your FastMCP server in another Starlette application: ```python from fastmcp import FastMCP from starlette.applications import Starlette from starlette.routing import Mount # Create your FastMCP server as well as any tools, resources, etc. mcp = FastMCP("MyServer") # Create the ASGI app mcp_app = mcp.http_app(path='/mcp') # Create a Starlette app and mount the MCP server app = Starlette( routes=[ Mount("/mcp-server", app=mcp_app), # Add other routes as needed ], lifespan=mcp_app.lifespan, ) ``` The MCP endpoint will be available at `/mcp-server/mcp` of the resulting Starlette app. For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the resulting Starlette app, as nested lifespans are not recognized. Otherwise, the FastMCP server's session manager will not be properly initialized. ### Nested Mounts You can create complex routing structures by nesting mounts: ```python from fastmcp import FastMCP from starlette.applications import Starlette from starlette.routing import Mount # Create your FastMCP server as well as any tools, resources, etc. mcp = FastMCP("MyServer") # Create the ASGI app mcp_app = mcp.http_app(path='/mcp') # Create nested application structure inner_app = Starlette(routes=[Mount("/inner", app=mcp_app)]) app = Starlette( routes=[Mount("/outer", app=inner_app)], lifespan=mcp_app.lifespan, ) ``` In this setup, the MCP server is accessible at the `/outer/inner/mcp` path of the resulting Starlette app. For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the *outer* Starlette app, as nested lifespans are not recognized. Otherwise, the FastMCP server's session manager will not be properly initialized. ## FastAPI Integration FastAPI is built on Starlette, so you can mount your FastMCP server in a similar way: ```python from fastmcp import FastMCP from fastapi import FastAPI from starlette.routing import Mount # Create your FastMCP server as well as any tools, resources, etc. mcp = FastMCP("MyServer") # Create the ASGI app mcp_app = mcp.http_app(path='/mcp') # Create a FastAPI app and mount the MCP server app = FastAPI(lifespan=mcp_app.lifespan) app.mount("/mcp-server", mcp_app) ``` The MCP endpoint will be available at `/mcp-server/mcp` of the resulting FastAPI app. For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the resulting FastAPI app, as nested lifespans are not recognized. Otherwise, the FastMCP server's session manager will not be properly initialized. ## Custom Routes In addition to adding your FastMCP server to an existing ASGI app, you can also add custom web routes to your FastMCP server, which will be exposed alongside the MCP endpoint. To do so, use the `@custom_route` decorator. Note that this is less flexible than using a full ASGI framework, but can be useful for adding simple endpoints like health checks to your standalone server. ```python from fastmcp import FastMCP from starlette.requests import Request from starlette.responses import PlainTextResponse mcp = FastMCP("MyServer") @mcp.custom_route("/health", methods=["GET"]) async def health_check(request: Request) -> PlainTextResponse: return PlainTextResponse("OK") ``` These routes will be included in the FastMCP app when mounted in your web application. # Authentication Source: https://gofastmcp.com/deployment/authentication Secure your FastMCP server with authentication. export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; This document will cover how to implement authentication for your FastMCP servers. FastMCP leverages the OAuth 2.0 support provided by the underlying Model Context Protocol (MCP) SDK. For now, refer to the [MCP Server Authentication documentation](/servers/fastmcp#authentication) for initial details and the [official MCP SDK documentation](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization) for more. # FastMCP CLI Source: https://gofastmcp.com/deployment/cli Learn how to use the FastMCP command-line interface export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; FastMCP provides a command-line interface (CLI) that makes it easy to run, develop, and install your MCP servers. The CLI is automatically installed when you install FastMCP. ```bash fastmcp --help ``` ## Commands Overview | Command | Purpose | Dependency Management | | --------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `run` | Run a FastMCP server directly | Uses your current environment; you are responsible for ensuring all dependencies are available | | `dev` | Run a server with the MCP Inspector for testing | Creates an isolated environment; dependencies must be explicitly specified with `--with` and/or `--with-editable` | | `install` | Install a server in the Claude desktop app | Creates an isolated environment; dependencies must be explicitly specified with `--with` and/or `--with-editable` | | `version` | Display version information | N/A | ## Command Details ### `run` Run a FastMCP server directly or proxy a remote server. ```bash fastmcp run server.py ``` This command runs the server directly in your current Python environment. You are responsible for ensuring all dependencies are available. #### Options | Option | Flag | Description | | --------- | ------------------- | ---------------------------------------------------------------- | | Transport | `--transport`, `-t` | Transport protocol to use (`stdio`, `streamable-http`, or `sse`) | | Host | `--host` | Host to bind to when using http transport (default: 127.0.0.1) | | Port | `--port`, `-p` | Port to bind to when using http transport (default: 8000) | | Log Level | `--log-level`, `-l` | Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) | #### Server Specification The server can be specified in three ways: 1. `server.py` - imports the module and looks for a FastMCP object named `mcp`, `server`, or `app`. Errors if no such object is found. 2. `server.py:custom_name` - imports and uses the specified server object 3. `http://server-url/path` or `https://server-url/path` - connects to a remote server and creates a proxy When using `fastmcp run` with a local file, it **ignores** the `if __name__ == "__main__"` block entirely. Instead, it finds your server object and calls its `run()` method directly with the transport options you specify. This means you can use `fastmcp run` to override the transport specified in your code. For example, if your code contains: ```python # server.py from fastmcp import FastMCP mcp = FastMCP("MyServer") @mcp.tool() def hello(name: str) -> str: return f"Hello, {name}!" if __name__ == "__main__": # This is ignored when using `fastmcp run`! mcp.run(transport="stdio") ``` You can run it with Streamable HTTP transport regardless of what's in the `__main__` block: ```bash fastmcp run server.py --transport streamable-http --port 8000 ``` **Examples** ```bash # Run a local server with Streamable HTTP transport on a custom port fastmcp run server.py --transport streamable-http --port 8000 # Connect to a remote server and proxy as a stdio server fastmcp run https://example.com/mcp-server # Connect to a remote server with specified log level fastmcp run https://example.com/mcp-server --log-level DEBUG ``` ### `dev` Run a MCP server with the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) for testing. ```bash fastmcp dev server.py ``` This command runs your server in an isolated environment. All dependencies must be explicitly specified using the `--with` and/or `--with-editable` options. The `dev` command is a shortcut for testing a server over STDIO only. When the Inspector launches, you may need to: 1. Select "STDIO" from the transport dropdown 2. Connect manually This command does not support HTTP testing. To test a server over HTTP: 1. Start your server manually with HTTP transport using either: ```bash fastmcp run server.py --transport streamable-http ``` or ```bash python server.py # Assuming your __main__ block sets HTTP transport ``` 2. Open the MCP Inspector separately and connect to your running server #### Options | Option | Flag | Description | | ------------------- | ----------------------- | --------------------------------------------------------------- | | Editable Package | `--with-editable`, `-e` | Directory containing pyproject.toml to install in editable mode | | Additional Packages | `--with` | Additional packages to install (can be used multiple times) | | Inspector Version | `--inspector-version` | Version of the MCP Inspector to use | | UI Port | `--ui-port` | Port for the MCP Inspector UI | | Server Port | `--server-port` | Port for the MCP Inspector Proxy server | **Example** ```bash # Run dev server with editable mode and additional packages fastmcp dev server.py -e . --with pandas --with matplotlib ``` ### `install` Install a MCP server in the Claude desktop app. ```bash fastmcp install server.py ``` This command installs your server in an isolated environment. All dependencies must be explicitly specified using the `--with` and/or `--with-editable` options. 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. #### Options | Option | Flag | Description | | --------------------- | ----------------------- | ---------------------------------------------------------------------- | | Server Name | `--name`, `-n` | Custom name for the server | | Editable Package | `--with-editable`, `-e` | Directory containing pyproject.toml to install in editable mode | | Additional Packages | `--with` | Additional packages to install (can be used multiple times) | | Environment Variables | `--env-var`, `-v` | Environment variables in KEY=VALUE format (can be used multiple times) | | Environment File | `--env-file`, `-f` | Load environment variables from a .env file | **Example** ```bash # Install server with custom name, dependencies, and environment variables fastmcp install server.py -n "My Analysis Server" -e . --with pandas --env-var API_KEY=12345 ``` ### `version` Display version information about FastMCP and related components. ```bash fastmcp version ``` # Running Your FastMCP Server Source: https://gofastmcp.com/deployment/running-server Learn how to run and deploy your FastMCP server using various transport protocols like STDIO, Streamable HTTP, and SSE. export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; FastMCP servers can be run in different ways depending on your application's needs, from local command-line tools to persistent web services. This guide covers the primary methods for running your server, focusing on the available transport protocols: STDIO, Streamable HTTP, and SSE. ## The `run()` Method FastMCP servers can be run directly from Python by calling the `run()` method on a `FastMCP` instance. For maximum compatibility, it's best practice to place the `run()` call within an `if __name__ == "__main__":` block. This ensures the server starts only when the script is executed directly, not when imported as a module. ```python {9-10} my_server.py from fastmcp import FastMCP mcp = FastMCP(name="MyServer") @mcp.tool() def hello(name: str) -> str: return f"Hello, {name}!" if __name__ == "__main__": mcp.run() ``` You can now run this MCP server by executing `python my_server.py`. MCP servers can be run with a variety of different transport options, depending on your application's requirements. The `run()` method can take a `transport` argument and other transport-specific keyword arguments to configure how the server operates. ## The FastMCP CLI FastMCP also provides a command-line interface for running servers without modifying the source code. After installing FastMCP, you can run your server directly from the command line: ```bash fastmcp run server.py ``` **Important**: When using `fastmcp run`, it **ignores** the `if __name__ == "__main__"` block entirely. Instead, it looks for a FastMCP object named `mcp`, `server`, or `app` and calls its `run()` method directly with the transport options you specify. This means you can use `fastmcp run` to override the transport specified in your code, which is particularly useful for testing or changing deployment methods without modifying the code. You can specify transport options and other configuration: ```bash fastmcp run server.py --transport sse --port 9000 ``` For development and testing, you can use the `dev` command to run your server with the MCP Inspector: ```bash fastmcp dev server.py ``` See the [CLI documentation](/deployment/cli) for detailed information about all available commands and options. ## Transport Options Below is a comparison of available transport options to help you choose the right one for your needs: | Transport | Use Cases | Recommendation | | ------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------- | | **STDIO** | Local tools, command-line scripts, and integrations with clients like Claude Desktop | Best for local tools and when clients manage server processes | | **Streamable HTTP** | Web-based deployments, microservices, exposing MCP over a network | Recommended choice for web-based deployments | | **SSE** | Existing web-based deployments that rely on SSE | Deprecated - prefer Streamable HTTP for new projects | ### STDIO The STDIO transport is the default and most widely compatible option for local MCP server execution. It is ideal for local tools, command-line integrations, and clients like Claude Desktop. However, it has the disadvantage of having to run the MCP code locally, which can introduce security concerns with third-party servers. STDIO is the default transport, so you don't need to specify it when calling `run()`. However, you can specify it explicitly to make your intent clear: ```python {6} from fastmcp import FastMCP mcp = FastMCP() if __name__ == "__main__": mcp.run(transport="stdio") ``` When using Stdio transport, you will typically *not* run the server yourself as a separate process. Rather, your *clients* will spin up a new server process for each session. As such, no additional configuration is required. ### Streamable HTTP Streamable HTTP is a modern, efficient transport for exposing your MCP server via HTTP. It is the recommended transport for web-based deployments. To run a server using Streamable HTTP, you can use the `run()` method with the `transport` argument set to `"streamable-http"`. This will start a Uvicorn server on the default host (`127.0.0.1`), port (`8000`), and path (`/mcp`). ```python {6} server.py from fastmcp import FastMCP mcp = FastMCP() if __name__ == "__main__": mcp.run(transport="streamable-http") ``` ```python {5} client.py import asyncio from fastmcp import Client async def example(): async with Client("http://127.0.0.1:8000/mcp") as client: await client.ping() if __name__ == "__main__": asyncio.run(example()) ``` To customize the host, port, path, or log level, provide appropriate keyword arguments to the `run()` method. ```python {8-11} server.py from fastmcp import FastMCP mcp = FastMCP() if __name__ == "__main__": mcp.run( transport="streamable-http", host="127.0.0.1", port=4200, path="/my-custom-path", log_level="debug", ) ``` ```python {5} client.py import asyncio from fastmcp import Client async def example(): async with Client("http://127.0.0.1:4200/my-custom-path") as client: await client.ping() if __name__ == "__main__": asyncio.run(example()) ``` ### SSE The SSE transport is deprecated and may be removed in a future version. New applications should use Streamable HTTP transport instead. Server-Sent Events (SSE) is an HTTP-based protocol for server-to-client streaming. While FastMCP still supports SSE, it is deprecated and Streamable HTTP is preferred for new projects. To run a server using SSE, you can use the `run()` method with the `transport` argument set to `"sse"`. This will start a Uvicorn server on the default host (`127.0.0.1`), port (`8000`), and with default SSE path (`/sse`) and message path (`/messages/`). ```python {6} server.py from fastmcp import FastMCP mcp = FastMCP() if __name__ == "__main__": mcp.run(transport="sse") ``` ```python {3,7} client.py import asyncio from fastmcp import Client from fastmcp.client.transports import SSETransport async def example(): async with Client( transport=SSETransport("http://127.0.0.1:8000/sse") ) as client: await client.ping() if __name__ == "__main__": asyncio.run(example()) ``` Notice that the client in the above example uses an explicit `SSETransport` to connect to the server. FastMCP will attempt to infer the appropriate transport from the provided configuration, but HTTP URLs are assumed to be Streamable HTTP (as of FastMCP 2.3.0). To customize the host, port, or log level, provide appropriate keyword arguments to the `run()` method. You can also adjust the SSE path (which clients should connect to) and the message POST endpoint (which clients use to send subsequent messages). ```python {8-12} server.py from fastmcp import FastMCP mcp = FastMCP() if __name__ == "__main__": mcp.run( transport="sse", host="127.0.0.1", port=4200, log_level="debug", path="/my-custom-sse-path", ) ``` ```python {7} client.py import asyncio from fastmcp import Client from fastmcp.client.transports import SSETransport async def example(): async with Client( transport=SSETransport("http://127.0.0.1:4200/my-custom-sse-path") ) as client: await client.ping() if __name__ == "__main__": asyncio.run(example()) ``` ## Async Usage FastMCP provides both synchronous and asynchronous APIs for running your server. The `run()` method seen in previous examples is a synchronous method that internally uses `anyio.run()` to run the asynchronous server. For applications that are already running in an async context, FastMCP provides the `run_async()` method. ```python {10-12} from fastmcp import FastMCP import asyncio mcp = FastMCP(name="MyServer") @mcp.tool() def hello(name: str) -> str: return f"Hello, {name}!" async def main(): # Use run_async() in async contexts await mcp.run_async(transport="streamable-http") if __name__ == "__main__": asyncio.run(main()) ``` The `run()` method cannot be called from inside an async function because it already creates its own async event loop internally. If you attempt to call `run()` from inside an async function, you'll get an error about the event loop already running. Always use `run_async()` inside async functions and `run()` in synchronous contexts. Both `run()` and `run_async()` accept the same transport arguments, so all the examples above apply to both methods. ## Custom Routes You can also add custom web routes to your FastMCP server, which will be exposed alongside the MCP endpoint. To do so, use the `@custom_route` decorator. Note that this is less flexible than using a full ASGI framework, but can be useful for adding simple endpoints like health checks to your standalone server. ```python from fastmcp import FastMCP from starlette.requests import Request from starlette.responses import PlainTextResponse mcp = FastMCP("MyServer") @mcp.custom_route("/health", methods=["GET"]) async def health_check(request: Request) -> PlainTextResponse: return PlainTextResponse("OK") if __name__ == "__main__": mcp.run() ``` # Installation Source: https://gofastmcp.com/getting-started/installation ## Install FastMCP We recommend using [uv](https://docs.astral.sh/uv/getting-started/installation/) to install and manage FastMCP. If you plan to use FastMCP in your project, you can add it as a dependency with: ```bash uv add fastmcp ``` Alternatively, you can install it directly with `pip` or `uv pip`: ```bash uv uv pip install fastmcp ``` ```bash pip pip install fastmcp ``` ### Verify Installation To verify that FastMCP is installed correctly, you can run the following command: ```bash fastmcp version ``` You should see output like the following: ```bash $ fastmcp version FastMCP version: 0.4.2.dev41+ga077727.d20250410 MCP version: 1.6.0 Python version: 3.12.2 Platform: macOS-15.3.1-arm64-arm-64bit FastMCP root path: ~/Developer/fastmcp ``` ## Upgrading from the Official MCP SDK Upgrading from the official MCP SDK's FastMCP 1.0 to FastMCP 2.0 is generally straightforward. The core server API is highly compatible, and in many cases, changing your import statement from `from mcp.server.fastmcp import FastMCP` to `from fastmcp import FastMCP` will be sufficient. ```python {1-5} # Before # from mcp.server.fastmcp import FastMCP # After from fastmcp import FastMCP mcp = FastMCP("My MCP Server") ``` Prior to `fastmcp==2.3.0` and `mcp==1.8.0`, the 2.x API always mirrored the 1.0 API. However, as the projects diverge, this can not be guaranteed. You may see deprecation warnings if you attempt to use 1.0 APIs in FastMCP 2.x. Please refer to this documentation for details on new capabilities. ## Versioning and Breaking Changes While we make every effort not to introduce backwards-incompatible changes to our public APIs and behavior, FastMCP exists in a rapidly evolving MCP landscape. We're committed to bringing the most cutting-edge features to our users, which occasionally necessitates changes to existing functionality. As a practice, breaking changes will only occur on minor version changes (e.g., 2.3.x to 2.4.0). A minor version change indicates either: * A significant new feature set that warrants a new minor version * Introducing breaking changes that may affect behavior on upgrade For users concerned about stability in production environments, we recommend pinning FastMCP to a specific version in your dependencies. Whenever possible, FastMCP will issue deprecation warnings when users attempt to use APIs that are either deprecated or destined for future removal. These warnings will be maintained for at least 1 minor version release, and may be maintained longer. Note that the "public API" includes the core functionality of the `FastMCP` server and its methods. It does not include private methods or objects that are stored as private attributes, as we do not expect users to rely on those implementation details. ## Installing for Development If you plan to contribute to FastMCP, you should begin by cloning the repository and using uv to install all dependencies (development dependencies are installed automatically): ```bash git clone https://github.com/jlowin/fastmcp.git cd fastmcp uv sync ``` This will install all dependencies, including ones for development, and create a virtual environment, which you can activate and use as normal. ### Unit Tests FastMCP has a comprehensive unit test suite, and all PR's must introduce and pass appropriate tests. To run the tests, use pytest: ```bash pytest ``` ### Pre-Commit Hooks FastMCP uses pre-commit to manage code quality, including formatting, linting, and type-safety. All PRs must pass the pre-commit hooks, which are run as a part of the CI process. To install the pre-commit hooks, run: ```bash uv run pre-commit install ``` Alternatively, to run pre-commit manually at any time, use: ```bash pre-commit run --all-files ``` # Quickstart Source: https://gofastmcp.com/getting-started/quickstart Welcome! This guide will help you quickly set up FastMCP and run your first MCP server. If you haven't already installed FastMCP, follow the [installation instructions](/getting-started/installation). ## Creating a FastMCP Server A FastMCP server is a collection of tools, resources, and other MCP components. To create a server, start by instantiating the `FastMCP` class. Create a new file called `my_server.py` and add the following code: ```python my_server.py from fastmcp import FastMCP mcp = FastMCP("My MCP Server") ``` That's it! You've created a FastMCP server, albeit a very boring one. Let's add a tool to make it more interesting. ## Adding a Tool To add a tool that returns a simple greeting, write a function and decorate it with `@mcp.tool` to register it with the server: ```python my_server.py {5-7} from fastmcp import FastMCP mcp = FastMCP("My MCP Server") @mcp.tool() def greet(name: str) -> str: return f"Hello, {name}!" ``` ## Testing the Server To test the server, create a FastMCP client and point it at the server object. ```python my_server.py {1-2, 10-17} import asyncio from fastmcp import FastMCP, Client mcp = FastMCP("My MCP Server") @mcp.tool() def greet(name: str) -> str: return f"Hello, {name}!" client = Client(mcp) async def call_tool(name: str): async with client: result = await client.call_tool("greet", {"name": name}) print(result) asyncio.run(call_tool("Ford")) ``` There are a few things to note here: * Clients are asynchronous, so we need to use `asyncio.run` to run the client. * We must enter a client context (`async with client:`) before using the client. You can make multiple client calls within the same context. ## Running the server In order to run the server with Python, we need to add a `run` statement to the `__main__` block of the server file. ```python my_server.py {9-10} from fastmcp import FastMCP mcp = FastMCP("My MCP Server") @mcp.tool() def greet(name: str) -> str: return f"Hello, {name}!" if __name__ == "__main__": mcp.run() ``` This lets us run the server with `python my_server.py`, using the default `stdio` transport, which is the standard way to expose an MCP server to a client. Why do we need the `if __name__ == "__main__":` block? Within the FastMCP ecosystem, this line may be unnecessary. However, including it ensures that your FastMCP server runs for all users and clients in a consistent way and is therefore recommended as best practice. ### Interacting with the Python server Now that the server can be executed with `python my_server.py`, we can interact with it like any other MCP server. In a new file, create a client and point it at the server file: ```python my_client.py import asyncio from fastmcp import Client client = Client("my_server.py") async def call_tool(name: str): async with client: result = await client.call_tool("greet", {"name": name}) print(result) asyncio.run(call_tool("Ford")) ``` ### Using the FastMCP CLI To have FastMCP run the server for us, we can use the `fastmcp run` command. This will start the server and keep it running until it is stopped. By default, it will use the `stdio` transport, which is a simple text-based protocol for interacting with the server. ```bash fastmcp run my_server.py:mcp ``` Note that FastMCP *does not* require the `__main__` block in the server file, and will ignore it if it is present. Instead, it looks for the server object provided in the CLI command (here, `mcp`). If no server object is provided, `fastmcp run` will automatically search for servers called "mcp", "app", or "server" in the file. We pointed our client at the server file, which is recognized as a Python MCP server and executed with `python my_server.py` by default. This executes the `__main__` block of the server file. There are other ways to run the server, which are described in the [server configuration](/servers/fastmcp#running-the-server) guide. # Welcome to FastMCP 2.0! Source: https://gofastmcp.com/getting-started/welcome The fast, Pythonic way to build MCP servers and clients. The [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) is a new, standardized way to provide context and tools to your LLMs, and FastMCP makes building MCP servers and clients simple and intuitive. Create tools, expose resources, define prompts, and more with clean, Pythonic code: ```python {1, 3, 5, 11} from fastmcp import FastMCP mcp = FastMCP("Demo 🚀") @mcp.tool() def add(a: int, b: int) -> int: """Add two numbers""" return a + b if __name__ == "__main__": mcp.run() ``` ## FastMCP 2.0 and the Official MCP SDK Recognize the `FastMCP` name? You might have seen the version that was contributed to the [official MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk), which was based on **FastMCP 1.0**. **Welcome to FastMCP 2.0!** This is the [actively developed successor](https://github.com/jlowin/fastmcp), and it significantly expands on 1.0 by introducing powerful client capabilities, server proxying & composition, OpenAPI/FastAPI integration, and more advanced features. FastMCP 2.0 is the recommended path for building modern, powerful MCP applications. Ready to upgrade or get started? Follow the [installation instructions](/getting-started/installation), which include specific steps for upgrading. ## What is MCP? The Model Context Protocol lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. It is often described as "the USB-C port for AI", providing a uniform way to connect LLMs to resources they can use. It may be easier to think of it as an API, but specifically designed for LLM interactions. MCP servers can: * Expose data through `Resources` (think of these sort of like GET endpoints; they are used to load information into the LLM's context) * Provide functionality through `Tools` (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect) * Define interaction patterns through `Prompts` (reusable templates for LLM interactions) * And more! There is a low-level Python SDK available for implementing the protocol directly, but FastMCP aims to make that easier by providing a high-level, Pythonic interface. ## Why FastMCP? The MCP protocol is powerful but implementing it involves a lot of boilerplate - server setup, protocol handlers, content types, error management. FastMCP handles all the complex protocol details and server management, so you can focus on building great tools. It's designed to be high-level and Pythonic; in most cases, decorating a function is all you need. While the core server concepts of FastMCP 1.0 laid the groundwork and were contributed to the official MCP SDK, FastMCP 2.0 (this project) is the actively developed successor, adding significant enhancements and entirely new capabilities like a powerful client library, server proxying, composition patterns, and much more. FastMCP aims to be: 🚀 **Fast**: High-level interface means less code and faster development 🍀 **Simple**: Build MCP servers with minimal boilerplate 🐍 **Pythonic**: Feels natural to Python developers 🔍 **Complete**: FastMCP aims to provide a full implementation of the core MCP specification ## `llms.txt` This documentation is also available in [llms.txt format](https://llmstxt.org/), which is a simple markdown standard that LLMs can consume easily. There are two ways to access the LLM-friendly documentation: * [`llms.txt`](https://gofastmcp.com/llms.txt) is essentially a sitemap, listing all the pages in the documentation. * [`llms-full.txt`](https://gofastmcp.com/llms-full.txt) contains the entire documentation. Note this may exceed the context window of your LLM. # Contrib Modules Source: https://gofastmcp.com/patterns/contrib Community-contributed modules extending FastMCP export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; FastMCP includes a `contrib` package that holds community-contributed modules. These modules extend FastMCP's functionality but aren't officially maintained by the core team. Contrib modules provide additional features, integrations, or patterns that complement the core FastMCP library. They offer a way for the community to share useful extensions while keeping the core library focused and maintainable. The available modules can be viewed in the [contrib directory](https://github.com/jlowin/fastmcp/tree/main/src/contrib). ## Usage To use a contrib module, import it from the `fastmcp.contrib` package: ```python from fastmcp.contrib import my_module ``` ## Important Considerations * **Stability**: Modules in `contrib` may have different testing requirements or stability guarantees compared to the core library. * **Compatibility**: Changes to core FastMCP might break modules in `contrib` without explicit warnings in the main changelog. * **Dependencies**: Contrib modules may have additional dependencies not required by the core library. These dependencies are typically documented in the module's README or separate requirements files. ## Contributing We welcome contributions to the `contrib` package! If you have a module that extends FastMCP in a useful way, consider contributing it: 1. Create a new directory in `src/fastmcp/contrib/` for your module 2. Add proper tests for your module in `tests/contrib/` 3. Include comprehensive documentation in a README.md file, including usage and examples, as well as any additional dependencies or installation instructions 4. Submit a pull request The ideal contrib module: * Solves a specific use case or integration need * Follows FastMCP coding standards * Includes thorough documentation and examples * Has comprehensive tests * Specifies any additional dependencies # Decorating Methods Source: https://gofastmcp.com/patterns/decorating-methods Properly use instance methods, class methods, and static methods with FastMCP decorators. FastMCP's decorator system is designed to work with functions, but you may see unexpected behavior if you try to decorate an instance or class method. This guide explains the correct approach for using methods with all FastMCP decorators (`@tool()`, `@resource()`, and `@prompt()`). ## Why Are Methods Hard? When you apply a FastMCP decorator like `@tool()`, `@resource()`, or `@prompt()` to a method, the decorator captures the function at decoration time. For instance methods and class methods, this poses a challenge because: 1. For instance methods: The decorator gets the unbound method before any instance exists 2. For class methods: The decorator gets the function before it's bound to the class This means directly decorating these methods doesn't work as expected. In practice, the LLM would see parameters like `self` or `cls` that it cannot provide values for. ## Recommended Patterns ### Instance Methods **Don't do this** (it doesn't work properly): ```python from fastmcp import FastMCP mcp = FastMCP() class MyClass: @mcp.tool() # This won't work correctly def add(self, x, y): return x + y @mcp.resource("resource://{param}") # This won't work correctly def get_resource(self, param: str): return f"Resource data for {param}" ``` When the decorator is applied this way, it captures the unbound method. When the LLM later tries to use this component, it will see `self` as a required parameter, but it won't know what to provide for it, causing errors or unexpected behavior. **Do this instead**: ```python from fastmcp import FastMCP mcp = FastMCP() class MyClass: def add(self, x, y): return x + y def get_resource(self, param: str): return f"Resource data for {param}" # Create an instance first, then add the bound methods obj = MyClass() mcp.add_tool(obj.add) mcp.add_resource_fn(obj.get_resource, uri="resource://{param}") # For resources or templates # Note: FastMCP provides add_resource() for adding Resource objects directly and # add_resource_fn() for adding functions that generate resources or templates # Now you can call it without 'self' showing up as a parameter await mcp.call_tool('add', {'x': 1, 'y': 2}) # Returns 3 ``` This approach works because: 1. You first create an instance of the class (`obj`) 2. When you access the method through the instance (`obj.add`), Python creates a bound method where `self` is already set to that instance 3. When you register this bound method, the system sees a callable that only expects the appropriate parameters, not `self` ### Class Methods Similar to instance methods, decorating class methods directly doesn't work properly: **Don't do this**: ```python from fastmcp import FastMCP mcp = FastMCP() class MyClass: @classmethod @mcp.tool() # This won't work correctly def from_string(cls, s): return cls(s) ``` The problem here is that the FastMCP decorator is applied before the `@classmethod` decorator (Python applies decorators bottom-to-top). So it captures the function before it's transformed into a class method, leading to incorrect behavior. **Do this instead**: ```python from fastmcp import FastMCP mcp = FastMCP() class MyClass: @classmethod def from_string(cls, s): return cls(s) # Add the class method after the class is defined mcp.add_tool(MyClass.from_string) ``` This works because: 1. The `@classmethod` decorator is applied properly during class definition 2. When you access `MyClass.from_string`, Python provides a special method object that automatically binds the class to the `cls` parameter 3. When registered, only the appropriate parameters are exposed to the LLM, hiding the implementation detail of the `cls` parameter ### Static Methods Unlike instance and class methods, static methods work fine with FastMCP decorators: ```python from fastmcp import FastMCP mcp = FastMCP() class MyClass: @staticmethod @mcp.tool() # This works! def utility(x, y): return x + y @staticmethod @mcp.resource("resource://data") # This works too! def get_data(): return "Static resource data" ``` This approach works because: 1. The `@staticmethod` decorator is applied first (executed last), transforming the method into a regular function 2. When the FastMCP decorator is applied, it's capturing what is effectively just a regular function 3. A static method doesn't have any binding requirements - it doesn't receive a `self` or `cls` parameter Alternatively, you can use the same pattern as the other methods: ```python from fastmcp import FastMCP mcp = FastMCP() class MyClass: @staticmethod def utility(x, y): return x + y # This also works mcp.add_tool(MyClass.utility) ``` This works for the same reason - a static method is essentially just a function in a class namespace. ## Additional Patterns ### Creating Components at Class Initialization You can automatically register instance methods when creating an object: ```python from fastmcp import FastMCP mcp = FastMCP() class ComponentProvider: def __init__(self, mcp_instance): # Register methods mcp_instance.add_tool(self.tool_method) mcp_instance.add_resource_fn(self.resource_method, uri="resource://data") def tool_method(self, x): return x * 2 def resource_method(self): return "Resource data" # The methods are automatically registered when creating the instance provider = ComponentProvider(mcp) ``` This pattern is useful when: * You want to encapsulate registration logic within the class itself * You have multiple related components that should be registered together * You want to ensure that methods are always properly registered when creating an instance The class automatically registers its methods during initialization, ensuring they're properly bound to the instance before registration. ## Summary While FastMCP's decorator pattern works seamlessly with regular functions and static methods, for instance methods and class methods, you should add them after creating the instance or class. This ensures that the methods are properly bound before being registered. These patterns apply to all FastMCP decorators and registration methods: * `@tool()` and `add_tool()` * `@resource()` and `add_resource_fn()` * `@prompt()` and `add_prompt()` Understanding these patterns allows you to effectively organize your components into classes while maintaining proper method binding, giving you the benefits of object-oriented design without sacrificing the simplicity of FastMCP's decorator system. # FastAPI Integration Source: https://gofastmcp.com/patterns/fastapi Generate MCP servers from FastAPI apps export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; FastMCP can automatically convert FastAPI applications into MCP servers. FastMCP does *not* include FastAPI as a dependency; you must install it separately to run these examples. ```python {2, 22, 25} from fastapi import FastAPI from fastmcp import FastMCP # A FastAPI app app = FastAPI() @app.get("/items") def list_items(): return [{"id": 1, "name": "Item 1"}, {"id": 2, "name": "Item 2"}] @app.get("/items/{item_id}") def get_item(item_id: int): return {"id": item_id, "name": f"Item {item_id}"} @app.post("/items") def create_item(name: str): return {"id": 3, "name": name} # Create an MCP server from your FastAPI app mcp = FastMCP.from_fastapi(app=app) if __name__ == "__main__": mcp.run() # Start the MCP server ``` ## Configuration Options ### Timeout You can set a timeout for all API requests: ```python # Set a 5 second timeout for all requests mcp = FastMCP.from_fastapi(app=app, timeout=5.0) ``` This timeout is applied to all requests made by tools, resources, and resource templates. ## Route Mapping By default, FastMCP will map FastAPI routes to MCP components according to the following rules: | FastAPI Route Type | FastAPI Example | MCP Component | Notes | | ----------------------- | ------------------------- | ----------------- | ------------------------------------------ | | GET without path params | `@app.get("/stats")` | Resource | Simple resources for fetching data | | GET with path params | `@app.get("/users/{id}")` | Resource Template | Path parameters become template parameters | | POST, PUT, DELETE, etc. | `@app.post("/users")` | Tool | Operations that modify data | For more details on route mapping or custom mapping rules, see the [OpenAPI integration documentation](/patterns/openapi#route-mapping); FastMCP uses the same mapping rules for both FastAPI and OpenAPI integrations. ## Complete Example Here's a more detailed example with a data model: ```python [expandable] import asyncio from fastapi import FastAPI, HTTPException from pydantic import BaseModel from fastmcp import FastMCP, Client # Define your Pydantic model class Item(BaseModel): name: str price: float # Create your FastAPI app app = FastAPI() items = {} # In-memory database @app.get("/items") def list_items(): """List all items""" return list(items.values()) @app.get("/items/{item_id}") def get_item(item_id: int): """Get item by ID""" if item_id not in items: raise HTTPException(404, "Item not found") return items[item_id] @app.post("/items") def create_item(item: Item): """Create a new item""" item_id = len(items) + 1 items[item_id] = {"id": item_id, **item.model_dump()} return items[item_id] # Test your MCP server with a client async def check_mcp(mcp: FastMCP): # List the components that were created tools = await mcp.get_tools() resources = await mcp.get_resources() templates = await mcp.get_resource_templates() print( f"{len(tools)} Tool(s): {', '.join([t.name for t in tools.values()])}" ) print( f"{len(resources)} Resource(s): {', '.join([r.name for r in resources.values()])}" ) print( f"{len(templates)} Resource Template(s): {', '.join([t.name for t in templates.values()])}" ) return mcp if __name__ == "__main__": # Create MCP server from FastAPI app mcp = FastMCP.from_fastapi(app=app) asyncio.run(check_mcp(mcp)) # In a real scenario, you would run the server: mcp.run() ``` ## Benefits * **Leverage existing FastAPI apps** - No need to rewrite your API logic * **Schema reuse** - FastAPI's Pydantic models and validation are inherited * **Full feature support** - Works with FastAPI's authentication, dependencies, etc. * **ASGI transport** - Direct communication without additional HTTP overhead # HTTP Requests Source: https://gofastmcp.com/patterns/http-requests Accessing and using HTTP requests in FastMCP servers export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; ## 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" } ``` # OpenAPI Integration Source: https://gofastmcp.com/patterns/openapi Generate MCP servers from OpenAPI specs export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; FastMCP can automatically generate an MCP server from an OpenAPI specification. Users only need to provide an OpenAPI specification (3.0 or 3.1) and an API client. ```python import httpx from fastmcp import FastMCP # Create a client for your API api_client = httpx.AsyncClient(base_url="https://api.example.com") # Load your OpenAPI spec spec = {...} # Create an MCP server from your OpenAPI spec mcp = FastMCP.from_openapi(openapi_spec=spec, client=api_client) if __name__ == "__main__": mcp.run() ``` ## Configuration Options ### Timeout You can set a timeout for all API requests: ```python # Set a 5 second timeout for all requests mcp = FastMCP.from_openapi( openapi_spec=spec, client=api_client, timeout=5.0 ) ``` This timeout is applied to all requests made by tools, resources, and resource templates. ## Route Mapping By default, OpenAPI routes are mapped to MCP components based on these rules: | OpenAPI Route | Example | MCP Component | Notes | | -------------------------------------- | ----------------- | ----------------- | ------------------------------------------ | | `GET` without path params | `GET /stats` | Resource | Simple resources for fetching data | | `GET` with path params | `GET /users/{id}` | Resource Template | Path parameters become template parameters | | `POST`, `PUT`, `PATCH`, `DELETE`, etc. | `POST /users` | Tool | Operations that modify data | Internally, FastMCP uses a priority-ordered set of `RouteMap` objects to determine the component type. Route maps indicate that a specific HTTP method (or methods) and path pattern should be treated as a specific component type. This is the default set of route maps: ```python # Simplified version of the actual mapping rules DEFAULT_ROUTE_MAPPINGS = [ # GET with path parameters -> ResourceTemplate RouteMap( methods=["GET"], pattern=r".*\{.*\}.*", route_type=RouteType.RESOURCE_TEMPLATE, ), # GET without path parameters -> Resource RouteMap( methods=["GET"], pattern=r".*", route_type=RouteType.RESOURCE, ), # All other methods -> Tool RouteMap( methods="*", pattern=r".*", route_type=RouteType.TOOL, ), ] ``` ### Custom Route Maps Users can add custom route maps to override the default mapping behavior. User-supplied route maps are always applied first, before the default route maps. ```python from fastmcp.server.openapi import RouteMap, RouteType # Custom mapping rules custom_maps = [ # Force all analytics endpoints to be Tools RouteMap(methods=["GET"], pattern=r"^/analytics/.*", route_type=RouteType.TOOL) ] # Apply custom mappings mcp = await FastMCP.from_openapi( openapi_spec=spec, client=api_client, route_maps=custom_maps ) ``` ### All Routes as Tools When building AI agent backends, it's often useful to treat all routes as callable tools regardless of their HTTP method. You can use the `all_routes_as_tools` parameter to automatically map every route to a Tool: ```python # Make all endpoints tools, regardless of HTTP method mcp = FastMCP.from_openapi( openapi_spec=spec, client=api_client, all_routes_as_tools=True ) ``` This is equivalent to defining a single route map that matches all routes: ```python # Same effect as all_routes_as_tools=True mcp = FastMCP.from_openapi( openapi_spec=spec, client=api_client, route_maps=[ RouteMap(methods="*", pattern=r".*", route_type=RouteType.TOOL) ] ) ``` Note that `all_routes_as_tools` and `route_maps` cannot be used together - if you need more complex mapping rules, use `route_maps` instead. ## How It Works 1. FastMCP parses your OpenAPI spec to extract routes and schemas 2. It applies mapping rules to categorize each route 3. When an MCP client calls a tool or accesses a resource: * FastMCP constructs an HTTP request based on the OpenAPI definition * It sends the request through the provided httpx client * It translates the HTTP response to the appropriate MCP format ### Request Parameter Handling FastMCP carefully handles different types of parameters in OpenAPI requests: #### Query Parameters By default, FastMCP will only include query parameters that have non-empty values. Parameters with `None` values or empty strings (`""`) are automatically filtered out of requests. This ensures that API servers don't receive unnecessary empty parameters that might cause issues. For example, if you call a tool with these parameters: ```python await client.call_tool("search_products", { "category": "electronics", # Will be included "min_price": 100, # Will be included "max_price": None, # Will be excluded "brand": "", # Will be excluded }) ``` The resulting HTTP request will only include `category=electronics&min_price=100`. #### Path Parameters For path parameters, which are typically required by REST APIs, FastMCP filters out `None` values and checks that all required path parameters are provided. If a required path parameter is missing or `None`, an error will be raised. ```python # This will work await client.call_tool("get_product", {"product_id": 123}) # This will raise ValueError: "Missing required path parameters: {'product_id'}" await client.call_tool("get_product", {"product_id": None}) ``` ## Complete Example ```python [expandable] import asyncio import httpx from fastmcp import FastMCP # Sample OpenAPI spec for a Pet Store API petstore_spec = { "openapi": "3.0.0", "info": { "title": "Pet Store API", "version": "1.0.0", "description": "A sample API for managing pets", }, "paths": { "/pets": { "get": { "operationId": "listPets", "summary": "List all pets", "responses": {"200": {"description": "A list of pets"}}, }, "post": { "operationId": "createPet", "summary": "Create a new pet", "responses": {"201": {"description": "Pet created successfully"}}, }, }, "/pets/{petId}": { "get": { "operationId": "getPet", "summary": "Get a pet by ID", "parameters": [ { "name": "petId", "in": "path", "required": True, "schema": {"type": "string"}, } ], "responses": { "200": {"description": "Pet details"}, "404": {"description": "Pet not found"}, }, } }, }, } async def check_mcp(mcp: FastMCP): # List what components were created tools = await mcp.get_tools() resources = await mcp.get_resources() templates = await mcp.get_resource_templates() print( f"{len(tools)} Tool(s): {', '.join([t.name for t in tools.values()])}" ) # Should include createPet print( f"{len(resources)} Resource(s): {', '.join([r.name for r in resources.values()])}" ) # Should include listPets print( f"{len(templates)} Resource Template(s): {', '.join([t.name for t in templates.values()])}" ) # Should include getPet return mcp if __name__ == "__main__": # Client for the Pet Store API client = httpx.AsyncClient(base_url="https://petstore.example.com/api") # Create the MCP server mcp = FastMCP.from_openapi( openapi_spec=petstore_spec, client=client, name="PetStore" ) asyncio.run(check_mcp(mcp)) # Start the MCP server mcp.run() ``` # Testing MCP Servers Source: https://gofastmcp.com/patterns/testing Learn how to test your FastMCP servers effectively Testing your MCP servers thoroughly is essential for ensuring they work correctly when deployed. FastMCP makes this easy through a variety of testing patterns. ## In-Memory Testing The most efficient way to test an MCP server is to pass your FastMCP server instance directly to a Client. This enables in-memory testing without having to start a separate server process, which is particularly useful because managing an MCP server programmatically can be challenging. Here is an example of using a `Client` to test a server with pytest: ```python import pytest from fastmcp import FastMCP, Client @pytest.fixture def mcp_server(): server = FastMCP("TestServer") @server.tool() def greet(name: str) -> str: return f"Hello, {name}!" return server async def test_tool_functionality(mcp_server): # Pass the server directly to the Client constructor async with Client(mcp_server) as client: result = await client.call_tool("greet", {"name": "World"}) assert result[0].text == "Hello, World!" ``` This pattern creates a direct connection between the client and server, allowing you to test your server's functionality efficiently. # Server Composition Source: https://gofastmcp.com/servers/composition Combine multiple FastMCP servers into a single, larger application using mounting and importing. export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; As your MCP applications grow, you might want to organize your tools, resources, and prompts into logical modules or reuse existing server components. FastMCP supports composition through two methods: * **`import_server`**: For a one-time copy of components with prefixing (static composition). * **`mount`**: For creating a live link where the main server delegates requests to the subserver (dynamic composition). ## Why Compose Servers? * **Modularity**: Break down large applications into smaller, focused servers (e.g., a `WeatherServer`, a `DatabaseServer`, a `CalendarServer`). * **Reusability**: Create common utility servers (e.g., a `TextProcessingServer`) and mount them wherever needed. * **Teamwork**: Different teams can work on separate FastMCP servers that are later combined. * **Organization**: Keep related functionality grouped together logically. ### Importing vs Mounting The choice of importing or mounting depends on your use case and requirements. | Feature | Importing | Mounting | | -------------------- | ---------------------------------- | ------------------------------------------ | | **Method** | `FastMCP.import_server()` | `FastMCP.mount()` | | **Composition Type** | One-time copy (static) | Live link (dynamic) | | **Updates** | Changes to subserver NOT reflected | Changes to subserver immediately reflected | | **Best For** | Bundling finalized components | Modular runtime composition | ### Proxy Servers FastMCP supports [MCP proxying](/patterns/proxy), which allows you to mirror a local or remote server in a local FastMCP instance. Proxies are fully compatible with both importing and mounting. You can also create proxies from configuration dictionaries that follow the MCPConfig schema, which is useful for quickly connecting to one or more remote servers. See the [Proxy Servers documentation](/servers/proxy#configuration-based-proxies) for details on configuration-based proxying. Note that MCPConfig follows an emerging standard and its format may evolve over time. ## Importing (Static Composition) The `import_server()` method copies all components (tools, resources, templates, prompts) from one `FastMCP` instance (the *subserver*) into another (the *main server*). A `prefix` is added to avoid naming conflicts. ```python from fastmcp import FastMCP import asyncio # Define subservers weather_mcp = FastMCP(name="WeatherService") @weather_mcp.tool() def get_forecast(city: str) -> dict: """Get weather forecast.""" return {"city": city, "forecast": "Sunny"} @weather_mcp.resource("data://cities/supported") def list_supported_cities() -> list[str]: """List cities with weather support.""" return ["London", "Paris", "Tokyo"] # Define main server main_mcp = FastMCP(name="MainApp") # Import subserver async def setup(): await main_mcp.import_server("weather", weather_mcp) # Result: main_mcp now contains prefixed components: # - Tool: "weather_get_forecast" # - Resource: "data://weather/cities/supported" if __name__ == "__main__": asyncio.run(setup()) main_mcp.run() ``` ### How Importing Works When you call `await main_mcp.import_server(prefix, subserver)`: 1. **Tools**: All tools from `subserver` are added to `main_mcp` with names prefixed using `{prefix}_`. * `subserver.tool(name="my_tool")` becomes `main_mcp.tool(name="{prefix}_my_tool")`. 2. **Resources**: All resources are added with URIs prefixed in the format `protocol://{prefix}/path`. * `subserver.resource(uri="data://info")` becomes `main_mcp.resource(uri="data://{prefix}/info")`. 3. **Resource Templates**: Templates are prefixed similarly to resources. * `subserver.resource(uri="data://{id}")` becomes `main_mcp.resource(uri="data://{prefix}/{id}")`. 4. **Prompts**: All prompts are added with names prefixed using `{prefix}_`. * `subserver.prompt(name="my_prompt")` becomes `main_mcp.prompt(name="{prefix}_my_prompt")`. Note that `import_server` performs a **one-time copy** of components. Changes made to the `subserver` *after* importing **will not** be reflected in `main_mcp`. The `subserver`'s `lifespan` context is also **not** executed by the main server. ## Mounting (Live Linking) The `mount()` method creates a **live link** between the `main_mcp` server and the `subserver`. Instead of copying components, requests for components matching the `prefix` are **delegated** to the `subserver` at runtime. ```python import asyncio from fastmcp import FastMCP, Client # Define subserver dynamic_mcp = FastMCP(name="DynamicService") @dynamic_mcp.tool() def initial_tool(): """Initial tool demonstration.""" return "Initial Tool Exists" # Mount subserver (synchronous operation) main_mcp = FastMCP(name="MainAppLive") main_mcp.mount("dynamic", dynamic_mcp) # Add a tool AFTER mounting - it will be accessible through main_mcp @dynamic_mcp.tool() def added_later(): """Tool added after mounting.""" return "Tool Added Dynamically!" # Testing access to mounted tools async def test_dynamic_mount(): tools = await main_mcp.get_tools() print("Available tools:", list(tools.keys())) # Shows: ['dynamic_initial_tool', 'dynamic_added_later'] async with Client(main_mcp) as client: result = await client.call_tool("dynamic_added_later") print("Result:", result[0].text) # Shows: "Tool Added Dynamically!" if __name__ == "__main__": asyncio.run(test_dynamic_mount()) ``` ### How Mounting Works When mounting is configured: 1. **Live Link**: The parent server establishes a connection to the mounted server. 2. **Dynamic Updates**: Changes to the mounted server are immediately reflected when accessed through the parent. 3. **Prefixed Access**: The parent server uses prefixes to route requests to the mounted server. 4. **Delegation**: Requests for components matching the prefix are delegated to the mounted server at runtime. The same prefixing rules apply as with `import_server` for naming tools, resources, templates, and prompts. ### Direct vs. Proxy Mounting FastMCP supports two mounting modes: 1. **Direct Mounting** (default): The parent server directly accesses the mounted server's objects in memory. * No client lifecycle events occur on the mounted server * The mounted server's lifespan context is not executed * Communication is handled through direct method calls 2. **Proxy Mounting**: The parent server treats the mounted server as a separate entity and communicates with it through a client interface. * Full client lifecycle events occur on the mounted server * The mounted server's lifespan is executed when a client connects * Communication happens via an in-memory Client transport ```python # Direct mounting (default when no custom lifespan) main_mcp.mount("api", api_server) # Proxy mounting (preserves full client lifecycle) main_mcp.mount("api", api_server, as_proxy=True) ``` FastMCP automatically uses proxy mounting when the mounted server has a custom lifespan, but you can override this behavior with the `as_proxy` parameter. #### Interaction with Proxy Servers When using `FastMCP.as_proxy()` to create a proxy server, mounting that server will always use proxy mounting: ```python # Create a proxy for a remote server remote_proxy = FastMCP.as_proxy(Client("http://example.com/mcp")) # Mount the proxy (always uses proxy mounting) main_server.mount("remote", remote_proxy) ``` ## Resource Prefix Formats When mounting or importing servers, resource URIs are usually prefixed to avoid naming conflicts. FastMCP supports two different formats for resource prefixes: ### Path Format (Default) In path format, prefixes are added to the path component of the URI: ``` resource://prefix/path/to/resource ``` This is the default format since FastMCP 2.4. This format is recommended because it avoids issues with URI protocol restrictions (like underscores not being allowed in protocol names). ### Protocol Format (Legacy) In protocol format, prefixes are added as part of the protocol: ``` prefix+resource://path/to/resource ``` This was the default format in FastMCP before 2.4. While still supported, it's not recommended for new code as it can cause problems with prefix names that aren't valid in URI protocols. ### Configuring the Prefix Format You can configure the prefix format globally in code: ```python import fastmcp fastmcp.settings.settings.resource_prefix_format = "protocol" ``` Or via environment variable: ```bash FASTMCP_RESOURCE_PREFIX_FORMAT=protocol ``` Or per-server: ```python from fastmcp import FastMCP # Create a server that uses legacy protocol format server = FastMCP("LegacyServer", resource_prefix_format="protocol") # Create a server that uses new path format server = FastMCP("NewServer", resource_prefix_format="path") ``` When mounting or importing servers, the prefix format of the parent server is used. # MCP Context Source: https://gofastmcp.com/servers/context Access MCP capabilities like logging, progress, and resources within your MCP objects. export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; When defining FastMCP [tools](/servers/tools), [resources](/servers/resources), resource templates, or [prompts](/servers/prompts), your functions might need to interact with the underlying MCP session or access server capabilities. FastMCP provides the `Context` object for this purpose. ## What Is Context? The `Context` object provides a clean interface to access MCP features within your functions, including: * **Logging**: Send debug, info, warning, and error messages back to the client * **Progress Reporting**: Update the client on the progress of long-running operations * **Resource Access**: Read data from resources registered with the server * **LLM Sampling**: Request the client's LLM to generate text based on provided messages * **Request Information**: Access metadata about the current request * **Server Access**: When needed, access the underlying FastMCP server instance ## 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:** * The parameter name (e.g., `ctx`, `context`) doesn't matter, only the type hint `Context` is important. * The context parameter can be placed anywhere in your function's signature; it will not be exposed to MCP clients as a valid parameter. * The context is optional - functions that don't need it can omit the parameter entirely. * Context methods are async, so your function usually needs to be async as well. * 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 ```python from fastmcp import FastMCP, Context mcp = FastMCP(name="ContextDemo") @mcp.tool() async def process_file(file_uri: str, ctx: Context) -> str: """Processes a file, using context for logging and resource access.""" # Context is available as the ctx parameter return "Processed file" ``` #### Resources and Templates ```python @mcp.resource("resource://user-data") async def get_user_data(ctx: Context) -> dict: """Fetch personalized user data based on the request context.""" # Context is available as the ctx parameter return {"user_id": "example"} @mcp.resource("resource://users/{user_id}/profile") async def get_user_profile(user_id: str, ctx: Context) -> dict: """Fetch user profile with context-aware logging.""" # Context is available as the ctx parameter return {"id": user_id} ``` #### Prompts ```python @mcp.prompt() async def data_analysis_request(dataset: str, ctx: Context) -> str: """Generate a request to analyze data with contextual information.""" # Context is available as the ctx parameter return f"Please analyze the following dataset: {dataset}" ``` ### 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 Send log messages back to the MCP client. This is useful for debugging and providing visibility into function execution during a request. ```python @mcp.tool() async def analyze_data(data: list[float], ctx: Context) -> dict: """Analyze numerical data with logging.""" await ctx.debug("Starting analysis of numerical data") await ctx.info(f"Analyzing {len(data)} data points") try: result = sum(data) / len(data) await ctx.info(f"Analysis complete, average: {result}") return {"average": result, "count": len(data)} except ZeroDivisionError: await ctx.warning("Empty data list provided") return {"error": "Empty data list"} except Exception as e: await ctx.error(f"Analysis failed: {str(e)}") raise ``` **Available Logging Methods:** * **`ctx.debug(message: str)`**: Low-level details useful for debugging * **`ctx.info(message: str)`**: General information about execution * **`ctx.warning(message: str)`**: Potential issues that didn't prevent execution * **`ctx.error(message: str)`**: Errors that occurred during execution * **`ctx.log(level: Literal["debug", "info", "warning", "error"], message: str, logger_name: str | None = None)`**: Generic log method supporting custom logger names ### Progress Reporting For long-running operations, notify the client about the progress. This allows clients to display progress indicators and provide a better user experience. ```python @mcp.tool() async def process_items(items: list[str], ctx: Context) -> dict: """Process a list of items with progress updates.""" total = len(items) results = [] for i, item in enumerate(items): # Report progress as percentage await ctx.report_progress(progress=i, total=total) # Process the item (simulated with a sleep) await asyncio.sleep(0.1) results.append(item.upper()) # Report 100% completion await ctx.report_progress(progress=total, total=total) return {"processed": len(results), "results": results} ``` **Method signature:** * **`ctx.report_progress(progress: float, total: float | None = None)`** * `progress`: Current progress value (e.g., 24) * `total`: Optional total value (e.g., 100). If provided, clients may interpret this as a percentage. Progress reporting requires the client to have sent a `progressToken` in the initial request. If the client doesn't support progress reporting, these calls will have no effect. ### Resource Access Read data from resources registered with your FastMCP server. This allows functions to access files, configuration, or dynamically generated content. ```python @mcp.tool() async def summarize_document(document_uri: str, ctx: Context) -> str: """Summarize a document by its resource URI.""" # Read the document content content_list = await ctx.read_resource(document_uri) if not content_list: return "Document is empty" document_text = content_list[0].content # Example: Generate a simple summary (length-based) words = document_text.split() total_words = len(words) await ctx.info(f"Document has {total_words} words") # Return a simple summary if total_words > 100: summary = " ".join(words[:100]) + "..." return f"Summary ({total_words} words total): {summary}" else: return f"Full document ({total_words} words): {document_text}" ``` **Method signature:** * **`ctx.read_resource(uri: str | AnyUrl) -> list[ReadResourceContents]`** * `uri`: The resource URI to read * Returns a list of resource content parts (usually containing just one item) The returned content is typically accessed via `content_list[0].content` and can be text or binary data depending on the resource. ### LLM Sampling Request the client's LLM to generate text based on provided messages. This is useful when your function needs to leverage the LLM's capabilities to process data or generate responses. ```python @mcp.tool() async def analyze_sentiment(text: str, ctx: Context) -> dict: """Analyze the sentiment of a text using the client's LLM.""" # Create a sampling prompt asking for sentiment analysis prompt = f"Analyze the sentiment of the following text as positive, negative, or neutral. Just output a single word - 'positive', 'negative', or 'neutral'. Text to analyze: {text}" # Send the sampling request to the client's LLM (provide a hint for the model you want to use) response = await ctx.sample(prompt, model_preferences="claude-3-sonnet") # Process the LLM's response sentiment = response.text.strip().lower() # Map to standard sentiment values if "positive" in sentiment: sentiment = "positive" elif "negative" in sentiment: sentiment = "negative" else: sentiment = "neutral" return {"text": text, "sentiment": sentiment} ``` **Method signature:** * **`ctx.sample(messages: str | list[str | SamplingMessage], system_prompt: str | None = None, temperature: float | None = None, max_tokens: int | None = None, model_preferences: ModelPreferences | str | list[str] | None = None) -> TextContent | ImageContent`** * `messages`: A string or list of strings/message objects to send to the LLM * `system_prompt`: Optional system prompt to guide the LLM's behavior * `temperature`: Optional sampling temperature (controls randomness) * `max_tokens`: Optional maximum number of tokens to generate (defaults to 512) * `model_preferences`: Optional model selection preferences (e.g., a model hint string, list of hints, or a ModelPreferences object) * Returns the LLM's response as TextContent or ImageContent When providing a simple string, it's treated as a user message. For more complex scenarios, you can provide a list of messages with different roles. ````python @mcp.tool() async def generate_example(concept: str, ctx: Context) -> str: """Generate a Python code example for a given concept.""" # Using a system prompt and a user message response = await ctx.sample( messages=f"Write a simple Python code example demonstrating '{concept}'.", system_prompt="You are an expert Python programmer. Provide concise, working code examples without explanations.", temperature=0.7, max_tokens=300 ) code_example = response.text return f"```python\n{code_example}\n```" ```` See [Client Sampling](/clients/client#llm-sampling) for more details on how clients handle these requests. ### Request Information Access metadata about the current request and client. ```python @mcp.tool() async def request_info(ctx: Context) -> dict: """Return information about the current request.""" return { "request_id": ctx.request_id, "client_id": ctx.client_id or "Unknown client" } ``` **Available Properties:** * **`ctx.request_id -> str`**: Get the unique ID for the current MCP request * **`ctx.client_id -> str | None`**: Get the ID of the client making the request, if provided during initialization ### Advanced Access #### FastMCP Server and Sessions ```python @mcp.tool() async def advanced_tool(ctx: Context) -> str: """Demonstrate advanced context access.""" # Access the FastMCP server instance server_name = ctx.fastmcp.name # Low-level session access (rarely needed) session = ctx.session request_context = ctx.request_context return f"Server: {server_name}" ``` #### 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 @mcp.tool() async def handle_web_request(ctx: Context) -> dict: """Access HTTP request information from the Starlette request.""" request = ctx.get_http_request() # Access HTTP headers, query parameters, etc. 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, } ``` #### Advanced Properties Reference * **`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 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. # The FastMCP Server Source: https://gofastmcp.com/servers/fastmcp Learn about the core FastMCP server class and how to run it. export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; The central piece of a FastMCP application is the `FastMCP` server class. This class acts as the main container for your application's tools, resources, and prompts, and manages communication with MCP clients. ## Creating a Server Instantiating a server is straightforward. You typically provide a name for your server, which helps identify it in client applications or logs. ```python from fastmcp import FastMCP # Create a basic server instance mcp = FastMCP(name="MyAssistantServer") # You can also add instructions for how to interact with the server mcp_with_instructions = FastMCP( name="HelpfulAssistant", instructions=""" This server provides data analysis tools. Call get_average() to analyze numerical data. """ ) ``` The `FastMCP` constructor accepts several arguments: * `name`: (Optional) A human-readable name for your server. Defaults to "FastMCP". * `instructions`: (Optional) Description of how to interact with this server. These instructions help clients understand the server's purpose and available functionality. * `lifespan`: (Optional) An async context manager function for server startup and shutdown logic. * `tags`: (Optional) A set of strings to tag the server itself. * `**settings`: Keyword arguments corresponding to additional `ServerSettings` configuration ## Components FastMCP servers expose several types of components to the client: ### Tools Tools are functions that the client can call to perform actions or access external systems. ```python @mcp.tool() def multiply(a: float, b: float) -> float: """Multiplies two numbers together.""" return a * b ``` See [Tools](/servers/tools) for detailed documentation. ### Resources Resources expose data sources that the client can read. ```python @mcp.resource("data://config") def get_config() -> dict: """Provides the application configuration.""" return {"theme": "dark", "version": "1.0"} ``` See [Resources & Templates](/servers/resources) for detailed documentation. ### Resource Templates Resource templates are parameterized resources that allow the client to request specific data. ```python @mcp.resource("users://{user_id}/profile") def get_user_profile(user_id: int) -> dict: """Retrieves a user's profile by ID.""" # The {user_id} in the URI is extracted and passed to this function return {"id": user_id, "name": f"User {user_id}", "status": "active"} ``` See [Resources & Templates](/servers/resources) for detailed documentation. ### Prompts Prompts are reusable message templates for guiding the LLM. ```python @mcp.prompt() def analyze_data(data_points: list[float]) -> str: """Creates a prompt asking for analysis of numerical data.""" formatted_data = ", ".join(str(point) for point in data_points) return f"Please analyze these data points: {formatted_data}" ``` See [Prompts](/servers/prompts) for detailed documentation. ## Running the Server FastMCP servers need a transport mechanism to communicate with clients. You typically start your server by calling the `mcp.run()` method on your `FastMCP` instance, often within an `if __name__ == "__main__":` block in your main server script. This pattern ensures compatibility with various MCP clients. ```python # my_server.py from fastmcp import FastMCP mcp = FastMCP(name="MyServer") @mcp.tool() def greet(name: str) -> str: """Greet a user by name.""" return f"Hello, {name}!" if __name__ == "__main__": # This runs the server, defaulting to STDIO transport mcp.run() # To use a different transport, e.g., HTTP: # mcp.run(transport="streamable-http", host="127.0.0.1", port=9000) ``` FastMCP supports several transport options: * STDIO (default, for local tools) * Streamable HTTP (recommended for web services) * SSE (legacy web transport, deprecated) The server can also be run using the FastMCP CLI. For detailed information on each transport, how to configure them (host, port, paths), and when to use which, please refer to the [**Running Your FastMCP Server**](/deployment/running-server) guide. ## Composing Servers FastMCP supports composing multiple servers together using `import_server` (static copy) and `mount` (live link). This allows you to organize large applications into modular components or reuse existing servers. See the [Server Composition](/patterns/composition) guide for full details, best practices, and examples. ```python # Example: Importing a subserver from fastmcp import FastMCP import asyncio main = FastMCP(name="Main") sub = FastMCP(name="Sub") @sub.tool() def hello(): return "hi" # Mount directly main.mount("sub", sub) ``` ## Proxying Servers FastMCP can act as a proxy for any MCP server (local or remote) using `FastMCP.as_proxy`, letting you bridge transports or add a frontend to existing servers. For example, you can expose a remote SSE server locally via stdio, or vice versa. See the [Proxying Servers](/patterns/proxy) guide for details and advanced usage. ```python from fastmcp import FastMCP, Client backend = Client("http://example.com/mcp/sse") proxy = FastMCP.as_proxy(backend, name="ProxyServer") # Now use the proxy like any FastMCP server ``` ## Server Configuration Server behavior, like transport settings (host, port for SSE) and how duplicate components are handled, can be configured via `ServerSettings`. These settings can be passed during `FastMCP` initialization, set via environment variables (prefixed with `FASTMCP_SERVER_`), or loaded from a `.env` file. ```python from fastmcp import FastMCP # Configure during initialization mcp = FastMCP( name="ConfiguredServer", port=8080, # Directly maps to ServerSettings on_duplicate_tools="error" # Set duplicate handling ) # Settings are accessible via mcp.settings print(mcp.settings.port) # Output: 8080 print(mcp.settings.on_duplicate_tools) # Output: "error" ``` ### Key Configuration Options * **`host`**: Host address for SSE transport (default: "127.0.0.1") * **`port`**: Port number for SSE transport (default: 8000) * **`log_level`**: Logging level (default: "INFO") * **`on_duplicate_tools`**: How to handle duplicate tool registrations * **`on_duplicate_resources`**: How to handle duplicate resource registrations * **`on_duplicate_prompts`**: How to handle duplicate prompt registrations All of these can be configured directly as parameters when creating the `FastMCP` instance. ### Custom Tool Serialization By default, FastMCP serializes tool return values to JSON when they need to be converted to text. You can customize this behavior by providing a `tool_serializer` function when creating your server: ```python import yaml from fastmcp import FastMCP # Define a custom serializer that formats dictionaries as YAML def yaml_serializer(data): return yaml.dump(data, sort_keys=False) # Create a server with the custom serializer mcp = FastMCP(name="MyServer", tool_serializer=yaml_serializer) @mcp.tool() def get_config(): """Returns configuration in YAML format.""" return {"api_key": "abc123", "debug": True, "rate_limit": 100} ``` The serializer function takes any data object and returns a string representation. This is applied to **all non-string return values** from your tools. Tools that already return strings bypass the serializer. This customization is useful when you want to: * Format data in a specific way (like YAML or custom formats) * Control specific serialization options (like indentation or sorting) * Add metadata or transform data before sending it to clients If the serializer function raises an exception, the tool will fall back to the default JSON serialization to avoid breaking the server. ## Authentication FastMCP supports OAuth 2.0 authentication, allowing servers to protect their tools and resources. This is configured by providing an `auth_server_provider` and `auth` settings during `FastMCP` initialization. ```python from fastmcp import FastMCP from mcp.server.auth.settings import AuthSettings #, ... other auth imports # from your_auth_implementation import MyOAuthServerProvider # Placeholder # Create a server with authentication (conceptual example) # mcp = FastMCP( # name="SecureApp", # auth_server_provider=MyOAuthServerProvider(), # auth=AuthSettings( # issuer_url="https://myapp.com", # # ... other OAuth settings ... # required_scopes=["myscope"], # ), # ) ``` Due to the low-level nature of the current MCP SDK's auth provider interface, detailed implementation is beyond a quick example. Refer to the [MCP SDK documentation](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization) for specifics on implementing an `OAuthAuthorizationServerProvider`. FastMCP integrates with this by passing the provider and settings to the underlying MCP server. A dedicated [Authentication guide](/deployment/authentication) will cover this in more detail once higher-level abstractions are available in FastMCP. # Prompts Source: https://gofastmcp.com/servers/prompts Create reusable, parameterized prompt templates for MCP clients. export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; Prompts are reusable message templates that help LLMs generate structured, purposeful responses. FastMCP simplifies defining these templates, primarily using the `@mcp.prompt` decorator. ## What Are Prompts? Prompts provide parameterized message templates for LLMs. When a client requests a prompt: 1. FastMCP finds the corresponding prompt definition. 2. If it has parameters, they are validated against your function signature. 3. Your function executes with the validated inputs. 4. The generated message(s) are returned to the LLM to guide its response. This allows you to define consistent, reusable templates that LLMs can use across different clients and contexts. ## Prompts ### The `@prompt` Decorator The most common way to define a prompt is by decorating a Python function. The decorator uses the function name as the prompt's identifier. ```python from fastmcp import FastMCP from fastmcp.prompts.prompt import Message, PromptMessage, TextContent mcp = FastMCP(name="PromptServer") # Basic prompt returning a string (converted to user message automatically) @mcp.prompt() def ask_about_topic(topic: str) -> str: """Generates a user message asking for an explanation of a topic.""" return f"Can you please explain the concept of '{topic}'?" # Prompt returning a specific message type @mcp.prompt() def generate_code_request(language: str, task_description: str) -> PromptMessage: """Generates a user message requesting code generation.""" content = f"Write a {language} function that performs the following task: {task_description}" return PromptMessage(role="user", content=TextContent(type="text", text=content)) ``` **Key Concepts:** * **Name:** By default, the prompt name is taken from the function name. * **Parameters:** The function parameters define the inputs needed to generate the prompt. * **Inferred Metadata:** By default: * Prompt Name: Taken from the function name (`ask_about_topic`). * Prompt Description: Taken from the function's docstring. Functions with `*args` or `**kwargs` are not supported as prompts. This restriction exists because FastMCP needs to generate a complete parameter schema for the MCP protocol, which isn't possible with variable argument lists. ### Return Values FastMCP intelligently handles different return types from your prompt function: * **`str`**: Automatically converted to a single `PromptMessage`. * **`PromptMessage`**: Used directly as provided. (Note a more user-friendly `Message` constructor is available that can accept raw strings instead of `TextContent` objects.) * **`list[PromptMessage | str]`**: Used as a sequence of messages (a conversation). * **`Any`**: If the return type is not one of the above, the return value is attempted to be converted to a string and used as a `PromptMessage`. ```python from fastmcp.prompts.prompt import Message @mcp.prompt() def roleplay_scenario(character: str, situation: str) -> list[Message]: """Sets up a roleplaying scenario with initial messages.""" return [ Message(f"Let's roleplay. You are {character}. The situation is: {situation}"), Message("Okay, I understand. I am ready. What happens next?", role="assistant") ] ``` ### Type Annotations Type annotations are important for prompts. They: 1. Inform FastMCP about the expected types for each parameter. 2. Allow validation of parameters received from clients. 3. Are used to generate the prompt's schema for the MCP protocol. ```python from pydantic import Field from typing import Literal, Optional @mcp.prompt() def generate_content_request( topic: str = Field(description="The main subject to cover"), format: Literal["blog", "email", "social"] = "blog", tone: str = "professional", word_count: Optional[int] = None ) -> str: """Create a request for generating content in a specific format.""" prompt = f"Please write a {format} post about {topic} in a {tone} tone." if word_count: prompt += f" It should be approximately {word_count} words long." return prompt ``` ### Required vs. Optional Parameters Parameters in your function signature are considered **required** unless they have a default value. ```python @mcp.prompt() def data_analysis_prompt( data_uri: str, # Required - no default value analysis_type: str = "summary", # Optional - has default value include_charts: bool = False # Optional - has default value ) -> str: """Creates a request to analyze data with specific parameters.""" prompt = f"Please perform a '{analysis_type}' analysis on the data found at {data_uri}." if include_charts: prompt += " Include relevant charts and visualizations." return prompt ``` In this example, the client *must* provide `data_uri`. If `analysis_type` or `include_charts` are omitted, their default values will be used. ### Prompt Metadata While FastMCP infers the name and description from your function, you can override these and add tags using arguments to the `@mcp.prompt` decorator: ```python @mcp.prompt( name="analyze_data_request", # Custom prompt name description="Creates a request to analyze data with specific parameters", # Custom description tags={"analysis", "data"} # Optional categorization tags ) def data_analysis_prompt( data_uri: str = Field(description="The URI of the resource containing the data."), analysis_type: str = Field(default="summary", description="Type of analysis.") ) -> str: """This docstring is ignored when description is provided.""" return f"Please perform a '{analysis_type}' analysis on the data found at {data_uri}." ``` * **`name`**: Sets the explicit prompt name exposed via MCP. * **`description`**: Provides the description exposed via MCP. If set, the function's docstring is ignored for this purpose. * **`tags`**: A set of strings used to categorize the prompt. Clients *might* use tags to filter or group available prompts. ### Asynchronous Prompts FastMCP seamlessly supports both standard (`def`) and asynchronous (`async def`) functions as prompts. ```python # Synchronous prompt @mcp.prompt() def simple_question(question: str) -> str: """Generates a simple question to ask the LLM.""" return f"Question: {question}" # Asynchronous prompt @mcp.prompt() async def data_based_prompt(data_id: str) -> str: """Generates a prompt based on data that needs to be fetched.""" # In a real scenario, you might fetch data from a database or API async with aiohttp.ClientSession() as session: async with session.get(f"https://api.example.com/data/{data_id}") as response: data = await response.json() return f"Analyze this data: {data['content']}" ``` Use `async def` when your prompt function performs I/O operations like network requests, database queries, file I/O, or external service calls. ### Accessing MCP Context Prompts can access additional MCP information and features through the `Context` object. To access it, add a parameter to your prompt function with a type annotation of `Context`: ```python {6} from fastmcp import FastMCP, Context mcp = FastMCP(name="PromptServer") @mcp.prompt() async def generate_report_request(report_type: str, ctx: Context) -> str: """Generates a request for a report.""" return f"Please create a {report_type} report. Request ID: {ctx.request_id}" ``` For full documentation on the Context object and all its capabilities, see the [Context documentation](/servers/context). ## Server Behavior ### Duplicate Prompts You can configure how the FastMCP server handles attempts to register multiple prompts with the same name. Use the `on_duplicate_prompts` setting during `FastMCP` initialization. ```python from fastmcp import FastMCP mcp = FastMCP( name="PromptServer", on_duplicate_prompts="error" # Raise an error if a prompt name is duplicated ) @mcp.prompt() def greeting(): return "Hello, how can I help you today?" # This registration attempt will raise a ValueError because # "greeting" is already registered and the behavior is "error". # @mcp.prompt() # def greeting(): return "Hi there! What can I do for you?" ``` The duplicate behavior options are: * `"warn"` (default): Logs a warning, and the new prompt replaces the old one. * `"error"`: Raises a `ValueError`, preventing the duplicate registration. * `"replace"`: Silently replaces the existing prompt with the new one. * `"ignore"`: Keeps the original prompt and ignores the new registration attempt. # Proxy Servers Source: https://gofastmcp.com/servers/proxy Use FastMCP to act as an intermediary or change transport for other MCP servers. export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; FastMCP provides a powerful proxying capability that allows one FastMCP server instance to act as a frontend for another MCP server (which could be remote, running on a different transport, or even another FastMCP instance). This is achieved using the `FastMCP.as_proxy()` class method. `as_proxy()` accepts either an existing `Client` or any argument that can be passed to a `Client` as its `transport` parameter—such as another `FastMCP` instance, a URL to a remote server, or an MCP configuration dictionary. ## What is Proxying? Proxying means setting up a FastMCP server that doesn't implement its own tools or resources directly. Instead, when it receives a request (like `tools/call` or `resources/read`), it forwards that request to a *backend* MCP server, receives the response, and then relays that response back to the original client. ```mermaid sequenceDiagram participant ClientApp as Your Client (e.g., Claude Desktop) participant FastMCPProxy as FastMCP Proxy Server participant BackendServer as Backend MCP Server (e.g., remote SSE) ClientApp->>FastMCPProxy: MCP Request (e.g. stdio) Note over FastMCPProxy, BackendServer: Proxy forwards the request FastMCPProxy->>BackendServer: MCP Request (e.g. sse) BackendServer-->>FastMCPProxy: MCP Response (e.g. sse) Note over ClientApp, FastMCPProxy: Proxy relays the response FastMCPProxy-->>ClientApp: MCP Response (e.g. stdio) ``` ### Use Cases * **Transport Bridging**: Expose a server running on one transport (e.g., a remote SSE server) via a different transport (e.g., local Stdio for Claude Desktop). * **Adding Functionality**: Insert a layer in front of an existing server to add caching, logging, authentication, or modify requests/responses (though direct modification requires subclassing `FastMCPProxy`). * **Security Boundary**: Use the proxy as a controlled gateway to an internal server. * **Simplifying Client Configuration**: Provide a single, stable endpoint (the proxy) even if the backend server's location or transport changes. ## Creating a Proxy The easiest way to create a proxy is using the `FastMCP.as_proxy()` class method. This creates a standard FastMCP server that forwards requests to another MCP server. ```python from fastmcp import FastMCP # Provide the backend in any form accepted by Client proxy_server = FastMCP.as_proxy( "backend_server.py", # Could also be a FastMCP instance, config dict, or a remote URL name="MyProxyServer" # Optional settings for the proxy ) # Or create the Client yourself for custom configuration backend_client = Client("backend_server.py") proxy_from_client = FastMCP.as_proxy(backend_client) ``` **How `as_proxy` Works:** 1. It connects to the backend server using the provided client. 2. It discovers all the tools, resources, resource templates, and prompts available on the backend server. 3. It creates corresponding "proxy" components that forward requests to the backend. 4. It returns a standard `FastMCP` server instance that can be used like any other. Currently, proxying focuses primarily on exposing the major MCP objects (tools, resources, templates, and prompts). Some advanced MCP features like notifications and sampling are not fully supported in proxies in the current version. Support for these additional features may be added in future releases. ### Bridging Transports A common use case is to bridge transports. For example, making a remote SSE server available locally via Stdio: ```python from fastmcp import FastMCP # Target a remote SSE server directly by URL proxy = FastMCP.as_proxy("http://example.com/mcp/sse", name="SSE to Stdio Proxy") # The proxy can now be used with any transport # No special handling needed - it works like any FastMCP server ``` ### In-Memory Proxies You can also proxy an in-memory `FastMCP` instance, which is useful for adjusting the configuration or behavior of a server you don't completely control. ```python from fastmcp import FastMCP # Original server original_server = FastMCP(name="Original") @original_server.tool() def tool_a() -> str: return "A" # Create a proxy of the original server directly proxy = FastMCP.as_proxy( original_server, name="Proxy Server" ) # proxy is now a regular FastMCP server that forwards # requests to original_server ``` ### Configuration-Based Proxies You can create a proxy directly from a configuration dictionary that follows the MCPConfig schema. This is useful for quickly setting up proxies to remote servers without manually configuring each connection detail. ```python from fastmcp import FastMCP # Create a proxy directly from a config dictionary config = { "mcpServers": { "default": { # For single server configs, 'default' is commonly used "url": "https://example.com/mcp", "transport": "streamable-http" } } } # Create a proxy to the configured server proxy = FastMCP.as_proxy(config, name="Config-Based Proxy") # Run the proxy with stdio transport for local access if __name__ == "__main__": proxy.run() ``` The MCPConfig format follows an emerging standard for MCP server configuration and may evolve as the specification matures. While FastMCP aims to maintain compatibility with future versions, be aware that field names or structure might change. You can also use MCPConfig to create a proxy to multiple servers. When multiple servers are specified, they are automatically mounted with their config names as prefixes, providing a unified interface to all servers: ```python from fastmcp import FastMCP # Multi-server configuration config = { "mcpServers": { "weather": { "url": "https://weather-api.example.com/mcp", "transport": "streamable-http" }, "calendar": { "url": "https://calendar-api.example.com/mcp", "transport": "streamable-http" } } } # Create a proxy to multiple servers composite_proxy = FastMCP.as_proxy(config, name="Composite Proxy") # Tools and resources are accessible with prefixes: # - weather_get_forecast, calendar_add_event # - weather://weather/icons/sunny, calendar://calendar/events/today ``` ## `FastMCPProxy` Class Internally, `FastMCP.as_proxy()` uses the `FastMCPProxy` class. You generally don't need to interact with this class directly, but it's available if needed. Using the class directly might be necessary for advanced scenarios, like subclassing `FastMCPProxy` to add custom logic before or after forwarding requests. # Resources & Templates Source: https://gofastmcp.com/servers/resources Expose data sources and dynamic content generators to your MCP client. export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; Resources represent data or files that an MCP client can read, and resource templates extend this concept by allowing clients to request dynamically generated resources based on parameters passed in the URI. FastMCP simplifies defining both static and dynamic resources, primarily using the `@mcp.resource` decorator. ## What Are Resources? Resources provide read-only access to data for the LLM or client application. When a client requests a resource URI: 1. FastMCP finds the corresponding resource definition. 2. If it's dynamic (defined by a function), the function is executed. 3. The content (text, JSON, binary data) is returned to the client. This allows LLMs to access files, database content, configuration, or dynamically generated information relevant to the conversation. ## Resources ### The `@resource` Decorator The most common way to define a resource is by decorating a Python function. The decorator requires the resource's unique URI. ```python import json from fastmcp import FastMCP mcp = FastMCP(name="DataServer") # Basic dynamic resource returning a string @mcp.resource("resource://greeting") def get_greeting() -> str: """Provides a simple greeting message.""" return "Hello from FastMCP Resources!" # Resource returning JSON data (dict is auto-serialized) @mcp.resource("data://config") def get_config() -> dict: """Provides application configuration as JSON.""" return { "theme": "dark", "version": "1.2.0", "features": ["tools", "resources"], } ``` **Key Concepts:** * **URI:** The first argument to `@resource` is the unique URI (e.g., `"resource://greeting"`) clients use to request this data. * **Lazy Loading:** The decorated function (`get_greeting`, `get_config`) is only executed when a client specifically requests that resource URI via `resources/read`. * **Inferred Metadata:** By default: * Resource Name: Taken from the function name (`get_greeting`). * Resource Description: Taken from the function's docstring. ### Return Values FastMCP automatically converts your function's return value into the appropriate MCP resource content: * **`str`**: Sent as `TextResourceContents` (with `mime_type="text/plain"` by default). * **`dict`, `list`, `pydantic.BaseModel`**: Automatically serialized to a JSON string and sent as `TextResourceContents` (with `mime_type="application/json"` by default). * **`bytes`**: Base64 encoded and sent as `BlobResourceContents`. You should specify an appropriate `mime_type` (e.g., `"image/png"`, `"application/octet-stream"`). * **`None`**: Results in an empty resource content list being returned. ### Resource Metadata You can customize the resource's properties using arguments in the decorator: ```python from fastmcp import FastMCP mcp = FastMCP(name="DataServer") # Example specifying metadata @mcp.resource( uri="data://app-status", # Explicit URI (required) name="ApplicationStatus", # Custom name description="Provides the current status of the application.", # Custom description mime_type="application/json", # Explicit MIME type tags={"monitoring", "status"} # Categorization tags ) def get_application_status() -> dict: """Internal function description (ignored if description is provided above).""" return {"status": "ok", "uptime": 12345, "version": mcp.settings.version} # Example usage ``` * **`uri`**: The unique identifier for the resource (required). * **`name`**: A human-readable name (defaults to function name). * **`description`**: Explanation of the resource (defaults to docstring). * **`mime_type`**: Specifies the content type (FastMCP often infers a default like `text/plain` or `application/json`, but explicit is better for non-text types). * **`tags`**: A set of strings for categorization, potentially used by clients for filtering. ### Accessing MCP Context Resources and resource templates can access additional MCP information and features through the `Context` object. To access it, add a parameter to your resource function with a type annotation of `Context`: ```python {6, 14} from fastmcp import FastMCP, Context mcp = FastMCP(name="DataServer") @mcp.resource("resource://system-status") async def get_system_status(ctx: Context) -> dict: """Provides system status information.""" return { "status": "operational", "request_id": ctx.request_id } @mcp.resource("resource://{name}/details") async def get_details(name: str, ctx: Context) -> dict: """Get details for a specific name.""" return { "name": name, "accessed_at": ctx.request_id } ``` For full documentation on the Context object and all its capabilities, see the [Context documentation](/servers/context). ### Asynchronous Resources Use `async def` for resource functions that perform I/O operations (e.g., reading from a database or network) to avoid blocking the server. ```python import aiofiles from fastmcp import FastMCP mcp = FastMCP(name="DataServer") @mcp.resource("file:///app/data/important_log.txt", mime_type="text/plain") async def read_important_log() -> str: """Reads content from a specific log file asynchronously.""" try: async with aiofiles.open("/app/data/important_log.txt", mode="r") as f: content = await f.read() return content except FileNotFoundError: return "Log file not found." ``` ### Resource Classes While `@mcp.resource` is ideal for dynamic content, you can directly register pre-defined resources (like static files or simple text) using `mcp.add_resource()` and concrete `Resource` subclasses. ```python from pathlib import Path from fastmcp import FastMCP from fastmcp.resources import FileResource, TextResource, DirectoryResource mcp = FastMCP(name="DataServer") # 1. Exposing a static file directly readme_path = Path("./README.md").resolve() if readme_path.exists(): # Use a file:// URI scheme readme_resource = FileResource( uri=f"file://{readme_path.as_posix()}", path=readme_path, # Path to the actual file name="README File", description="The project's README.", mime_type="text/markdown", tags={"documentation"} ) mcp.add_resource(readme_resource) # 2. Exposing simple, predefined text notice_resource = TextResource( uri="resource://notice", name="Important Notice", text="System maintenance scheduled for Sunday.", tags={"notification"} ) mcp.add_resource(notice_resource) # 3. Using a custom key different from the URI special_resource = TextResource( uri="resource://common-notice", name="Special Notice", text="This is a special notice with a custom storage key.", ) mcp.add_resource(special_resource, key="resource://custom-key") # 4. Exposing a directory listing data_dir_path = Path("./app_data").resolve() if data_dir_path.is_dir(): data_listing_resource = DirectoryResource( uri="resource://data-files", path=data_dir_path, # Path to the directory name="Data Directory Listing", description="Lists files available in the data directory.", recursive=False # Set to True to list subdirectories ) mcp.add_resource(data_listing_resource) # Returns JSON list of files ``` **Common Resource Classes:** * `TextResource`: For simple string content. * `BinaryResource`: For raw `bytes` content. * `FileResource`: Reads content from a local file path. Handles text/binary modes and lazy reading. * `HttpResource`: Fetches content from an HTTP(S) URL (requires `httpx`). * `DirectoryResource`: Lists files in a local directory (returns JSON). * (`FunctionResource`: Internal class used by `@mcp.resource`). Use these when the content is static or sourced directly from a file/URL, bypassing the need for a dedicated Python function. #### Custom Resource Keys When adding resources directly with `mcp.add_resource()`, you can optionally provide a custom storage key: ```python # Creating a resource with standard URI as the key resource = TextResource(uri="resource://data") mcp.add_resource(resource) # Will be stored and accessed using "resource://data" # Creating a resource with a custom key special_resource = TextResource(uri="resource://special-data") mcp.add_resource(special_resource, key="internal://data-v2") # Will be stored and accessed using "internal://data-v2" ``` Note that this parameter is only available when using `add_resource()` directly and not through the `@resource` decorator, as URIs are provided explicitly when using the decorator. ## Resource Templates Resource Templates allow clients to request resources whose content depends on parameters embedded in the URI. Define a template using the **same `@mcp.resource` decorator**, but include `{parameter_name}` placeholders in the URI string and add corresponding arguments to your function signature. Resource templates share most configuration options with regular resources (name, description, mime\_type, tags), but add the ability to define URI parameters that map to function parameters. Resource templates generate a new resource for each unique set of parameters, which means that resources can be dynamically created on-demand. For example, if the resource template `"user://profile/{name}"` is registered, MCP clients could request `"user://profile/ford"` or `"user://profile/marvin"` to retrieve either of those two user profiles as resources, without having to register each resource individually. Functions with `*args` are not supported as resource templates. However, unlike tools and prompts, resource templates do support `**kwargs` because the URI template defines specific parameter names that will be collected and passed as keyword arguments. Here is a complete example that shows how to define two resource templates: ```python from fastmcp import FastMCP mcp = FastMCP(name="DataServer") # Template URI includes {city} placeholder @mcp.resource("weather://{city}/current") def get_weather(city: str) -> dict: """Provides weather information for a specific city.""" # In a real implementation, this would call a weather API # Here we're using simplified logic for example purposes return { "city": city.capitalize(), "temperature": 22, "condition": "Sunny", "unit": "celsius" } # Template with multiple parameters @mcp.resource("repos://{owner}/{repo}/info") def get_repo_info(owner: str, repo: str) -> dict: """Retrieves information about a GitHub repository.""" # In a real implementation, this would call the GitHub API return { "owner": owner, "name": repo, "full_name": f"{owner}/{repo}", "stars": 120, "forks": 48 } ``` With these two templates defined, clients can request a variety of resources: * `weather://london/current` → Returns weather for London * `weather://paris/current` → Returns weather for Paris * `repos://jlowin/fastmcp/info` → Returns info about the jlowin/fastmcp repository * `repos://prefecthq/prefect/info` → Returns info about the prefecthq/prefect repository ### Wildcard Parameters Please note: FastMCP's support for wildcard parameters is an **extension** of the Model Context Protocol standard, which otherwise follows RFC 6570. Since all template processing happens in the FastMCP server, this should not cause any compatibility issues with other MCP implementations. Resource templates support wildcard parameters that can match multiple path segments. While standard parameters (`{param}`) only match a single path segment and don't cross "/" boundaries, wildcard parameters (`{param*}`) can capture multiple segments including slashes. Wildcards capture all subsequent path segments *up until* the defined part of the URI template (whether literal or another parameter). This allows you to have multiple wildcard parameters in a single URI template. ```python {15, 23} from fastmcp import FastMCP mcp = FastMCP(name="DataServer") # Standard parameter only matches one segment @mcp.resource("files://{filename}") def get_file(filename: str) -> str: """Retrieves a file by name.""" # Will only match files:// return f"File content for: {filename}" # Wildcard parameter can match multiple segments @mcp.resource("path://{filepath*}") def get_path_content(filepath: str) -> str: """Retrieves content at a specific path.""" # Can match path://docs/server/resources.mdx return f"Content at path: {filepath}" # Mixing standard and wildcard parameters @mcp.resource("repo://{owner}/{path*}/template.py") def get_template_file(owner: str, path: str) -> dict: """Retrieves a file from a specific repository and path, but only if the resource ends with `template.py`""" # Can match repo://jlowin/fastmcp/src/resources/template.py return { "owner": owner, "path": path + "/template.py", "content": f"File at {path}/template.py in {owner}'s repository" } ``` Wildcard parameters are useful when: * Working with file paths or hierarchical data * Creating APIs that need to capture variable-length path segments * Building URL-like patterns similar to REST APIs Note that like regular parameters, each wildcard parameter must still be a named parameter in your function signature, and all required function parameters must appear in the URI template. ### Default Values When creating resource templates, FastMCP enforces two rules for the relationship between URI template parameters and function parameters: 1. **Required Function Parameters:** All function parameters without default values (required parameters) must appear in the URI template. 2. **URI Parameters:** All URI template parameters must exist as function parameters. However, function parameters with default values don't need to be included in the URI template. When a client requests a resource, FastMCP will: * Extract parameter values from the URI for parameters included in the template * Use default values for any function parameters not in the URI template This allows for flexible API designs. For example, a simple search template with optional parameters: ```python from fastmcp import FastMCP mcp = FastMCP(name="DataServer") @mcp.resource("search://{query}") def search_resources(query: str, max_results: int = 10, include_archived: bool = False) -> dict: """Search for resources matching the query string.""" # Only 'query' is required in the URI, the other parameters use their defaults results = perform_search(query, limit=max_results, archived=include_archived) return { "query": query, "max_results": max_results, "include_archived": include_archived, "results": results } ``` With this template, clients can request `search://python` and the function will be called with `query="python", max_results=10, include_archived=False`. MCP Developers can still call the underlying `search_resources` function directly with more specific parameters. An even more powerful pattern is registering a single function with multiple URI templates, allowing different ways to access the same data: ```python from fastmcp import FastMCP mcp = FastMCP(name="DataServer") # Define a user lookup function that can be accessed by different identifiers @mcp.resource("users://email/{email}") @mcp.resource("users://name/{name}") def lookup_user(name: str | None = None, email: str | None = None) -> dict: """Look up a user by either name or email.""" if email: return find_user_by_email(email) # pseudocode elif name: return find_user_by_name(name) # pseudocode else: return {"error": "No lookup parameters provided"} ``` Now an LLM or client can retrieve user information in two different ways: * `users://email/alice@example.com` → Looks up user by email (with name=None) * `users://name/Bob` → Looks up user by name (with email=None) In this stacked decorator pattern: * The `name` parameter is only provided when using the `users://name/{name}` template * The `email` parameter is only provided when using the `users://email/{email}` template * Each parameter defaults to `None` when not included in the URI * The function logic handles whichever parameter is provided Templates provide a powerful way to expose parameterized data access points following REST-like principles. ## Error Handling If your resource function encounters an error, you can raise a standard Python exception (`ValueError`, `TypeError`, `FileNotFoundError`, custom exceptions, etc.) or a FastMCP `ResourceError`. For security reasons, most exceptions are wrapped in a generic `ResourceError` before being sent to the client, with internal error details masked. However, if you raise a `ResourceError` directly, its contents **are** included in the response. This allows you to provide informative error messages to the client on an opt-in basis. ```python from fastmcp import FastMCP from fastmcp.exceptions import ResourceError mcp = FastMCP(name="DataServer") @mcp.resource("resource://safe-error") def fail_with_details() -> str: """This resource provides detailed error information.""" # ResourceError contents are sent back to clients raise ResourceError("Unable to retrieve data: file not found") @mcp.resource("resource://masked-error") def fail_with_masked_details() -> str: """This resource masks internal error details.""" # Other exceptions are converted to ResourceError with generic message raise ValueError("Sensitive internal file path: /etc/secrets.conf") @mcp.resource("data://{id}") def get_data_by_id(id: str) -> dict: """Template resources also support the same error handling pattern.""" if id == "secure": raise ValueError("Cannot access secure data") elif id == "missing": raise ResourceError("Data ID 'missing' not found in database") return {"id": id, "value": "data"} ``` This error handling pattern applies to both regular resources and resource templates. ## Server Behavior ### Duplicate Resources You can configure how the FastMCP server handles attempts to register multiple resources or templates with the same URI. Use the `on_duplicate_resources` setting during `FastMCP` initialization. ```python from fastmcp import FastMCP mcp = FastMCP( name="ResourceServer", on_duplicate_resources="error" # Raise error on duplicates ) @mcp.resource("data://config") def get_config_v1(): return {"version": 1} # This registration attempt will raise a ValueError because # "data://config" is already registered and the behavior is "error". # @mcp.resource("data://config") # def get_config_v2(): return {"version": 2} ``` The duplicate behavior options are: * `"warn"` (default): Logs a warning, and the new resource/template replaces the old one. * `"error"`: Raises a `ValueError`, preventing the duplicate registration. * `"replace"`: Silently replaces the existing resource/template with the new one. * `"ignore"`: Keeps the original resource/template and ignores the new registration attempt. # Tools Source: https://gofastmcp.com/servers/tools Expose functions as executable capabilities for your MCP client. export const VersionBadge = ({version}) => { return
New in version:  {version}
; }; Tools are the core building blocks that allow your LLM to interact with external systems, execute code, and access data that isn't in its training data. In FastMCP, tools are Python functions exposed to LLMs through the MCP protocol. ## What Are Tools? Tools in FastMCP transform regular Python functions into capabilities that LLMs can invoke during conversations. When an LLM decides to use a tool: 1. It sends a request with parameters based on the tool's schema. 2. FastMCP validates these parameters against your function's signature. 3. Your function executes with the validated inputs. 4. The result is returned to the LLM, which can use it in its response. This allows LLMs to perform tasks like querying databases, calling APIs, making calculations, or accessing files—extending their capabilities beyond what's in their training data. ## Tools ### The `@tool` Decorator Creating a tool is as simple as decorating a Python function with `@mcp.tool()`: ```python from fastmcp import FastMCP mcp = FastMCP(name="CalculatorServer") @mcp.tool() def add(a: int, b: int) -> int: """Adds two integer numbers together.""" return a + b ``` When this tool is registered, FastMCP automatically: * Uses the function name (`add`) as the tool name. * Uses the function's docstring (`Adds two integer numbers...`) as the tool description. * Generates an input schema based on the function's parameters and type annotations. * Handles parameter validation and error reporting. The way you define your Python function dictates how the tool appears and behaves for the LLM client. Functions with `*args` or `**kwargs` are not supported as tools. This restriction exists because FastMCP needs to generate a complete parameter schema for the MCP protocol, which isn't possible with variable argument lists. ### Parameters #### Annotations Type annotations for parameters are essential for proper tool functionality. They: 1. Inform the LLM about the expected data types for each parameter 2. Enable FastMCP to validate input data from clients 3. Generate accurate JSON schemas for the MCP protocol Use standard Python type annotations for parameters: ```python @mcp.tool() def analyze_text( text: str, max_tokens: int = 100, language: str | None = None ) -> dict: """Analyze the provided text.""" # Implementation... ``` #### Parameter Metadata You can provide additional metadata about parameters using Pydantic's `Field` class with `Annotated`. This approach is preferred as it's more modern and keeps type hints separate from validation rules: ```python from typing import Annotated from pydantic import Field @mcp.tool() def process_image( image_url: Annotated[str, Field(description="URL of the image to process")], resize: Annotated[bool, Field(description="Whether to resize the image")] = False, width: Annotated[int, Field(description="Target width in pixels", ge=1, le=2000)] = 800, format: Annotated[ Literal["jpeg", "png", "webp"], Field(description="Output image format") ] = "jpeg" ) -> dict: """Process an image with optional resizing.""" # Implementation... ``` You can also use the Field as a default value, though the Annotated approach is preferred: ```python @mcp.tool() def search_database( query: str = Field(description="Search query string"), limit: int = Field(10, description="Maximum number of results", ge=1, le=100) ) -> list: """Search the database with the provided query.""" # Implementation... ``` Field provides several validation and documentation features: * `description`: Human-readable explanation of the parameter (shown to LLMs) * `ge`/`gt`/`le`/`lt`: Greater/less than (or equal) constraints * `min_length`/`max_length`: String or collection length constraints * `pattern`: Regex pattern for string validation * `default`: Default value if parameter is omitted #### Supported Types FastMCP supports a wide range of type annotations, including all Pydantic types: | Type Annotation | Example | Description | | :---------------- | :---------------------------------------- | :---------------------------------------------------------------------------------------------- | | Basic types | `int`, `float`, `str`, `bool` | Simple scalar values - see [Built-in Types](#built-in-types) | | Binary data | `bytes` | Binary content - see [Binary Data](#binary-data) | | Date and Time | `datetime`, `date`, `timedelta` | Date and time objects - see [Date and Time Types](#date-and-time-types) | | Collection types | `list[str]`, `dict[str, int]`, `set[int]` | Collections of items - see [Collection Types](#collection-types) | | Optional types | `float \| None`, `Optional[float]` | Parameters that may be null/omitted - see [Union and Optional Types](#union-and-optional-types) | | Union types | `str \| int`, `Union[str, int]` | Parameters accepting multiple types - see [Union and Optional Types](#union-and-optional-types) | | Constrained types | `Literal["A", "B"]`, `Enum` | Parameters with specific allowed values - see [Constrained Types](#constrained-types) | | Paths | `Path` | File system paths - see [Paths](#paths) | | UUIDs | `UUID` | Universally unique identifiers - see [UUIDs](#uuids) | | Pydantic models | `UserData` | Complex structured data - see [Pydantic Models](#pydantic-models) | For additional type annotations not listed here, see the [Parameter Types](#parameter-types) section below for more detailed information and examples. #### Optional Arguments FastMCP follows Python's standard function parameter conventions. Parameters without default values are required, while those with default values are optional. ```python @mcp.tool() def search_products( query: str, # Required - no default value max_results: int = 10, # Optional - has default value sort_by: str = "relevance", # Optional - has default value category: str | None = None # Optional - can be None ) -> list[dict]: """Search the product catalog.""" # Implementation... ``` In this example, the LLM must provide a `query` parameter, while `max_results`, `sort_by`, and `category` will use their default values if not explicitly provided. ### Metadata While FastMCP infers the name and description from your function, you can override these and add tags using arguments to the `@mcp.tool` decorator: ```python @mcp.tool( name="find_products", # Custom tool name for the LLM description="Search the product catalog with optional category filtering.", # Custom description tags={"catalog", "search"} # Optional tags for organization/filtering ) def search_products_implementation(query: str, category: str | None = None) -> list[dict]: """Internal function description (ignored if description is provided above).""" # Implementation... print(f"Searching for '{query}' in category '{category}'") return [{"id": 2, "name": "Another Product"}] ``` * **`name`**: Sets the explicit tool name exposed via MCP. * **`description`**: Provides the description exposed via MCP. If set, the function's docstring is ignored for this purpose. * **`tags`**: A set of strings used to categorize the tool. Clients *might* use tags to filter or group available tools. ### Async Tools FastMCP seamlessly supports both standard (`def`) and asynchronous (`async def`) functions as tools. ```python # Synchronous tool (suitable for CPU-bound or quick tasks) @mcp.tool() def calculate_distance(lat1: float, lon1: float, lat2: float, lon2: float) -> float: """Calculate the distance between two coordinates.""" # Implementation... return 42.5 # Asynchronous tool (ideal for I/O-bound operations) @mcp.tool() async def fetch_weather(city: str) -> dict: """Retrieve current weather conditions for a city.""" # Use 'async def' for operations involving network calls, file I/O, etc. # This prevents blocking the server while waiting for external operations. async with aiohttp.ClientSession() as session: async with session.get(f"https://api.example.com/weather/{city}") as response: # Check response status before returning response.raise_for_status() return await response.json() ``` Use `async def` when your tool needs to perform operations that might wait for external systems (network requests, database queries, file access) to keep your server responsive. ### Return Values FastMCP automatically converts the value returned by your function into the appropriate MCP content format for the client: * **`str`**: Sent as `TextContent`. * **`dict`, `list`, Pydantic `BaseModel`**: Serialized to a JSON string and sent as `TextContent`. * **`bytes`**: Base64 encoded and sent as `BlobResourceContents` (often within an `EmbeddedResource`). * **`fastmcp.Image`**: A helper class for easily returning image data. Sent as `ImageContent`. * **`None`**: Results in an empty response (no content is sent back to the client). FastMCP will attempt to serialize other types to a string if possible. At this time, FastMCP responds only to your tool's return *value*, not its return *annotation*. ```python from fastmcp import FastMCP, Image import io try: from PIL import Image as PILImage except ImportError: raise ImportError("Please install the `pillow` library to run this example.") mcp = FastMCP("Image Demo") @mcp.tool() def generate_image(width: int, height: int, color: str) -> Image: """Generates a solid color image.""" # Create image using Pillow img = PILImage.new("RGB", (width, height), color=color) # Save to a bytes buffer buffer = io.BytesIO() img.save(buffer, format="PNG") img_bytes = buffer.getvalue() # Return using FastMCP's Image helper return Image(data=img_bytes, format="png") @mcp.tool() def do_nothing() -> None: """This tool performs an action but returns no data.""" print("Performing a side effect...") return None ``` ### Error Handling If your tool encounters an error, you can raise a standard Python exception (`ValueError`, `TypeError`, `FileNotFoundError`, custom exceptions, etc.) or a FastMCP `ToolError`. In all cases, the exception is logged and converted into an MCP error response to be sent back to the client LLM. For security reasons, the error message is **not** included in the response by default. However, if you raise a `ToolError`, the contents of the exception **are** included in the response. This allows you to provide informative error messages to the client LLM on an opt-in basis, which can help the LLM understand failures and react appropriately. ```python {2, 10, 14} from fastmcp import FastMCP from fastmcp.exceptions import ToolError @mcp.tool() def divide(a: float, b: float) -> float: """Divide a by b.""" # Python exceptions raise errors but the contents are not sent to clients if not isinstance(a, (int, float)) or not isinstance(b, (int, float)): raise TypeError("Both arguments must be numbers.") if b == 0: # ToolError contents are sent back to clients raise ToolError("Division by zero is not allowed.") return a / b ``` ### Annotations FastMCP allows you to add specialized metadata to your tools through annotations. These annotations communicate how tools behave to client applications without consuming token context in LLM prompts. Annotations serve several purposes in client applications: * Adding user-friendly titles for display purposes * Indicating whether tools modify data or systems * Describing the safety profile of tools (destructive vs. non-destructive) * Signaling if tools interact with external systems You can add annotations to a tool using the `annotations` parameter in the `@mcp.tool()` decorator: ```python @mcp.tool( annotations={ "title": "Calculate Sum", "readOnlyHint": True, "openWorldHint": False } ) def calculate_sum(a: float, b: float) -> float: """Add two numbers together.""" return a + b ``` FastMCP supports these standard annotations: | Annotation | Type | Default | Purpose | | :---------------- | :------ | :------ | :-------------------------------------------------------------------------- | | `title` | string | - | Display name for user interfaces | | `readOnlyHint` | boolean | false | Indicates if the tool only reads without making changes | | `destructiveHint` | boolean | true | For non-readonly tools, signals if changes are destructive | | `idempotentHint` | boolean | false | Indicates if repeated identical calls have the same effect as a single call | | `openWorldHint` | boolean | true | Specifies if the tool interacts with external systems | Remember that annotations help make better user experiences but should be treated as advisory hints. They help client applications present appropriate UI elements and safety controls, but won't enforce security boundaries on their own. Always focus on making your annotations accurately represent what your tool actually does. ## MCP Context Tools can access MCP features like logging, reading resources, or reporting progress through the `Context` object. To use it, add a parameter to your tool function with the type hint `Context`. ```python from fastmcp import FastMCP, Context mcp = FastMCP(name="ContextDemo") @mcp.tool() async def process_data(data_uri: str, ctx: Context) -> dict: """Process data from a resource with progress reporting.""" await ctx.info(f"Processing data from {data_uri}") # Read a resource resource = await ctx.read_resource(data_uri) data = resource[0].content if resource else "" # Report progress await ctx.report_progress(progress=50, total=100) # Example request to the client's LLM for help summary = await ctx.sample(f"Summarize this in 10 words: {data[:200]}") await ctx.report_progress(progress=100, total=100) return { "length": len(data), "summary": summary.text } ``` The Context object provides access to: * **Logging**: `ctx.debug()`, `ctx.info()`, `ctx.warning()`, `ctx.error()` * **Progress Reporting**: `ctx.report_progress(progress, total)` * **Resource Access**: `ctx.read_resource(uri)` * **LLM Sampling**: `ctx.sample(...)` * **Request Information**: `ctx.request_id`, `ctx.client_id` For full documentation on the Context object and all its capabilities, see the [Context documentation](/servers/context). ## Parameter Types FastMCP supports a wide variety of parameter types to give you flexibility when designing your tools. FastMCP generally supports all types that Pydantic supports as fields, including all Pydantic custom types. This means you can use any type that can be validated and parsed by Pydantic in your tool parameters. FastMCP supports **type coercion** when possible. This means that if a client sends data that doesn't match the expected type, FastMCP will attempt to convert it to the appropriate type. For example, if a client sends a string for a parameter annotated as `int`, FastMCP will attempt to convert it to an integer. If the conversion is not possible, FastMCP will return a validation error. ### Built-in Types The most common parameter types are Python's built-in scalar types: ```python @mcp.tool() def process_values( name: str, # Text data count: int, # Integer numbers amount: float, # Floating point numbers enabled: bool # Boolean values (True/False) ): """Process various value types.""" # Implementation... ``` These types provide clear expectations to the LLM about what values are acceptable and allow FastMCP to validate inputs properly. Even if a client provides a string like "42", it will be coerced to an integer for parameters annotated as `int`. ### Date and Time Types FastMCP supports various date and time types from the `datetime` module: ```python from datetime import datetime, date, timedelta @mcp.tool() def process_date_time( event_date: date, # ISO format date string or date object event_time: datetime, # ISO format datetime string or datetime object duration: timedelta = timedelta(hours=1) # Integer seconds or timedelta ) -> str: """Process date and time information.""" # Types are automatically converted from strings assert isinstance(event_date, date) assert isinstance(event_time, datetime) assert isinstance(duration, timedelta) return f"Event on {event_date} at {event_time} for {duration}" ``` * `datetime` - Accepts ISO format strings (e.g., "2023-04-15T14:30:00") * `date` - Accepts ISO format date strings (e.g., "2023-04-15") * `timedelta` - Accepts integer seconds or timedelta objects ### Collection Types FastMCP supports all standard Python collection types: ```python @mcp.tool() def analyze_data( values: list[float], # List of numbers properties: dict[str, str], # Dictionary with string keys and values unique_ids: set[int], # Set of unique integers coordinates: tuple[float, float], # Tuple with fixed structure mixed_data: dict[str, list[int]] # Nested collections ): """Analyze collections of data.""" # Implementation... ``` All collection types can be used as parameter annotations: * `list[T]` - Ordered sequence of items * `dict[K, V]` - Key-value mapping * `set[T]` - Unordered collection of unique items * `tuple[T1, T2, ...]` - Fixed-length sequence with potentially different types Collection types can be nested and combined to represent complex data structures. JSON strings that match the expected structure will be automatically parsed and converted to the appropriate Python collection type. ### Union and Optional Types For parameters that can accept multiple types or may be omitted: ```python @mcp.tool() def flexible_search( query: str | int, # Can be either string or integer filters: dict[str, str] | None = None, # Optional dictionary sort_field: str | None = None # Optional string ): """Search with flexible parameter types.""" # Implementation... ``` Modern Python syntax (`str | int`) is preferred over older `Union[str, int]` forms. Similarly, `str | None` is preferred over `Optional[str]`. ### Constrained Types When a parameter must be one of a predefined set of values, you can use either Literal types or Enums: #### Literals Literals constrain parameters to a specific set of values: ```python from typing import Literal @mcp.tool() def sort_data( data: list[float], order: Literal["ascending", "descending"] = "ascending", algorithm: Literal["quicksort", "mergesort", "heapsort"] = "quicksort" ): """Sort data using specific options.""" # Implementation... ``` Literal types: * Specify exact allowable values directly in the type annotation * Help LLMs understand exactly which values are acceptable * Provide input validation (errors for invalid values) * Create clear schemas for clients #### Enums For more structured sets of constrained values, use Python's Enum class: ```python from enum import Enum class Color(Enum): RED = "red" GREEN = "green" BLUE = "blue" @mcp.tool() def process_image( image_path: str, color_filter: Color = Color.RED ): """Process an image with a color filter.""" # Implementation... # color_filter will be a Color enum member ``` When using Enum types: * Clients should provide the enum's value (e.g., "red"), not the enum member name (e.g., "RED") * FastMCP automatically coerces the string value into the appropriate Enum object * Your function receives the actual Enum member (e.g., `Color.RED`) * Validation errors are raised for values not in the enum ### Binary Data There are two approaches to handling binary data in tool parameters: #### Bytes ```python @mcp.tool() def process_binary(data: bytes): """Process binary data directly. The client can send a binary string, which will be converted directly to bytes. """ # Implementation using binary data data_length = len(data) # ... ``` When you annotate a parameter as `bytes`, FastMCP will: * Convert raw strings directly to bytes * Validate that the input can be properly represented as bytes FastMCP does not automatically decode base64-encoded strings for bytes parameters. If you need to accept base64-encoded data, you should handle the decoding manually as shown below. #### Base64-encoded strings ```python from typing import Annotated from pydantic import Field @mcp.tool() def process_image_data( image_data: Annotated[str, Field(description="Base64-encoded image data")] ): """Process an image from base64-encoded string. The client is expected to provide base64-encoded data as a string. You'll need to decode it manually. """ # Manual base64 decoding import base64 binary_data = base64.b64decode(image_data) # Process binary_data... ``` This approach is recommended when you expect to receive base64-encoded binary data from clients. ### Paths The `Path` type from the `pathlib` module can be used for file system paths: ```python from pathlib import Path @mcp.tool() def process_file(path: Path) -> str: """Process a file at the given path.""" assert isinstance(path, Path) # Path is properly converted return f"Processing file at {path}" ``` When a client sends a string path, FastMCP automatically converts it to a `Path` object. ### UUIDs The `UUID` type from the `uuid` module can be used for unique identifiers: ```python import uuid @mcp.tool() def process_item( item_id: uuid.UUID # String UUID or UUID object ) -> str: """Process an item with the given UUID.""" assert isinstance(item_id, uuid.UUID) # Properly converted to UUID return f"Processing item {item_id}" ``` When a client sends a string UUID (e.g., "123e4567-e89b-12d3-a456-426614174000"), FastMCP automatically converts it to a `UUID` object. ### Pydantic Models For complex, structured data with nested fields and validation, use Pydantic models: ```python from pydantic import BaseModel, Field from typing import Optional class User(BaseModel): username: str email: str = Field(description="User's email address") age: int | None = None is_active: bool = True @mcp.tool() def create_user(user: User): """Create a new user in the system.""" # The input is automatically validated against the User model # Even if provided as a JSON string or dict # Implementation... ``` Using Pydantic models provides: * Clear, self-documenting structure for complex inputs * Built-in data validation * Automatic generation of detailed JSON schemas for the LLM * Automatic conversion from dict/JSON input Clients can provide data for Pydantic model parameters as either: * A JSON object (string) * A dictionary with the appropriate structure * Nested parameters in the appropriate format ### Pydantic Fields FastMCP supports robust parameter validation through Pydantic's `Field` class. This is especially useful to ensure that input values meet specific requirements beyond just their type. Note that fields can be used *outside* Pydantic models to provide metadata and validation constraints. The preferred approach is using `Annotated` with `Field`: ```python from typing import Annotated from pydantic import Field @mcp.tool() def analyze_metrics( # Numbers with range constraints count: Annotated[int, Field(ge=0, le=100)], # 0 <= count <= 100 ratio: Annotated[float, Field(gt=0, lt=1.0)], # 0 < ratio < 1.0 # String with pattern and length constraints user_id: Annotated[str, Field( pattern=r"^[A-Z]{2}\d{4}$", # Must match regex pattern description="User ID in format XX0000" )], # String with length constraints comment: Annotated[str, Field(min_length=3, max_length=500)] = "", # Numeric constraints factor: Annotated[int, Field(multiple_of=5)] = 10, # Must be multiple of 5 ): """Analyze metrics with validated parameters.""" # Implementation... ``` You can also use `Field` as a default value, though the `Annotated` approach is preferred: ```python @mcp.tool() def validate_data( # Value constraints age: int = Field(ge=0, lt=120), # 0 <= age < 120 # String constraints email: str = Field(pattern=r"^[\w\.-]+@[\w\.-]+\.\w+$"), # Email pattern # Collection constraints tags: list[str] = Field(min_length=1, max_length=10) # 1-10 tags ): """Process data with field validations.""" # Implementation... ``` Common validation options include: | Validation | Type | Description | | :------------------------- | :----------------- | :--------------------------------------------- | | `ge`, `gt` | Number | Greater than (or equal) constraint | | `le`, `lt` | Number | Less than (or equal) constraint | | `multiple_of` | Number | Value must be a multiple of this number | | `min_length`, `max_length` | String, List, etc. | Length constraints | | `pattern` | String | Regular expression pattern constraint | | `description` | Any | Human-readable description (appears in schema) | When a client sends invalid data, FastMCP will return a validation error explaining why the parameter failed validation. ## Server Behavior ### Duplicate Tools You can control how the FastMCP server behaves if you try to register multiple tools with the same name. This is configured using the `on_duplicate_tools` argument when creating the `FastMCP` instance. ```python from fastmcp import FastMCP mcp = FastMCP( name="StrictServer", # Configure behavior for duplicate tool names on_duplicate_tools="error" ) @mcp.tool() def my_tool(): return "Version 1" # This will now raise a ValueError because 'my_tool' already exists # and on_duplicate_tools is set to "error". # @mcp.tool() # def my_tool(): return "Version 2" ``` The duplicate behavior options are: * `"warn"` (default): Logs a warning and the new tool replaces the old one. * `"error"`: Raises a `ValueError`, preventing the duplicate registration. * `"replace"`: Silently replaces the existing tool with the new one. * `"ignore"`: Keeps the original tool and ignores the new registration attempt. ### Removing Tools You can dynamically remove tools from a server using the `remove_tool` method: ```python from fastmcp import FastMCP mcp = FastMCP(name="DynamicToolServer") @mcp.tool() def calculate_sum(a: int, b: int) -> int: """Add two numbers together.""" return a + b mcp.remove_tool("calculate_sum") ``` ### Legacy JSON Parsing FastMCP 1.0 and \< 2.2.10 relied on a crutch that attempted to work around LLM limitations by automatically parsing stringified JSON in tool arguments (e.g., converting `"[1,2,3]"` to `[1,2,3]`). As of FastMCP 2.2.10, this behavior is disabled by default because it circumvents type validation and can lead to unexpected type coercion issues (e.g. parsing "true" as a bool and attempting to call a tool that expected a string, which would fail type validation). Most modern LLMs correctly format JSON, but if working with models that unnecessarily stringify JSON (as was the case with Claude Desktop in late 2024), you can re-enable this behavior on your server by setting the environment variable `FASTMCP_TOOL_ATTEMPT_PARSE_JSON_ARGS=1`. We strongly recommend leaving this disabled unless necessary.