Meet [Prefect Horizon](https://prefect.io/horizon?utm_source=gofastmcp&utm_medium=docs&utm_campaign=docs_banner&utm_content=sitewide_banner), the enterprise MCP gateway built by the team behind FastMCP

v2.14.5

These are the docs for FastMCP 2.0. [FastMCP 3.0](/content/getting-started/welcome/index.html) is now available.

## Choosing the Right Transport

- **Use [STDIO Transport](/content/v2/clients/transports#stdio-transport/index.html)** when you need to run local MCP servers with full control over their environment and lifecycle
- **Use [Remote Transports](/content/v2/clients/transports#remote-transports/index.html)** when connecting to production services or shared MCP servers running independently
- **Use [In-Memory Transport](/content/v2/clients/transports#in-memory-transport/index.html)** for testing FastMCP servers without subprocess or network overhead
- **Use [MCP JSON Configuration](/content/v2/clients/transports#mcp-json-configuration-transport/index.html)** when you need to connect to multiple servers defined in configuration files

## STDIO Transport

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.

### The Client Runs the Server

**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.

With STDIO transport, your client:

- Starts the server as a subprocess when you connect
- Manages the server’s lifecycle (start, stop, restart)
- Controls the server’s environment and configuration
- Communicates through stdin/stdout pipes

### Environment Isolation

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. When your client launches an MCP server:

- The server does NOT inherit your shell’s environment variables
- API keys, paths, and other configuration must be explicitly passed
- The working directory and system paths may differ from your shell

To pass environment variables to your server, use the `env` parameter:

```python
from fastmcp import Client

# If your server needs environment variables (like API keys),
# you must explicitly pass them:
client = Client(
    "my_server.py",
    env={"API_KEY": "secret", "DEBUG": "true"}
)

# This won't work - the server runs in isolation:
# export API_KEY="secret"  # in your shell
# client = Client("my_server.py")  # server can't see API_KEY
```

### Basic Usage

To use STDIO transport, you create a transport instance with the command and arguments needed to run your server:

```python
from fastmcp.client.transports import StdioTransport

transport = StdioTransport(
    command="python",
    args=["my_server.py"]
)
client = Client(transport)
```

You can configure additional settings like environment variables, working directory, or command arguments:

```python
transport = StdioTransport(
    command="python",
    args=["my_server.py", "--verbose"],
    env={"LOG_LEVEL": "DEBUG"},
    cwd="/path/to/server"
)
client = Client(transport)
```

### Environment Variables

Since STDIO servers don’t inherit your environment, you need strategies for passing configuration. Here are two common approaches:

**Selective forwarding** passes only the variables your server actually needs:

```python
import os
from fastmcp.client.transports import StdioTransport

required_vars = ["API_KEY", "DATABASE_URL", "REDIS_HOST"]
env = {
    var: os.environ[var]
    for var in required_vars
    if var in os.environ
}

transport = StdioTransport(
    command="python",
    args=["server.py"],
    env=env
)
client = Client(transport)
```

**Loading from .env files** keeps configuration separate from code:

```python
from dotenv import dotenv_values
from fastmcp.client.transports import StdioTransport

env = dotenv_values(".env")
transport = StdioTransport(
    command="python",
    args=["server.py"],
    env=env
)
client = Client(transport)
```

### Session Persistence

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. By default, the subprocess persists between connections:

```python
from fastmcp.client.transports import StdioTransport

transport = StdioTransport(
    command="python",
    args=["server.py"]
)
client = Client(transport)

async def efficient_multiple_operations():
    async with client:
        await client.ping()

async with client:  # Reuses the same subprocess
        await client.call_tool("process_data", {"file": "data.csv"})
```

For complete isolation between connections, disable session persistence:

```python
transport = StdioTransport(
    command="python",
    args=["server.py"],
    keep_alive=False
)
client = Client(transport)
```

Use `keep_alive=False` when you need complete isolation (e.g., in test suites) or when server state could cause issues between connections.

### Specialized STDIO Transports

FastMCP provides convenience transports that are thin wrappers around `StdioTransport` with pre-configured commands:

- **`PythonStdioTransport`** - Uses `python` command for `.py` files
- **`NodeStdioTransport`** - Uses `node` command for `.js` files
- **`UvStdioTransport`** - Uses `uv` for Python packages (uses `env_vars` parameter)
- **`UvxStdioTransport`** - Uses `uvx` for Python packages (uses `env_vars` parameter)
- **`NpxStdioTransport`** - Uses `npx` for Node packages (uses `env_vars` parameter)

For most use cases, instantiate `StdioTransport` directly with your desired command. These specialized transports are primarily useful for client inference shortcuts.

## Remote Transports

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.

### Streamable HTTP Transport

New in version `2.3.0` Streamable HTTP is the recommended transport for production deployments, providing efficient bidirectional streaming over HTTP connections.

- **Class:** `StreamableHttpTransport`
- **Server compatibility:** FastMCP servers running with `mcp run --transport http`

The transport requires a URL and optionally supports custom headers for authentication and configuration:

```python
from fastmcp.client.transports import StreamableHttpTransport

# Basic connection
transport = StreamableHttpTransport(url="https://api.example.com/mcp")
client = Client(transport)

# With custom headers for authentication
transport = StreamableHttpTransport(
    url="https://api.example.com/mcp",
    headers={
        "Authorization": "Bearer your-token-here",
        "X-Custom-Header": "value"
    }
)
client = Client(transport)
```

For convenience, FastMCP also provides authentication helpers:

```python
from fastmcp.client.auth import BearerAuth

client = Client(
    "https://api.example.com/mcp",
    auth=BearerAuth("your-token-here")
)
```

### In-Memory Transport

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.

```python
from fastmcp import FastMCP, Client
import os

mcp = FastMCP("TestServer")

@mcp.tool
def greet(name: str) -> str:
    prefix = os.environ.get("GREETING_PREFIX", "Hello")
    return f"{prefix}, {name}!"

client = Client(mcp)

async with client:
    result = await client.call_tool("greet", {"name": "World"})
```

### MCP JSON Configuration Transport

New in version `2.4.0` This transport supports the emerging MCP JSON configuration standard for defining multiple servers:

```python
config = {
    "mcpServers": {
        "weather": {
            "url": "https://weather.example.com/mcp",
            "transport": "http"
        },
        "assistant": {
            "command": "python",
            "args": ["./assistant.py"],
            "env": {"LOG_LEVEL": "INFO"}
        }
    }
}

client = Client(config)

async with client:
    # Tools are namespaced by server
    weather = await client.call_tool("weather_get_forecast", {"city": "NYC"})
    answer = await client.call_tool("assistant_ask", {"question": "What?"})
```

----
