---
title: "MCPServerStdio: Local Tool Integration via Standard I/O"
description: "Master MCPServerStdio for connecting agents to local tool servers via standard I/O, including subprocess management, npx-based servers, filesystem operations, and automatic lifecycle handling."
canonical: https://callsphere.ai/blog/mcp-server-stdio-local-tool-integration-standard-io
category: "Learn Agentic AI"
tags: ["OpenAI", "MCP", "Stdio", "Local Tools", "Python"]
author: "CallSphere Team"
published: 2026-03-14T00:00:00.000Z
updated: 2026-05-06T01:02:41.507Z
---

# MCPServerStdio: Local Tool Integration via Standard I/O

> Master MCPServerStdio for connecting agents to local tool servers via standard I/O, including subprocess management, npx-based servers, filesystem operations, and automatic lifecycle handling.

## How MCPServerStdio Works

MCPServerStdio is the simplest MCP transport. Your agent spawns the MCP server as a child process, then communicates with it by writing JSON-RPC messages to the process's stdin and reading responses from stdout. No network, no ports, no HTTP — just pipes.

This makes Stdio ideal for local development, filesystem tools, database access on the same machine, and any scenario where the tool server runs alongside the agent.

## Basic Setup

```python
from agents.mcp import MCPServerStdio

# The params dict mirrors how you would run the command in a terminal
server = MCPServerStdio(
    name="Filesystem",
    params={
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/documents"],
    },
)
```

The `params` object accepts:

```mermaid
flowchart LR
    HOST(["MCP host
Claude Desktop or IDE"])
    CLIENT["MCP client"]
    subgraph SERVERS["MCP Servers"]
        S1["Filesystem server"]
        S2["GitHub server"]
        S3["Postgres server"]
        SX["Custom tool server"]
    end
    LLM["LLM session"]
    OUT(["Grounded action"])
    HOST  CLIENT
    CLIENT |stdio or HTTP+SSE| S1
    CLIENT  S2
    CLIENT  S3
    CLIENT  SX
    CLIENT --> LLM --> OUT
    style HOST fill:#f1f5f9,stroke:#64748b,color:#0f172a
    style CLIENT fill:#4f46e5,stroke:#4338ca,color:#fff
    style OUT fill:#059669,stroke:#047857,color:#fff
```

- **command** — The executable to run (e.g., `npx`, `python`, `node`)
- **args** — Command-line arguments passed to the executable
- **env** — Optional environment variables for the subprocess
- **cwd** — Optional working directory for the subprocess

## Launching Local Subprocesses

When you enter the `async with` block, MCPServerStdio spawns the subprocess and performs the MCP initialization handshake:

```python
import asyncio
from agents import Agent, Runner
from agents.mcp import MCPServerStdio

async def main():
    server = MCPServerStdio(
        name="SQLite",
        params={
            "command": "npx",
            "args": ["-y", "@modelcontextprotocol/server-sqlite",
                     "--db-path", "/tmp/my-database.db"],
        },
    )

    async with server:
        # At this point, the subprocess is running and tools are discovered
        # The server has reported its available tools via the MCP handshake

        agent = Agent(
            name="Database Assistant",
            instructions="Help users query and manage the SQLite database.",
            mcp_servers=[server],
        )

        result = await Runner.run(
            agent,
            input="What tables exist in the database? Show me the schema.",
        )
        print(result.final_output)

    # Exiting the async with block kills the subprocess cleanly

asyncio.run(main())
```

## npx-Based MCP Servers

The most common pattern uses `npx` to run MCP servers published as npm packages. The `-y` flag auto-confirms the install prompt:

```python
# Filesystem access
fs_server = MCPServerStdio(
    name="Filesystem",
    params={
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-filesystem", "/allowed/path"],
    },
)

# Git operations
git_server = MCPServerStdio(
    name="Git",
    params={
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-git",
                 "--repository", "/path/to/repo"],
    },
)

# GitHub API (requires GITHUB_TOKEN env var)
github_server = MCPServerStdio(
    name="GitHub",
    params={
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-github"],
        "env": {"GITHUB_TOKEN": "ghp_your_token_here"},
    },
)

# PostgreSQL queries
postgres_server = MCPServerStdio(
    name="Postgres",
    params={
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-postgres",
                 "postgresql://user:pass@localhost:5432/mydb"],
    },
)
```

## Python-Based MCP Servers

You can also write MCP servers in Python using the `mcp` package:

