Files
wehub-resource-sync 60e0ffc959
Upgrade checks / Notify on failure (push) Has been cancelled
Upgrade checks / Close issue on success (push) Has been cancelled
Schema Crash Test / Real-world schema crash test (232K schemas) (push) Has been cancelled
Run static analysis / static_analysis (push) Has been cancelled
Tests / Tests: Python 3.10 on ubuntu-latest (push) Has been cancelled
Tests / Tests: Python 3.13 on ubuntu-latest (push) Has been cancelled
Tests / Tests: Python 3.10 on windows-latest (push) Has been cancelled
Tests / Tests with lowest-direct dependencies (push) Has been cancelled
Tests / MCP conformance tests (push) Has been cancelled
Tests / Integration tests (push) Has been cancelled
Tests / Package install smoke (push) Has been cancelled
Upgrade checks / Static analysis (push) Has been cancelled
Upgrade checks / Tests: Python 3.10 on ubuntu-latest (push) Has been cancelled
Upgrade checks / Tests: Python 3.13 on ubuntu-latest (push) Has been cancelled
Upgrade checks / Tests: Python 3.10 on windows-latest (push) Has been cancelled
Upgrade checks / Integration tests (push) Has been cancelled
Update MCPServerConfig Schema / update-config-schema (push) Has been cancelled
Update SDK Documentation / update-sdk-docs (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:59 +08:00

312 lines
12 KiB
Plaintext

---
title: The FastMCP Client
sidebarTitle: Overview
description: Programmatic client for interacting with MCP servers through a well-typed, Pythonic interface.
icon: user-robot
---
import { VersionBadge } from '/snippets/version-badge.mdx'
<VersionBadge version="2.0.0" />
The `fastmcp.Client` class provides a programmatic interface for interacting with any MCP server. It handles protocol details and connection management automatically, letting you focus on the operations you want to perform.
The FastMCP Client is designed for deterministic, controlled interactions rather than autonomous behavior, making it ideal for testing MCP servers during development, building deterministic applications that need reliable MCP interactions, and creating the foundation for agentic or LLM-based clients with structured, type-safe operations.
<Note>
This is a programmatic client that requires explicit function calls and provides direct control over all MCP operations. Use it as a building block for higher-level systems.
</Note>
## Creating a Client
You provide a server source and the client automatically infers the appropriate transport mechanism.
```python
import asyncio
from fastmcp import Client, FastMCP
# In-memory server (ideal for testing)
server = FastMCP("TestServer")
client = Client(server)
# HTTP server
client = Client("https://example.com/mcp")
# Local Python script
client = Client("my_mcp_server.py")
async def main():
async with client:
# Basic server interaction
await client.ping()
# List available operations
tools = await client.list_tools()
resources = await client.list_resources()
prompts = await client.list_prompts()
# Execute operations
result = await client.call_tool("example_tool", {"param": "value"})
print(result)
asyncio.run(main())
```
All client operations require using the `async with` context manager for proper connection lifecycle management.
## Choosing a Transport
The client automatically selects a transport based on what you pass to it, but different transports have different characteristics that matter for your use case.
**In-memory transport** connects directly to a FastMCP server instance within the same Python process. Use this for testing and development where you want to eliminate subprocess and network complexity. The server shares your process's environment and memory space.
```python
from fastmcp import Client, FastMCP
server = FastMCP("TestServer")
client = Client(server) # In-memory, no network or subprocess
```
**STDIO transport** launches a server as a subprocess and communicates through stdin/stdout pipes. This is the standard mechanism used by desktop clients like Claude Desktop. The subprocess runs in an isolated environment, so you must explicitly pass any environment variables the server needs.
```python
from fastmcp import Client
# Simple inference from file path
client = Client("my_server.py")
# With explicit environment configuration
client = Client("my_server.py", env={"API_KEY": "secret"})
```
**HTTP transport** connects to servers running as web services. Use this for production deployments where the server runs independently and manages its own lifecycle.
```python
from fastmcp import Client
client = Client("https://api.example.com/mcp")
```
See [Transports](/clients/transports) for detailed configuration options including authentication headers, session persistence, and multi-server configurations.
## Configuration-Based Clients
<VersionBadge version="2.4.0" />
Create clients from MCP configuration dictionaries, which can include multiple servers. While there is no official standard for MCP configuration format, FastMCP follows established conventions used by tools like Claude Desktop.
```python
config = {
"mcpServers": {
"weather": {
"url": "https://weather-api.example.com/mcp"
},
"assistant": {
"command": "python",
"args": ["./assistant_server.py"]
}
}
}
client = Client(config)
async with client:
# Tools are prefixed with server names
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?"})
# Resources use prefixed URIs
icons = await client.read_resource("weather://weather/icons/sunny")
```
## Connection Lifecycle
The client uses context managers for connection management. When you enter the context, the client establishes a connection and performs an MCP initialization handshake with the server. This handshake exchanges capabilities, server metadata, and instructions.
```python
from fastmcp import Client, FastMCP
mcp = FastMCP(name="MyServer", instructions="Use the greet tool to say hello!")
@mcp.tool
def greet(name: str) -> str:
"""Greet a user by name."""
return f"Hello, {name}!"
async with Client(mcp) as client:
# Initialization already happened automatically
print(f"Server: {client.initialize_result.server_info.name}")
print(f"Instructions: {client.initialize_result.instructions}")
print(f"Capabilities: {client.initialize_result.capabilities.tools}")
```
For advanced scenarios where you need precise control over when initialization happens, disable automatic initialization and call `initialize()` manually:
```python
from fastmcp import Client
client = Client("my_mcp_server.py", auto_initialize=False)
async with client:
# Connection established, but not initialized yet
print(f"Connected: {client.is_connected()}")
print(f"Initialized: {client.initialize_result is not None}") # False
# Initialize manually with custom timeout
result = await client.initialize(timeout=10.0)
print(f"Server: {result.server_info.name}")
# Now ready for operations
tools = await client.list_tools()
```
## Protocol negotiation
<VersionBadge version="4.0.0" />
MCP has two protocol eras: the original *legacy* era, which begins every connection with an `initialize` handshake, and the *modern* era (protocol version `2026-07-28` and later), which a client discovers by probing the server's `server/discover` endpoint. The `mode` parameter controls which era the client negotiates when it connects.
By default, `mode="legacy"`. This runs the initialize handshake and behaves identically to earlier FastMCP versions, so existing code connecting to any server keeps working unchanged.
```python
from fastmcp import Client
# Legacy handshake (the default)
client = Client("https://example.com/mcp", mode="legacy")
```
Set `mode="auto"` to negotiate the newest era the server supports. The client probes `server/discover` and adopts the modern protocol when the server responds; for any server that is not positive evidence of modern support, it falls back to the legacy handshake. This makes `"auto"` safe to use against a mixed fleet of legacy and modern servers.
```python
client = Client("https://example.com/mcp", mode="auto")
```
You can also pin a specific modern protocol version to adopt it directly, without a discovery probe:
```python
client = Client("https://example.com/mcp", mode="2026-07-28")
```
Once connected, the negotiated version and the server's advertised capabilities are available as properties. Both are populated regardless of which era was negotiated, and both are `None` while the client is disconnected.
```python
async with Client("https://example.com/mcp", mode="auto") as client:
print(client.protocol_version) # e.g. "2026-07-28"
print(client.server_capabilities) # ServerCapabilities | None
```
<Note>
`mode="auto"` is not the default yet — the conservative `"legacy"` remains the default to preserve byte-identical behavior against pre-2026 servers. Whether `"auto"` becomes the default is a future release decision.
</Note>
## Response caching
<VersionBadge version="4.0.0" />
The client can cache the results of `list_tools`, `list_resources`, `list_prompts`, and `read_resource` so that repeated calls avoid a network round-trip. Caching is opt-in and honors the server's own cache hints, so it only takes effect against modern-era servers that advertise them — a cache is inert on a legacy connection.
Enable the default in-memory cache by passing `cache=True`. It respects the `ttlMs` and `cacheScope` hints the server attaches to each response.
```python
from fastmcp import Client
client = Client("https://example.com/mcp", mode="auto", cache=True)
async with client:
tools = await client.list_tools() # fetched from the server
tools = await client.list_tools() # served from the cache
```
The default (`cache=None`) and `cache=False` both disable caching. For control over the store, TTL, or partitioning, pass a `CacheConfig`. A custom config requires a `target_id`, since in-memory FastMCP transports expose no server URL to derive a shared-store identity from.
```python
from fastmcp import Client
from mcp.client.caching import CacheConfig
config = CacheConfig(target_id="weather-api", default_ttl_ms=60_000)
client = Client("https://example.com/mcp", mode="auto", cache=config)
```
The high-level `list_tools`, `list_resources`, `list_prompts`, and `read_resource` methods always use the cache when one is configured. To override the behavior for a single call, use the lower-level `*_mcp` variants, which accept a `cache_mode` argument: `"use"` (the default) serves and stores, `"refresh"` stores a fresh result without serving a cached one, and `"bypass"` skips the cache entirely.
```python
async with client:
fresh = await client.list_tools_mcp(cache_mode="refresh")
```
## Operations
FastMCP clients interact with three types of server components.
**Tools** are server-side functions that the client can execute with arguments. Call them with `call_tool()` and receive structured results.
```python
async with client:
tools = await client.list_tools()
result = await client.call_tool("multiply", {"a": 5, "b": 3})
print(result.data) # 15
```
See [Tools](/clients/tools) for detailed documentation including version selection, error handling, and structured output.
**Resources** are data sources that the client can read, either static or templated. Access them with `read_resource()` using URIs.
```python
async with client:
resources = await client.list_resources()
content = await client.read_resource("file:///config/settings.json")
print(content[0].text)
```
See [Resources](/clients/resources) for detailed documentation including templates and binary content.
**Prompts** are reusable message templates that can accept arguments. Retrieve rendered prompts with `get_prompt()`.
```python
async with client:
prompts = await client.list_prompts()
messages = await client.get_prompt("analyze_data", {"data": [1, 2, 3]})
print(messages.messages)
```
See [Prompts](/clients/prompts) for detailed documentation including argument serialization.
## Callback Handlers
The client supports callback handlers for advanced server interactions. These let you respond to server-initiated requests and receive notifications.
```python
from fastmcp import Client
from fastmcp.client.logging import LogMessage
async def log_handler(message: LogMessage):
print(f"Server log: {message.data}")
async def progress_handler(progress: float, total: float | None, message: str | None):
print(f"Progress: {progress}/{total} - {message}")
async def sampling_handler(messages, params, context):
# Integrate with your LLM service here
return "Generated response"
client = Client(
"my_mcp_server.py",
log_handler=log_handler,
progress_handler=progress_handler,
sampling_handler=sampling_handler,
timeout=30.0
)
```
Each handler type has its own documentation:
- **[Sampling](/clients/sampling)** - Respond to server LLM requests
- **[Elicitation](/clients/elicitation)** - Handle server requests for user input
- **[Progress](/clients/progress)** - Monitor long-running operations
- **[Logging](/clients/logging)** - Handle server log messages
- **[Roots](/clients/roots)** - Provide local context to servers
<Tip>
The FastMCP Client is designed as a foundational tool. Use it directly for deterministic operations, or build higher-level agentic systems on top of its reliable, type-safe interface.
</Tip>