Skip to content

Chapter 20 · MCP Client Integration in Practice ​

Chapter goals:接入 the MCP Server you wrote to real clients — master Claude Desktop's mcpServers配置, Claude Code's mcp add command, the配置 difference between stdio and remote servers, and write a programmatically-called Client in Python.

20.1 Configuring a Local Server in Claude Desktop ​

Claude Desktop manages MCP servers through a JSON config file. Open claude_desktop_config.json (menu File → Settings → Developer → Edit Config) and add the mcpServers field:

json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/yourname/Documents",
        "/Users/yourname/Desktop"
      ]
    }
  }
}

Field-by-field解读:

FieldMeaningNote
Key filesystemThe display name you给 this serverAppears as a prefix on tool names
commandThe executable to start the servernpx, python, uv, or a compiled binary
argsCommand-line argument arrayThe example above limits visibility to two directories only
envEnvironment variables注入ed into the subprocessPlace API Keys and other secrets (see 20.3)

After saving, completely quit and restart Claude Desktop (not just close the window). If the config is correct, a tool icon appears in the bottom-right of the input box; clicking it lists all tools exposed by that server.

Least Privilege

The directories listed in args above are the filesystem server's entire可见范围. Never配置 the entire user home directory or / — this is the first security闸门 of MCP.

20.2 Config Difference: stdio vs Remote Servers ​

Local servers use stdio transport: the client spawns them as subprocesses and communicates via stdin/stdout, so they need command + args. Remote servers use Streamable HTTP: they already run somewhere else, needing only a URL.

json
{
  "mcpServers": {
    "local-notes": {
      "command": "python",
      "args": ["/path/to/server.py"]
    },
    "remote-docs": {
      "url": "https://mcp.example.com/mcp",
      "headers": {
        "Authorization": "Bearer <token>"
      }
    }
  }
}

Selection advice: personal tools and本机 file access use stdio; team-shared capabilities (internal knowledge base queries, CI status, etc.) deploy as HTTP services — maintain once, use多方.

20.3 Environment Variables and Secret Passing ​

Servers often need API Keys. The correct approach is to写 them in the config's env field, let the client注入 them into the subprocess environment:

json
{
  "mcpServers": {
    "brave-search": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-brave-search"],
      "env": {
        "BRAVE_API_KEY": "your-secret-key"
      }
    }
  }
}

The official docs specially提醒 about a Windows坑: if the log error contains ${APPDATA}, it means the server didn't get the expanded path variable; manually补 the expanded value in env.

Security red lines:

  1. The config file contains plaintext secrets — do not commit to Git;
  2. Secrets only enter the server process via environment variables; don't hardcode in server.py source;
  3. When distributing to the team,提供 a config.example.json template; each personfills their own本地 config.

20.4 Managing via CLI in Claude Code ​

Claude Code turns the same config into CLI commands, no need to手动 edit JSON:

bash
# Add a stdio local server
claude mcp add notes -- python /path/to/server.py

# Add a server with environment variables
claude mcp add brave-search -e BRAVE_API_KEY=sk-xxx -- npx -y @modelcontextprotocol/server-brave-search

# Add a remote HTTP server
claude mcp add --transport http docs https://mcp.example.com/mcp

# List / remove
claude mcp list
claude mcp remove notes

The part after -- is the启动 command itself; the semantics map one-to-one to the JSON config.

20.5 Tools Not Appearing? Troubleshooting Checklist ​

If you don't see tools in the client after config,排查 from高命中率 to low:

bash
# ① Run the server command手工 to confirm it starts正常 without errors
npx -y @modelcontextprotocol/server-filesystem ~/Documents

# ② Check Claude Desktop's MCP logs (macOS)
tail -f ~/Library/Logs/Claude/mcp*.log
  • JSON syntax error: extra commas, missing quotes — the most common cause; run through任意 JSON validator;
  • Incomplete restart: Claude Desktop必须从托盘完全退出再启动才会重读配置;
  • Missing dependencies: npx needs Node.js; Python servers注意是否装在正确的虚拟环境里;
  • Wrong path: when server.py uses a relative path, the working directory depends on the client;一律 write absolute paths;
  • Server crashes on startup: check ②'s log output — usually missing dependencies or未 set secrets.

20.6 Writing a Programmatic Client in Python ​

Beyond off-the-shelf clients, you can also directly call MCP servers in your own应用. The official SDK is simultaneously a complete MCP Client library:

python
import asyncio

from mcp import Client


async def main() -> None:
    # URL form connects to a Streamable HTTP transport Server
    async with Client("http://localhost:8000/mcp") as client:
        # List all tools the server provides
        tools = await client.list_tools()
        for t in tools:
            print("Tool:", t.name, "-", t.description)

        # Call the add tool from Chapter 13
        result = await client.call_tool("add", {"a": 1, "b": 2})
        print(result.structured_content)  # {'result': 3}


asyncio.run(main())

Start the Server from the previous chapter via HTTP first, then run the client:

bash
mcp run server.py --transport streamable-http   # Terminal 1
python my_client.py                             # Terminal 2

Key points:

  • async with Client(...) handles the full lifecycle — establishing the connection, initialize handshake, capabilities negotiation, and exit cleanup all happen in this step;
  • The URL connects via HTTP transport; Client同样 supports spawning a local script as a stdio subprocess; the parameter form is一致 with Claude Desktop's config;
  • When you need精细 control over底层 request/notification sending, the SDK also provides a Low-Level session API (in the mcp.client.session module); for日常场景 the高层接口 above is sufficient.

This is the minimal path to嵌入 MCP capabilities into your own product — your application此时 is an MCP Host.

Chapter Summary ​

  • Claude Desktop configures servers under mcpServers in claude_desktop_config.json; must completely restart after changes;
  • Local servers配 command+args (stdio); remote servers配 url (Streamable HTTP);
  • Secrets in env field; config files不入库; Windows注意 ${APPDATA} expansion issue;
  • Claude Code provides claude mcp add/list/remove command-equivalent operations;
  • Troubleshooting order:手工起 server → check mcp logs → check JSON syntax → check dependencies and absolute paths;
  • from mcp import Client十几行代码即可让任何 Python application become an MCP host.

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. After修改 the mcpServers config in Claude Desktop, how do you make it生效?

2. What is the本质 difference in配置 between stdio and Streamable HTTP transports?

3. Regarding passing API Keys to an MCP server, what is the correct approach?

4. The config is无误 but the client doesn't show the server's tools. What should you check first?

🛠️ Hands-on Practice ​

1.接入 the notebook Server from Chapter 13 to Claude Desktop; verify the tool list appears; deliberately删除 a comma in the config file and观察 the error behavior. 2. Use claude mcp add to添加 the same Server into Claude Code; compare whether the最终 config structures generated by the two methods are一致. 3. Extend this chapter's Python client: after listing tools, automatically调用 each one with "no-arg invocation" or skip tools with required parameters; print each tool's structured return.

After completing the exercises, proceed to Next chapter: MCP Security and Production Practices to securely跑 the server in production.