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 addcommand, 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:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/yourname/Documents",
"/Users/yourname/Desktop"
]
}
}
}Field-by-field解读:
| Field | Meaning | Note |
|---|---|---|
Key filesystem | The display name you给 this server | Appears as a prefix on tool names |
command | The executable to start the server | npx, python, uv, or a compiled binary |
args | Command-line argument array | The example above limits visibility to two directories only |
env | Environment variables注入ed into the subprocess | Place 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.
{
"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:
{
"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:
- The config file contains plaintext secrets — do not commit to Git;
- Secrets only enter the server process via environment variables; don't hardcode in server.py source;
- When distributing to the team,提供 a
config.example.jsontemplate; 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:
# 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 notesThe 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:
# ① 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:
npxneeds Node.js; Python servers注意是否装在正确的虚拟环境里; - Wrong path: when
server.pyuses 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:
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:
mcp run server.py --transport streamable-http # Terminal 1
python my_client.py # Terminal 2Key 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.sessionmodule); 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
mcpServersinclaude_desktop_config.json; must completely restart after changes; - Local servers配
command+args(stdio); remote servers配url(Streamable HTTP); - Secrets in
envfield; config files不入库; Windows注意${APPDATA}expansion issue; - Claude Code provides
claude mcp add/list/removecommand-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.