```python
# my_tools_server.py
from mcp.server.fastmcp import FastMCP
import httpx

mcp = FastMCP("My Custom Tools")

@mcp.tool()
async def get_weather(city: str) -> str:
    """Get current weather for a city."""
    async with httpx.AsyncClient() as client:
        resp = await client.get(
            "https://api.weatherapi.com/v1/current.json",
            params={"key": "YOUR_KEY", "q": city},
        )
        data = resp.json()
        current = data["current"]
        return f"{city}: {current['temp_c']}C, {current['condition']['text']}"

@mcp.tool()
def calculate_bmi(weight_kg: float, height_m: float) -> str:
    """Calculate BMI given weight in kg and height in meters."""
    bmi = weight_kg / (height_m ** 2)
    category = (
        "underweight" if bmi < 18.5
        else "normal" if bmi < 25
        else "overweight" if bmi < 30
        else "obese"
    )
    return f"BMI: {bmi:.1f} ({category})"

if __name__ == "__main__":
    mcp.run(transport="stdio")
```

Connect this server to your agent:

```python
custom_server = MCPServerStdio(
    name="Custom Tools",
    params={
        "command": "python",
        "args": ["my_tools_server.py"],
        "cwd": "/path/to/server",
    },
)
```

## Filesystem Server Deep Dive

The filesystem MCP server is one of the most useful. It provides these tools:

- **read_file** — Read the contents of a file
- **write_file** — Create or overwrite a file
- **edit_file** — Make targeted edits to an existing file
- **list_directory** — List files and subdirectories
- **search_files** — Search for files matching a pattern
- **get_file_info** — Get metadata (size, modified date, permissions)
- **create_directory** — Create a new directory
- **move_file** — Move or rename a file

The path argument to the server defines the allowed root directory. The server will refuse to access files outside this directory, providing a security boundary:

```python
async def file_management_agent():
    server = MCPServerStdio(
        name="Filesystem",
        params={
            "command": "npx",
            "args": ["-y", "@modelcontextprotocol/server-filesystem",
                     "/home/user/projects"],
        },
    )

    async with server:
        agent = Agent(
            name="Project Organizer",
            instructions="""You help organize project files.
            You can read, create, move, and search files.
            Always explain what you are doing before making changes.
            Never delete files without explicit confirmation.""",
            mcp_servers=[server],
        )

        result = await Runner.run(
            agent,
            input="Find all Python files in the project and create an index.md listing them with their first docstring",
        )
        print(result.final_output)
```

## Automatic Process Lifecycle Management

MCPServerStdio handles the full subprocess lifecycle:

- **Startup**: Spawns the process when entering `async with`
- **Initialization**: Performs the MCP handshake to discover tools
- **Communication**: Routes tool calls via stdin/stdout during agent execution
- **Cleanup**: Sends SIGTERM, waits briefly, then SIGKILL if needed on exit

If the subprocess crashes mid-conversation, the SDK raises an error that you can catch and handle:

```python
async def resilient_agent():
    server = MCPServerStdio(
        name="Tools",
        params={"command": "npx", "args": ["-y", "my-mcp-server"]},
    )

    try:
        async with server:
            agent = Agent(
                name="Resilient Agent",
                instructions="Help users with their tasks.",
                mcp_servers=[server],
            )
            result = await Runner.run(agent, input="Do something useful")
            print(result.final_output)
    except Exception as e:
        print(f"MCP server error: {e}")
        # Fall back to agent without MCP tools, or restart the server
```

## Environment Variables and Secrets

Pass secrets to MCP servers via environment variables, never as command-line arguments (which are visible in process listings):

```python
server = MCPServerStdio(
    name="GitHub",
    params={
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-github"],
        "env": {
            "GITHUB_TOKEN": os.environ["GITHUB_TOKEN"],
            "PATH": os.environ["PATH"],  # Inherit PATH for npx resolution
        },
    },
)
```

Note that when you specify `env`, it replaces the entire environment. You typically want to include `PATH` so the subprocess can find `npx` and `node`.

## Multiple Stdio Servers

Running multiple Stdio servers is straightforward — each gets its own subprocess:

```python
async def multi_tool_agent():
    fs = MCPServerStdio(
        name="Files",
        params={"command": "npx",
                "args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"]},
    )
    db = MCPServerStdio(
        name="Database",
        params={"command": "npx",
                "args": ["-y", "@modelcontextprotocol/server-sqlite",
                         "--db-path", "/workspace/data.db"]},
    )
    git = MCPServerStdio(
        name="Git",
        params={"command": "npx",
                "args": ["-y", "@modelcontextprotocol/server-git",
                         "--repository", "/workspace"]},
    )

    async with fs, db, git:
        agent = Agent(
            name="Full-Stack Dev",
            instructions="""You are a development assistant with access to
            the filesystem, a SQLite database, and git.
            Use these tools to help developers with their tasks.""",
            mcp_servers=[fs, db, git],
        )

        result = await Runner.run(
            agent,
            input="Read the schema from schema.sql, create the tables in the database, then commit the changes",
        )
        print(result.final_output)
```

MCPServerStdio is the workhorse transport for local development and single-machine deployments. It is fast, simple, and requires no infrastructure beyond the subprocess itself.

---

Source: https://callsphere.ai/blog/mcp-server-stdio-local-tool-integration-standard-io
