# KeyError: 'transport' from MultiServerMCPClient.get_tools()

TL;DR: your server config is wrapped in an extra `"mcpServers"` key that `MultiServerMCPClient` does not expect. Pass the servers dict directly: `MultiServerMCPClient({"airbnb": {"transport": "stdio", ...}})`. The client iterates the dict you give it, so one extra nesting level breaks the `"transport"` lookup.

```text
KeyError: 'transport'
# raised by await client.get_tools() when the config dict has the wrong shape.
```

## When this applies

- You use `MultiServerMCPClient` from `langchain_mcp_adapters` to load MCP tools into a LangGraph agent.
- `get_tools()` raises `KeyError: 'transport'` immediately, before any server starts.
- Your config looks like `{"mcpServers": {"airbnb": {...}}}` (copied from a blog post or the FastMCP multi-server docs).

## When it does not

- Timeouts or connection refused mean the server config is right but the server is not reachable. Different fix.
- `get_tools()` returning an empty list means the server started but exposed no tools.

## Fix it

### 1. Drop the wrapper key

```python
# wrong: extra "mcpServers" nesting
client = MultiServerMCPClient(connections={"mcpServers": {"airbnb": {...}}})

# right: servers dict directly
from langchain_mcp_adapters.client import MultiServerMCPClient

client = MultiServerMCPClient({
    "airbnb": {
        "transport": "stdio",
        "command": "npx",
        "args": ["-y", "@openbnb/mcp-server-airbnb"],
    }
})
tools = await client.get_tools()
```

Expected: `get_tools()` returns the tool list instead of raising KeyError.

### 2. Every server entry needs a transport

```python
# stdio servers
"my_server": {"transport": "stdio", "command": "npx", "args": [...]}

# HTTP servers
"other": {"transport": "streamable_http", "url": "YOUR_HOST:4001/mcp"}
```

Expected: the client knows how to reach each server. A missing `"transport"` key on ANY entry raises the same KeyError, so check all of them.

### 3. Then wire the tools into your agent

```python
from langgraph.prebuilt import create_react_agent

agent = create_react_agent(model, tools)
```

Expected: the agent lists the MCP tools and can call them.

## Why it happens

`MultiServerMCPClient` expects `{server_name: server_config}` and reads `server_config["transport"]` for each entry. When you wrap everything in `"mcpServers"`, it iterates one entry named `"mcpServers"` whose value is the whole servers dict, and that dict has no `"transport"` key. The blog-post shape comes from a different client (FastMCP's multi-server config), not this one.

## Edge cases

- `connections=` vs positional: both spellings appear in examples. The SHAPE of the dict matters, not the kwarg name.
- npx-based servers need node installed where the agent runs. In Docker, that means node in the image, not just on your laptop.
- On Windows, stdio servers often need `shell: True` or a `.cmd` shim for npx.

## Compatibility

`langchain-mcp-adapters` (Python), used with langgraph's `create_react_agent` / `ToolNode`.