Add documentation for config-based clients

This commit is contained in:
Jeremiah Lowin 2025-05-20 21:05:44 -04:00
commit 35e20774c0
7 changed files with 264 additions and 5 deletions

View file

@ -43,7 +43,8 @@ The following inference rules are used to determine the appropriate `ClientTrans
* 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. **Other**: Raises a `ValueError` if the type cannot be inferred.
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
@ -76,6 +77,65 @@ print(client_stdio.transport)
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.
</Tip>
### Multi-Server Clients
<VersionBadge version="2.3.6" />
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.
<Note>
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.
</Note>
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
from fastmcp.utilities.mcp_config import MCPConfig
# 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

View file

@ -317,4 +317,65 @@ async def main():
asyncio.run(main())
```
Communication happens through efficient in-memory queues, making it very fast and ideal for unit testing.
Communication happens through efficient in-memory queues, making it very fast and ideal for unit testing.
## Configuration-Based Transports
### MCPConfig Transport
<VersionBadge version="2.3.6" />
- **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
from fastmcp.utilities.mcp_config import MCPConfig
# 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.
<Note>
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.
</Note>

View file

@ -67,8 +67,8 @@
"group": "Clients",
"pages": [
"clients/client",
"clients/features",
"clients/transports"
"clients/transports",
"clients/advanced-features"
]
},
{

View file

@ -35,6 +35,10 @@ The choice of importing or mounting depends on your use case and requirements.
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.
<VersionBadge version="2.3.6" />
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.

View file

@ -104,6 +104,64 @@ proxy = FastMCP.as_proxy(
# requests to original_server
```
### Configuration-Based Proxies
<VersionBadge version="2.3.6" />
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()
```
<Note>
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.
</Note>
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.

View file

@ -474,7 +474,52 @@ class FastMCPTransport(ClientTransport):
class MCPConfigTransport(ClientTransport):
"""Transport for running MCPConfig."""
"""Transport for connecting to one or more MCP servers defined in an MCPConfig.
This transport provides a unified interface to multiple MCP servers defined in an MCPConfig
object or dictionary matching the MCPConfig schema. It supports two key scenarios:
1. If the MCPConfig contains exactly one server, it creates a direct transport to that server.
2. If the MCPConfig contains multiple servers, it creates a composite client by mounting
all servers on a single FastMCP instance, with each server's name used as its mounting prefix.
In the multi-server case, tools are accessible with the prefix pattern `{server_name}_{tool_name}`
and resources with the pattern `protocol://{server_name}/path/to/resource`.
This is particularly useful for creating clients that need to interact with multiple specialized
MCP servers through a single interface, simplifying client code.
Examples:
```python
from fastmcp import Client
from fastmcp.utilities.mcp_config import MCPConfig
# Create a config with multiple servers
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 client with the config
client = Client(config)
async with client:
# Access tools with prefixes
weather = await client.call_tool("weather_get_forecast", {"city": "London"})
events = await client.call_tool("calendar_list_events", {"date": "2023-06-01"})
# Access resources with prefixed URIs
icons = await client.read_resource("weather://weather/icons/sunny")
```
"""
def __init__(self, config: MCPConfig | dict):
from fastmcp.client.client import Client
@ -526,7 +571,38 @@ def infer_transport(
argument, handling various input types and converting them to the appropriate
ClientTransport subclass.
The function supports these input types:
- ClientTransport: Used directly without modification
- FastMCPServer: Creates an in-memory FastMCPTransport
- Path or str (file path): Creates PythonStdioTransport (.py) or NodeStdioTransport (.js)
- AnyUrl or str (URL): Creates StreamableHttpTransport (default) or SSETransport (for /sse endpoints)
- MCPConfig or dict: Creates MCPConfigTransport, potentially connecting to multiple servers
For HTTP URLs, they are assumed to be Streamable HTTP URLs unless they end in `/sse`.
For MCPConfig with multiple servers, a composite client is created where each server
is mounted with its name as prefix. This allows accessing tools and resources from multiple
servers through a single unified client interface, using naming patterns like
`servername_toolname` for tools and `protocol://servername/path` for resources.
If the MCPConfig contains only one server, a direct connection is established without prefixing.
Examples:
```python
# Connect to a local Python script
transport = infer_transport("my_script.py")
# Connect to a remote server via HTTP
transport = infer_transport("http://example.com/mcp")
# Connect to multiple servers using MCPConfig
config = {
"mcpServers": {
"weather": {"url": "http://weather.example.com/mcp"},
"calendar": {"url": "http://calendar.example.com/mcp"}
}
}
transport = infer_transport(config)
```
"""
from fastmcp.utilities.mcp_config import MCPConfig