Spaces:
Running
Running
Jeremiah Lowin commited on
Commit ·
bc18d08
1
Parent(s): 2e1c8b2
Update transport docs
Browse files- .gitignore +3 -0
- docs/clients/transports.mdx +169 -308
- docs/docs.json +1 -1
.gitignore
CHANGED
|
@@ -60,3 +60,6 @@ dmypy.json
|
|
| 60 |
*.sqlite
|
| 61 |
*.db
|
| 62 |
*.ddb
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
*.sqlite
|
| 61 |
*.db
|
| 62 |
*.ddb
|
| 63 |
+
|
| 64 |
+
# Claude worktree management
|
| 65 |
+
.claude-wt/worktrees
|
docs/clients/transports.mdx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
---
|
| 2 |
title: Client Transports
|
| 3 |
sidebarTitle: Transports
|
| 4 |
-
description:
|
| 5 |
icon: link
|
| 6 |
---
|
| 7 |
|
|
@@ -9,441 +9,302 @@ import { VersionBadge } from "/snippets/version-badge.mdx"
|
|
| 9 |
|
| 10 |
<VersionBadge version="2.0.0" />
|
| 11 |
|
| 12 |
-
The FastMCP `Client`
|
| 13 |
|
| 14 |
-
|
| 15 |
|
| 16 |
-
|
| 17 |
-
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.
|
| 18 |
-
</Tip>
|
| 19 |
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
-
|
| 23 |
|
| 24 |
-
|
| 25 |
|
| 26 |
-
|
| 27 |
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
These transports connect to servers running over a network, typically long-running services accessible via URLs.
|
| 33 |
-
|
| 34 |
-
### Streamable HTTP
|
| 35 |
|
| 36 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
-
|
| 39 |
|
| 40 |
-
###
|
| 41 |
|
| 42 |
-
|
| 43 |
-
- **Inferred From:** URLs starting with `http://` or `https://` (default for HTTP URLs since v2.3.0) that do not contain `/sse/` in the path
|
| 44 |
-
- **Server Compatibility:** Works with FastMCP servers running in `http` mode
|
| 45 |
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
-
|
| 49 |
|
| 50 |
```python
|
| 51 |
from fastmcp import Client
|
| 52 |
-
import asyncio
|
| 53 |
-
|
| 54 |
-
# The Client automatically uses StreamableHttpTransport for HTTP URLs
|
| 55 |
-
client = Client("https://example.com/mcp")
|
| 56 |
-
|
| 57 |
-
async def main():
|
| 58 |
-
async with client:
|
| 59 |
-
tools = await client.list_tools()
|
| 60 |
-
print(f"Available tools: {tools}")
|
| 61 |
-
|
| 62 |
-
asyncio.run(main())
|
| 63 |
-
```
|
| 64 |
-
|
| 65 |
-
You can also explicitly instantiate the transport:
|
| 66 |
|
| 67 |
-
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
|
| 70 |
-
|
| 71 |
-
|
|
|
|
| 72 |
```
|
| 73 |
|
| 74 |
-
###
|
| 75 |
|
| 76 |
-
|
| 77 |
|
| 78 |
```python
|
| 79 |
-
from fastmcp import
|
| 80 |
-
from fastmcp.client.transports import StreamableHttpTransport
|
| 81 |
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
headers={"Authorization": "Bearer your-token-here"}
|
| 86 |
)
|
| 87 |
-
|
| 88 |
client = Client(transport)
|
| 89 |
```
|
| 90 |
|
| 91 |
-
|
| 92 |
|
| 93 |
```python
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
"
|
| 99 |
-
auth=BearerAuth("your-token-here"),
|
| 100 |
)
|
|
|
|
| 101 |
```
|
| 102 |
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
<VersionBadge version="2.0.0" />
|
| 106 |
-
|
| 107 |
-
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.
|
| 108 |
-
|
| 109 |
-
#### Overview
|
| 110 |
-
|
| 111 |
-
- **Class:** `fastmcp.client.transports.SSETransport`
|
| 112 |
-
- **Inferred From:** HTTP URLs containing `/sse/` in the path
|
| 113 |
-
- **Server Compatibility:** Works with FastMCP servers running in `sse` mode
|
| 114 |
-
|
| 115 |
-
#### Basic Usage
|
| 116 |
-
|
| 117 |
-
The simplest way to use SSE is to let the transport be inferred from a URL with `/sse/` in the path:
|
| 118 |
|
| 119 |
```python
|
| 120 |
from fastmcp import Client
|
| 121 |
-
import asyncio
|
| 122 |
|
| 123 |
-
|
| 124 |
-
|
| 125 |
|
| 126 |
-
|
| 127 |
-
async with client:
|
| 128 |
-
tools = await client.list_tools()
|
| 129 |
-
print(f"Available tools: {tools}")
|
| 130 |
|
| 131 |
-
|
| 132 |
-
```
|
| 133 |
|
| 134 |
-
|
| 135 |
|
| 136 |
```python
|
| 137 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
|
| 139 |
-
transport =
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
client = Client(transport)
|
| 141 |
```
|
| 142 |
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
SSE transport also supports custom headers for authentication:
|
| 146 |
|
| 147 |
```python
|
| 148 |
-
from
|
| 149 |
-
from fastmcp.client.transports import
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
transport =
|
| 153 |
-
|
| 154 |
-
|
|
|
|
| 155 |
)
|
| 156 |
-
|
| 157 |
client = Client(transport)
|
| 158 |
```
|
| 159 |
|
| 160 |
-
###
|
| 161 |
-
|
| 162 |
-
- **Use Streamable HTTP when:**
|
| 163 |
-
- Setting up new deployments (recommended default)
|
| 164 |
-
- You need bidirectional streaming
|
| 165 |
-
- You're connecting to FastMCP servers running in `http` mode
|
| 166 |
-
|
| 167 |
-
- **Use SSE when:**
|
| 168 |
-
- Connecting to legacy FastMCP servers running in `sse` mode
|
| 169 |
-
- Working with infrastructure optimized for Server-Sent Events
|
| 170 |
-
|
| 171 |
-
## Local Transports
|
| 172 |
|
| 173 |
-
|
| 174 |
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
All stdio transports support a `keep_alive` parameter (default: `True`) that controls session persistence across multiple client context managers:
|
| 178 |
-
|
| 179 |
-
- **`keep_alive=True` (default)**: The subprocess and session are maintained between client context exits and re-entries. This improves performance when making multiple separate connections to the same server.
|
| 180 |
-
- **`keep_alive=False`**: A new subprocess is started for each client context, ensuring complete isolation between sessions.
|
| 181 |
-
|
| 182 |
-
When `keep_alive=True`, you can manually close the session using `await client.close()` if needed. This will terminate the subprocess and require a new one to be started on the next connection.
|
| 183 |
-
|
| 184 |
-
<CodeGroup>
|
| 185 |
-
```python keep_alive=True
|
| 186 |
-
from fastmcp import Client
|
| 187 |
-
|
| 188 |
-
# Client with keep_alive=True (default)
|
| 189 |
-
client = Client("my_mcp_server.py")
|
| 190 |
-
|
| 191 |
-
async def example():
|
| 192 |
-
# First session
|
| 193 |
-
async with client:
|
| 194 |
-
await client.ping()
|
| 195 |
-
|
| 196 |
-
# Second session - uses the same subprocess
|
| 197 |
-
async with client:
|
| 198 |
-
await client.ping()
|
| 199 |
-
|
| 200 |
-
# Manually close the session
|
| 201 |
-
await client.close()
|
| 202 |
-
|
| 203 |
-
# Third session - will start a new subprocess
|
| 204 |
-
async with client:
|
| 205 |
-
await client.ping()
|
| 206 |
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
```python keep_alive=False
|
| 210 |
-
from fastmcp import Client
|
| 211 |
|
| 212 |
-
|
| 213 |
-
|
|
|
|
|
|
|
|
|
|
| 214 |
|
| 215 |
-
async def
|
| 216 |
-
# First session
|
| 217 |
async with client:
|
| 218 |
await client.ping()
|
| 219 |
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
|
| 224 |
-
|
| 225 |
-
async with client:
|
| 226 |
-
await client.ping()
|
| 227 |
|
| 228 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 229 |
```
|
| 230 |
-
</CodeGroup>
|
| 231 |
-
|
| 232 |
-
### Python Stdio
|
| 233 |
|
| 234 |
-
|
| 235 |
-
- **Inferred From:** Paths to `.py` files
|
| 236 |
-
- **Use Case:** Running a Python-based MCP server script in a subprocess
|
| 237 |
|
| 238 |
-
|
| 239 |
|
| 240 |
-
``
|
| 241 |
-
from fastmcp import Client
|
| 242 |
-
from fastmcp.client.transports import PythonStdioTransport
|
| 243 |
|
| 244 |
-
|
|
|
|
|
|
|
|
|
|
| 245 |
|
| 246 |
-
|
| 247 |
-
client = Client(server_script)
|
| 248 |
|
| 249 |
-
#
|
| 250 |
-
transport = PythonStdioTransport(
|
| 251 |
-
script_path=server_script,
|
| 252 |
-
python_cmd="/usr/bin/python3.11", # Optional: specify Python interpreter
|
| 253 |
-
# args=["--some-server-arg"], # Optional: pass arguments to the script
|
| 254 |
-
# env={"MY_VAR": "value"}, # Optional: set environment variables
|
| 255 |
-
)
|
| 256 |
-
client = Client(transport)
|
| 257 |
|
| 258 |
-
|
| 259 |
-
async with client:
|
| 260 |
-
tools = await client.list_tools()
|
| 261 |
-
print(f"Connected via Python Stdio, found tools: {tools}")
|
| 262 |
|
| 263 |
-
|
| 264 |
-
```
|
| 265 |
|
| 266 |
-
<
|
| 267 |
-
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.
|
| 268 |
-
</Warning>
|
| 269 |
|
| 270 |
-
|
| 271 |
|
| 272 |
-
- **Class:** `
|
| 273 |
-
- **
|
| 274 |
-
- **Use Case:** Running a Node.js-based MCP server script in a subprocess
|
| 275 |
|
| 276 |
-
|
| 277 |
|
| 278 |
```python
|
| 279 |
-
from fastmcp import
|
| 280 |
-
from fastmcp.client.transports import NodeStdioTransport
|
| 281 |
-
|
| 282 |
-
node_server_script = "my_mcp_server.js" # Path to your Node.js server script
|
| 283 |
|
| 284 |
-
#
|
| 285 |
-
|
|
|
|
| 286 |
|
| 287 |
-
#
|
| 288 |
-
transport =
|
| 289 |
-
|
| 290 |
-
|
|
|
|
|
|
|
|
|
|
| 291 |
)
|
| 292 |
client = Client(transport)
|
| 293 |
-
|
| 294 |
-
async def main():
|
| 295 |
-
async with client:
|
| 296 |
-
tools = await client.list_tools()
|
| 297 |
-
print(f"Connected via Node.js Stdio, found tools: {tools}")
|
| 298 |
-
|
| 299 |
-
asyncio.run(main())
|
| 300 |
```
|
| 301 |
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
- **Class:** `fastmcp.client.transports.UvxStdioTransport`
|
| 305 |
-
- **Inferred From:** Not automatically inferred
|
| 306 |
-
- **Use Case:** Running an MCP server packaged as a Python tool using [`uvx`](https://docs.astral.sh/uv/reference/cli/#uvx)
|
| 307 |
-
|
| 308 |
-
This is useful for executing MCP servers distributed as command-line tools or packages without installing them into your environment.
|
| 309 |
|
| 310 |
```python
|
| 311 |
-
from fastmcp import
|
| 312 |
-
from fastmcp.client.transports import UvxStdioTransport
|
| 313 |
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
# from_package="cloud-analyzer-cli", # Optional: specify package if tool name differs
|
| 318 |
-
# with_packages=["boto3", "requests"] # Optional: add dependencies
|
| 319 |
)
|
| 320 |
-
client = Client(transport)
|
| 321 |
-
|
| 322 |
-
async def main():
|
| 323 |
-
async with client:
|
| 324 |
-
result = await client.call_tool("analyze_bucket", {"name": "my-data"})
|
| 325 |
-
print(f"Analysis result: {result}")
|
| 326 |
-
|
| 327 |
-
asyncio.run(main())
|
| 328 |
```
|
| 329 |
|
| 330 |
-
###
|
|
|
|
|
|
|
| 331 |
|
| 332 |
-
- **Class:** `
|
| 333 |
-
- **
|
| 334 |
-
- **Use Case:** Running an MCP server packaged as an NPM package using `npx`
|
| 335 |
|
| 336 |
-
|
| 337 |
|
| 338 |
```python
|
| 339 |
-
from fastmcp import
|
| 340 |
-
from fastmcp.client.transports import NpxStdioTransport
|
| 341 |
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
# args=["--port", "stdio"] # Optional: pass arguments to the package
|
| 346 |
)
|
| 347 |
client = Client(transport)
|
| 348 |
-
|
| 349 |
-
async def main():
|
| 350 |
-
async with client:
|
| 351 |
-
result = await client.call_tool("get_npm_data", {})
|
| 352 |
-
print(f"Result: {result}")
|
| 353 |
-
|
| 354 |
-
asyncio.run(main())
|
| 355 |
```
|
| 356 |
|
| 357 |
-
|
| 358 |
|
| 359 |
-
##
|
| 360 |
|
| 361 |
-
-
|
| 362 |
-
- **Inferred From:** An instance of `fastmcp.server.FastMCP` or a **FastMCP 1.0 server** (`mcp.server.fastmcp.FastMCP`)
|
| 363 |
-
- **Use Case:** Connecting directly to a FastMCP server instance in the same Python process
|
| 364 |
|
| 365 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 366 |
|
| 367 |
```python
|
| 368 |
from fastmcp import FastMCP, Client
|
| 369 |
-
import
|
| 370 |
-
|
| 371 |
-
# 1. Create your FastMCP server instance
|
| 372 |
-
server = FastMCP(name="InMemoryServer")
|
| 373 |
|
| 374 |
-
|
| 375 |
-
def ping():
|
| 376 |
-
return "pong"
|
| 377 |
|
| 378 |
-
|
| 379 |
-
|
|
|
|
|
|
|
| 380 |
|
| 381 |
-
|
| 382 |
-
async with client:
|
| 383 |
-
result = await client.call_tool("ping")
|
| 384 |
-
print(f"In-memory call result: {result}")
|
| 385 |
|
| 386 |
-
|
|
|
|
| 387 |
```
|
| 388 |
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
## Configuration-Based Transports
|
| 392 |
-
|
| 393 |
-
### MCPConfig Transport
|
| 394 |
|
| 395 |
<VersionBadge version="2.4.0" />
|
| 396 |
|
| 397 |
-
|
| 398 |
-
- **Inferred From:** An instance of `MCPConfig` or a dictionary matching the MCPConfig schema
|
| 399 |
-
- **Use Case:** Connecting to one or more MCP servers defined in a configuration object
|
| 400 |
|
| 401 |
-
|
| 402 |
|
| 403 |
```python
|
| 404 |
-
from fastmcp import Client
|
| 405 |
-
|
| 406 |
-
# Configuration for multiple MCP servers (both local and remote)
|
| 407 |
config = {
|
| 408 |
"mcpServers": {
|
| 409 |
-
# Remote HTTP server
|
| 410 |
"weather": {
|
| 411 |
-
"url": "https://weather
|
| 412 |
"transport": "http"
|
| 413 |
},
|
| 414 |
-
# Local stdio server
|
| 415 |
"assistant": {
|
| 416 |
"command": "python",
|
| 417 |
-
"args": ["./
|
| 418 |
-
"env": {"
|
| 419 |
-
},
|
| 420 |
-
# Another remote server
|
| 421 |
-
"calendar": {
|
| 422 |
-
"url": "https://calendar-api.example.com/mcp",
|
| 423 |
-
"transport": "http"
|
| 424 |
}
|
| 425 |
}
|
| 426 |
}
|
| 427 |
|
| 428 |
-
# Create a transport from the config (happens automatically with Client)
|
| 429 |
client = Client(config)
|
| 430 |
|
| 431 |
-
async
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
answer = await client.call_tool("assistant_answer_question", {"query": "What is MCP?"})
|
| 436 |
-
events = await client.call_tool("calendar_list_events", {"date": "2023-06-01"})
|
| 437 |
-
|
| 438 |
-
# Resources use prefixed URI paths
|
| 439 |
-
icons = await client.read_resource("weather://weather/icons/sunny")
|
| 440 |
-
docs = await client.read_resource("resource://assistant/docs/mcp")
|
| 441 |
-
|
| 442 |
-
asyncio.run(main())
|
| 443 |
```
|
| 444 |
|
| 445 |
-
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.
|
| 446 |
-
|
| 447 |
-
<Note>
|
| 448 |
-
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.
|
| 449 |
-
</Note>
|
|
|
|
| 1 |
---
|
| 2 |
title: Client Transports
|
| 3 |
sidebarTitle: Transports
|
| 4 |
+
description: Configure how FastMCP Clients connect to and communicate with servers.
|
| 5 |
icon: link
|
| 6 |
---
|
| 7 |
|
|
|
|
| 9 |
|
| 10 |
<VersionBadge version="2.0.0" />
|
| 11 |
|
| 12 |
+
The FastMCP `Client` communicates with MCP servers through transport objects that handle the underlying connection mechanics. While the client can automatically select a transport based on what you pass to it, instantiating transports explicitly gives you full control over configuration—environment variables, authentication, session management, and more.
|
| 13 |
|
| 14 |
+
Think of transports as configurable adapters between your client code and MCP servers. Each transport type handles a different communication pattern: subprocesses with pipes, HTTP connections, or direct in-memory calls.
|
| 15 |
|
| 16 |
+
## Choosing the Right Transport
|
|
|
|
|
|
|
| 17 |
|
| 18 |
+
- **Use [STDIO Transport](#stdio-transport)** when you need to run local MCP servers with full control over their environment and lifecycle
|
| 19 |
+
- **Use [Remote Transports](#remote-transports)** when connecting to production services or shared MCP servers running independently
|
| 20 |
+
- **Use [In-Memory Transport](#in-memory-transport)** for testing FastMCP servers without subprocess or network overhead
|
| 21 |
+
- **Use [MCP JSON Configuration](#mcp-json-configuration-transport)** when you need to connect to multiple servers defined in configuration files
|
| 22 |
|
| 23 |
+
## STDIO Transport
|
| 24 |
|
| 25 |
+
STDIO (Standard Input/Output) transport communicates with MCP servers through subprocess pipes. This is the standard mechanism used by desktop clients like Claude Desktop and is the primary way to run local MCP servers.
|
| 26 |
|
| 27 |
+
### The Client Runs the Server
|
| 28 |
|
| 29 |
+
<Warning>
|
| 30 |
+
**Critical Concept**: When using STDIO transport, your client actually launches and manages the server process. This is fundamentally different from network transports where you connect to an already-running server. Understanding this relationship is key to using STDIO effectively.
|
| 31 |
+
</Warning>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
+
With STDIO transport, your client:
|
| 34 |
+
- Starts the server as a subprocess when you connect
|
| 35 |
+
- Manages the server's lifecycle (start, stop, restart)
|
| 36 |
+
- Controls the server's environment and configuration
|
| 37 |
+
- Communicates through stdin/stdout pipes
|
| 38 |
|
| 39 |
+
This architecture enables powerful local integrations but requires understanding environment isolation and process management.
|
| 40 |
|
| 41 |
+
### Environment Isolation
|
| 42 |
|
| 43 |
+
STDIO servers run in isolated environments by default. This is a security feature enforced by the MCP protocol to prevent accidental exposure of sensitive data.
|
|
|
|
|
|
|
| 44 |
|
| 45 |
+
When your client launches an MCP server:
|
| 46 |
+
- The server does NOT inherit your shell's environment variables
|
| 47 |
+
- API keys, paths, and other configuration must be explicitly passed
|
| 48 |
+
- The working directory and system paths may differ from your shell
|
| 49 |
|
| 50 |
+
To pass environment variables to your server, use the `env` parameter:
|
| 51 |
|
| 52 |
```python
|
| 53 |
from fastmcp import Client
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
+
# If your server needs environment variables (like API keys),
|
| 56 |
+
# you must explicitly pass them:
|
| 57 |
+
client = Client(
|
| 58 |
+
"my_server.py",
|
| 59 |
+
env={"API_KEY": "secret", "DEBUG": "true"}
|
| 60 |
+
)
|
| 61 |
|
| 62 |
+
# This won't work - the server runs in isolation:
|
| 63 |
+
# export API_KEY="secret" # in your shell
|
| 64 |
+
# client = Client("my_server.py") # server can't see API_KEY
|
| 65 |
```
|
| 66 |
|
| 67 |
+
### Basic Usage
|
| 68 |
|
| 69 |
+
To use STDIO transport, you create a transport instance with the command and arguments needed to run your server:
|
| 70 |
|
| 71 |
```python
|
| 72 |
+
from fastmcp.client.transports import StdioTransport
|
|
|
|
| 73 |
|
| 74 |
+
transport = StdioTransport(
|
| 75 |
+
command="python",
|
| 76 |
+
args=["my_server.py"]
|
|
|
|
| 77 |
)
|
|
|
|
| 78 |
client = Client(transport)
|
| 79 |
```
|
| 80 |
|
| 81 |
+
You can configure additional settings like environment variables, working directory, or command arguments:
|
| 82 |
|
| 83 |
```python
|
| 84 |
+
transport = StdioTransport(
|
| 85 |
+
command="python",
|
| 86 |
+
args=["my_server.py", "--verbose"],
|
| 87 |
+
env={"LOG_LEVEL": "DEBUG"},
|
| 88 |
+
cwd="/path/to/server"
|
|
|
|
| 89 |
)
|
| 90 |
+
client = Client(transport)
|
| 91 |
```
|
| 92 |
|
| 93 |
+
For convenience, the client can also infer STDIO transport from file paths, but this doesn't allow configuration:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
|
| 95 |
```python
|
| 96 |
from fastmcp import Client
|
|
|
|
| 97 |
|
| 98 |
+
client = Client("my_server.py") # Limited - no configuration options
|
| 99 |
+
```
|
| 100 |
|
| 101 |
+
### Environment Variables
|
|
|
|
|
|
|
|
|
|
| 102 |
|
| 103 |
+
Since STDIO servers don't inherit your environment, you need strategies for passing configuration. Here are two common approaches:
|
|
|
|
| 104 |
|
| 105 |
+
**Selective forwarding** passes only the variables your server actually needs:
|
| 106 |
|
| 107 |
```python
|
| 108 |
+
import os
|
| 109 |
+
from fastmcp.client.transports import StdioTransport
|
| 110 |
+
|
| 111 |
+
required_vars = ["API_KEY", "DATABASE_URL", "REDIS_HOST"]
|
| 112 |
+
env = {
|
| 113 |
+
var: os.environ[var]
|
| 114 |
+
for var in required_vars
|
| 115 |
+
if var in os.environ
|
| 116 |
+
}
|
| 117 |
|
| 118 |
+
transport = StdioTransport(
|
| 119 |
+
command="python",
|
| 120 |
+
args=["server.py"],
|
| 121 |
+
env=env
|
| 122 |
+
)
|
| 123 |
client = Client(transport)
|
| 124 |
```
|
| 125 |
|
| 126 |
+
**Loading from .env files** keeps configuration separate from code:
|
|
|
|
|
|
|
| 127 |
|
| 128 |
```python
|
| 129 |
+
from dotenv import dotenv_values
|
| 130 |
+
from fastmcp.client.transports import StdioTransport
|
| 131 |
+
|
| 132 |
+
env = dotenv_values(".env")
|
| 133 |
+
transport = StdioTransport(
|
| 134 |
+
command="python",
|
| 135 |
+
args=["server.py"],
|
| 136 |
+
env=env
|
| 137 |
)
|
|
|
|
| 138 |
client = Client(transport)
|
| 139 |
```
|
| 140 |
|
| 141 |
+
### Session Persistence
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 142 |
|
| 143 |
+
STDIO transports maintain sessions across multiple client contexts by default (`keep_alive=True`). This improves performance by reusing the same subprocess for multiple connections, but can be controlled when you need isolation.
|
| 144 |
|
| 145 |
+
By default, the subprocess persists between connections:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
|
| 147 |
+
```python
|
| 148 |
+
from fastmcp.client.transports import StdioTransport
|
|
|
|
|
|
|
| 149 |
|
| 150 |
+
transport = StdioTransport(
|
| 151 |
+
command="python",
|
| 152 |
+
args=["server.py"]
|
| 153 |
+
)
|
| 154 |
+
client = Client(transport)
|
| 155 |
|
| 156 |
+
async def efficient_multiple_operations():
|
|
|
|
| 157 |
async with client:
|
| 158 |
await client.ping()
|
| 159 |
|
| 160 |
+
async with client: # Reuses the same subprocess
|
| 161 |
+
await client.call_tool("process_data", {"file": "data.csv"})
|
| 162 |
+
```
|
| 163 |
|
| 164 |
+
For complete isolation between connections, disable session persistence:
|
|
|
|
|
|
|
| 165 |
|
| 166 |
+
```python
|
| 167 |
+
transport = StdioTransport(
|
| 168 |
+
command="python",
|
| 169 |
+
args=["server.py"],
|
| 170 |
+
keep_alive=False
|
| 171 |
+
)
|
| 172 |
+
client = Client(transport)
|
| 173 |
```
|
|
|
|
|
|
|
|
|
|
| 174 |
|
| 175 |
+
Use `keep_alive=False` when you need complete isolation (e.g., in test suites) or when server state could cause issues between connections.
|
|
|
|
|
|
|
| 176 |
|
| 177 |
+
### Specialized STDIO Transports
|
| 178 |
|
| 179 |
+
FastMCP provides convenience transports that are thin wrappers around `StdioTransport` with pre-configured commands:
|
|
|
|
|
|
|
| 180 |
|
| 181 |
+
- **`PythonStdioTransport`** - Uses `python` command for `.py` files
|
| 182 |
+
- **`NodeStdioTransport`** - Uses `node` command for `.js` files
|
| 183 |
+
- **`UvxStdioTransport`** - Uses `uvx` for Python packages (uses `env_vars` parameter)
|
| 184 |
+
- **`NpxStdioTransport`** - Uses `npx` for Node packages (uses `env_vars` parameter)
|
| 185 |
|
| 186 |
+
For most use cases, instantiate `StdioTransport` directly with your desired command. These specialized transports are primarily useful for client inference shortcuts.
|
|
|
|
| 187 |
|
| 188 |
+
## Remote Transports
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
|
| 190 |
+
Remote transports connect to MCP servers running as web services. This is a fundamentally different model from STDIO transports—instead of your client launching and managing a server process, you connect to an already-running service that manages its own environment and lifecycle.
|
|
|
|
|
|
|
|
|
|
| 191 |
|
| 192 |
+
### Streamable HTTP Transport
|
|
|
|
| 193 |
|
| 194 |
+
<VersionBadge version="2.3.0" />
|
|
|
|
|
|
|
| 195 |
|
| 196 |
+
Streamable HTTP is the recommended transport for production deployments, providing efficient bidirectional streaming over HTTP connections.
|
| 197 |
|
| 198 |
+
- **Class:** `StreamableHttpTransport`
|
| 199 |
+
- **Server compatibility:** FastMCP servers running with `mcp run --transport http`
|
|
|
|
| 200 |
|
| 201 |
+
The transport requires a URL and optionally supports custom headers for authentication and configuration:
|
| 202 |
|
| 203 |
```python
|
| 204 |
+
from fastmcp.client.transports import StreamableHttpTransport
|
|
|
|
|
|
|
|
|
|
| 205 |
|
| 206 |
+
# Basic connection
|
| 207 |
+
transport = StreamableHttpTransport(url="https://api.example.com/mcp")
|
| 208 |
+
client = Client(transport)
|
| 209 |
|
| 210 |
+
# With custom headers for authentication
|
| 211 |
+
transport = StreamableHttpTransport(
|
| 212 |
+
url="https://api.example.com/mcp",
|
| 213 |
+
headers={
|
| 214 |
+
"Authorization": "Bearer your-token-here",
|
| 215 |
+
"X-Custom-Header": "value"
|
| 216 |
+
}
|
| 217 |
)
|
| 218 |
client = Client(transport)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 219 |
```
|
| 220 |
|
| 221 |
+
For convenience, FastMCP also provides authentication helpers:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 222 |
|
| 223 |
```python
|
| 224 |
+
from fastmcp.client.auth import BearerAuth
|
|
|
|
| 225 |
|
| 226 |
+
client = Client(
|
| 227 |
+
"https://api.example.com/mcp",
|
| 228 |
+
auth=BearerAuth("your-token-here")
|
|
|
|
|
|
|
| 229 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
```
|
| 231 |
|
| 232 |
+
### SSE Transport (Legacy)
|
| 233 |
+
|
| 234 |
+
Server-Sent Events transport is maintained for backward compatibility but is superseded by Streamable HTTP for new deployments.
|
| 235 |
|
| 236 |
+
- **Class:** `SSETransport`
|
| 237 |
+
- **Server compatibility:** FastMCP servers running with `mcp run --transport sse`
|
|
|
|
| 238 |
|
| 239 |
+
SSE transport supports the same configuration options as Streamable HTTP:
|
| 240 |
|
| 241 |
```python
|
| 242 |
+
from fastmcp.client.transports import SSETransport
|
|
|
|
| 243 |
|
| 244 |
+
transport = SSETransport(
|
| 245 |
+
url="https://api.example.com/sse",
|
| 246 |
+
headers={"Authorization": "Bearer token"}
|
|
|
|
| 247 |
)
|
| 248 |
client = Client(transport)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 249 |
```
|
| 250 |
|
| 251 |
+
Use Streamable HTTP for new deployments unless you have specific infrastructure requirements for SSE.
|
| 252 |
|
| 253 |
+
## In-Memory Transport
|
| 254 |
|
| 255 |
+
In-memory transport connects directly to a FastMCP server instance within the same Python process. This eliminates both subprocess management and network overhead, making it ideal for testing and development.
|
|
|
|
|
|
|
| 256 |
|
| 257 |
+
- **Class:** `FastMCPTransport`
|
| 258 |
+
|
| 259 |
+
<Note>
|
| 260 |
+
Unlike STDIO transports, in-memory servers have full access to your Python process's environment. They share the same memory space and environment variables as your client code—no isolation or explicit environment passing required.
|
| 261 |
+
</Note>
|
| 262 |
|
| 263 |
```python
|
| 264 |
from fastmcp import FastMCP, Client
|
| 265 |
+
import os
|
|
|
|
|
|
|
|
|
|
| 266 |
|
| 267 |
+
mcp = FastMCP("TestServer")
|
|
|
|
|
|
|
| 268 |
|
| 269 |
+
@mcp.tool
|
| 270 |
+
def greet(name: str) -> str:
|
| 271 |
+
prefix = os.environ.get("GREETING_PREFIX", "Hello")
|
| 272 |
+
return f"{prefix}, {name}!"
|
| 273 |
|
| 274 |
+
client = Client(mcp)
|
|
|
|
|
|
|
|
|
|
| 275 |
|
| 276 |
+
async with client:
|
| 277 |
+
result = await client.call_tool("greet", {"name": "World"})
|
| 278 |
```
|
| 279 |
|
| 280 |
+
## MCP JSON Configuration Transport
|
|
|
|
|
|
|
|
|
|
|
|
|
| 281 |
|
| 282 |
<VersionBadge version="2.4.0" />
|
| 283 |
|
| 284 |
+
This transport supports the emerging MCP JSON configuration standard for defining multiple servers:
|
|
|
|
|
|
|
| 285 |
|
| 286 |
+
- **Class:** `MCPConfigTransport`
|
| 287 |
|
| 288 |
```python
|
|
|
|
|
|
|
|
|
|
| 289 |
config = {
|
| 290 |
"mcpServers": {
|
|
|
|
| 291 |
"weather": {
|
| 292 |
+
"url": "https://weather.example.com/mcp",
|
| 293 |
"transport": "http"
|
| 294 |
},
|
|
|
|
| 295 |
"assistant": {
|
| 296 |
"command": "python",
|
| 297 |
+
"args": ["./assistant.py"],
|
| 298 |
+
"env": {"LOG_LEVEL": "INFO"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
}
|
| 300 |
}
|
| 301 |
}
|
| 302 |
|
|
|
|
| 303 |
client = Client(config)
|
| 304 |
|
| 305 |
+
async with client:
|
| 306 |
+
# Tools are namespaced by server
|
| 307 |
+
weather = await client.call_tool("weather_get_forecast", {"city": "NYC"})
|
| 308 |
+
answer = await client.call_tool("assistant_ask", {"question": "What?"})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 309 |
```
|
| 310 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/docs.json
CHANGED
|
@@ -103,6 +103,7 @@
|
|
| 103 |
"group": "Clients",
|
| 104 |
"pages": [
|
| 105 |
"clients/client",
|
|
|
|
| 106 |
{
|
| 107 |
"group": "Core Operations",
|
| 108 |
"icon": "handshake",
|
|
@@ -124,7 +125,6 @@
|
|
| 124 |
"clients/roots"
|
| 125 |
]
|
| 126 |
},
|
| 127 |
-
"clients/transports",
|
| 128 |
{
|
| 129 |
"group": "Authentication",
|
| 130 |
"icon": "user-shield",
|
|
|
|
| 103 |
"group": "Clients",
|
| 104 |
"pages": [
|
| 105 |
"clients/client",
|
| 106 |
+
"clients/transports",
|
| 107 |
{
|
| 108 |
"group": "Core Operations",
|
| 109 |
"icon": "handshake",
|
|
|
|
| 125 |
"clients/roots"
|
| 126 |
]
|
| 127 |
},
|
|
|
|
| 128 |
{
|
| 129 |
"group": "Authentication",
|
| 130 |
"icon": "user-shield",
|