运行你的第一个 MCP Python 客户端:mcp-for-beginners 标准 I/O 客户端实战指南

原创2026-10-03 10:34:42789 阅读
文章标签:教程文档人工智能

运行你的第一个 MCP Python 客户端:mcp-for-beginners 标准 I/O 客户端实战指南

本篇指南以 mcp-for-beginners 开源课程中 03-GettingStarted/02-client 一课的 Python 示例为核心,带你从零搭建虚拟环境、安装 mcp[cli] 依赖、启动一个基于 stdio 传输的 MCP 客户端,并连接本地的 FastMCP 服务器完成资源发现、工具调用与结果读取。学完本文,你将掌握编写、运行和验证一个 Python MCP 客户端的最小可行流程,并理解 ClientSession、stdio_client、initialize 等核心 API 的调用关系。

一、示例概览:一个最小可运行的 Python MCP 客户端

该示例位于 03-GettingStarted/02-client/solution/python,包含两个核心文件:

  • client.py:客户端主程序,负责与 MCP 服务器通信;
  • server.py:配套的 FastMCP 服务器,暴露一个 add 工具和一个 greeting://{name} 动态资源。

整个示例的目标是:客户端通过标准输入/输出(stdio)管道启动服务器进程,建立会话,依次列出资源、列出工具、读取资源、调用工具,并把结果打印到终端。它是 MCP 客户端编程的"Hello World",适合作为后续集成 LLM 客户端(见 03-llm-client)的起点。

前置条件

  • 已安装 Python 3 及 pip;
  • 官方建议(非必须)安装 uv 来管理 Python 环境与依赖,具体说明见 uv 官方文档;不安装 uv 也完全可以按下面的 pip 流程执行。

二、逐步运行:四个命令跑通示例

原文档给出了从环境创建到运行客户端的完整命令序列,下面逐一展开说明。

步骤 0:创建虚拟环境

python -m venv venv

venv 会在当前目录下生成一个隔离的 Python 环境目录,避免依赖污染系统级 Python。这是 Python 项目开发的标准做法,尤其适用于依赖版本敏感的 MCP SDK。

步骤 1:激活虚拟环境

venv\Scripts\activate

注意:示例使用 Windows 风格路径。在 Linux/macOS 下请使用 source venv/bin/activate。

激活后,后续的 pip install 与 python 命令都会指向虚拟环境内的解释器。

步骤 2:安装依赖

pip install "mcp[cli]"

这一条命令安装了两部分内容:

  • mcp:官方 Python SDK,提供 ClientSession、StdioServerParameters、types 等客户端构造,以及 FastMCP 服务端构造;
  • [cli]:额外安装 mcp 命令行工具(即可执行文件 mcp),StdioServerParameters 中的 command="mcp" 正是依赖它来拉起服务器。

步骤 3:运行客户端

python client.py

客户端会自动以子进程方式启动服务器(通过 mcp run server.py),然后执行协议交互。运行成功后,你应该看到与原文档一致的输出:

LISTING RESOURCES
Resource:  ('meta', None)
Resource:  ('nextCursor', None)
Resource:  ('resources', [])
INFO Processing request of type ListToolsRequest server.py:534
LISTING TOOLS
Tool:  add
READING RESOURCE
INFO Processing request of type ReadResourceRequest server.py:534
CALL TOOL
INFO Processing request of type CallToolRequest server.py:534
[TextContent(type='text', text='8', annotations=None)]

这段输出清晰展示了客户端的完整生命周期:先列出资源,再列出工具,然后读取 greeting://hello 资源,最后调用 add(1, 7) 工具并拿到 text='8' 的结果。中间的 INFO Processing request of type ... server.py:534 行来自 SDK 内部的请求日志,用于说明当前正在处理的协议消息类型(ListToolsRequest、ReadResourceRequest、CallToolRequest)。

三、客户端代码逐段解析

下面结合 client.py 的完整实现,讲解每一段代码的作用。

3.1 导入所需库

from mcp import ClientSession, StdioServerParameters, types
from mcp.client.stdio import stdio_client
  • ClientSession:高层会话抽象,提供 initialize、list_resources、list_tools、read_resource、call_tool 等方法;
  • StdioServerParameters:描述如何以子进程方式启动 MCP 服务器(可执行文件、参数、环境变量);
  • stdio_client:负责建立 stdio 传输通道,返回一对读写流;
  • types:协议类型引用(当前示例中主要用于后续的 TextContent 等类型)。

3.2 配置服务器启动参数

server_params = StdioServerParameters(
    command="mcp",  # Executable
    args=["run", "server.py"],  # Optional command line arguments
    env=None,  # Optional environment variables
)

这里的关键点:客户端并不直接"连接"一个已在运行的进程,而是声明"如何启动服务器"。

  • command:要执行的可执行文件,这里是 mcp(由 pip install "mcp[cli]" 提供);
  • args:传给可执行文件的参数,run server.py 表示用 MCP CLI 运行当前目录下的 server.py;
  • env:可选的额外环境变量,None 表示继承当前进程环境。

3.3 建立会话并初始化

async def run():
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            # Initialize the connection
            await session.initialize()
  • stdio_client(server_params) 会按照参数启动子进程服务器,并返回 (read, write) 两条流;
  • ClientSession(read, write) 基于这两条流建立 MCP 会话,其 __aenter__ 会自动完成初始化握手;
  • session.initialize() 是显式初始化调用,对应 MCP 协议中的 initialize 请求,用于协商协议版本与能力。

客户端整体通过 asyncio.run(run()) 驱动,这是 mcp Python SDK 基于异步模型设计的标准用法。

3.4 列出资源与工具

resources = await session.list_resources()
print("LISTING RESOURCES")
for resource in resources:
    print("Resource: ", resource)

tools = await session.list_tools()
print("LISTING TOOLS")
for tool in tools.tools:
    print("Tool: ", tool.name)

list_resources() 返回服务器声明的资源列表;list_tools() 返回 ListToolsResult,其中 tools 字段包含每个工具的名称、描述与输入 schema。在本示例中,服务器通过 @mcp.tool() 暴露了 add 工具,因此输出中可以看到 Tool: add。

3.5 读取资源与调用工具

print("READING RESOURCE")
content, mime_type = await session.read_resource("greeting://hello")

print("CALL TOOL")
result = await session.call_tool("add", arguments={"a": 1, "b": 7})
print(result.content)
  • read_resource("greeting://hello"):按 URI 读取资源,URI 模板中的 {name} 会被替换为 hello;
  • call_tool("add", arguments={"a": 1, "b": 7}):按名称调用工具并传入参数,返回结果对象;result.content 中是 TextContent(type='text', text='8', ...) 列表,即 1 + 7 的运算结果。

四、配套服务器端实现

客户端所交互的服务器在 server.py 中定义,它是用 FastMCP 构建的最小示例:

# server.py
from mcp.server.fastmcp import FastMCP

# Create an MCP server
mcp = FastMCP("Demo")

# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers"""
    return a + b

# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
    """Get a personalized greeting"""
    return f"Hello, {name}!"

# Main execution block - this is required to run the server
if __name__ == "__main__":
    mcp.run()

解读:

  • FastMCP("Demo") 创建名为 "Demo" 的 MCP 服务器;
  • @mcp.tool() 装饰器把 add(a, b) 注册为工具,docstring 即工具描述;
  • @mcp.resource("greeting://{name}") 注册一个带 URI 模板的动态资源,模板参数 {name} 在客户端读取 greeting://hello 时被解析为 name="hello",返回 Hello, hello!;
  • mcp.run() 是服务器启动入口;客户端通过 mcp run server.py 以子进程方式把它拉起,双方通过 stdio 管道交换 JSON-RPC 消息。

同样风格的服务器也出现在前一课 01-first-server 的 Python 方案中(后者额外提供了 subtract 工具),可与客户端代码配合扩展练习。

五、客户端与服务器的传输原理:stdio 到底发生了什么

从客户端视角看,整个通信链路可以归纳为:

  1. stdio_client(server_params) 根据 command 与 args 启动服务器子进程;
  2. 客户端把协议消息(JSON-RPC 格式,如 initialize、tools/list、resources/read、tools/call)写入服务器子进程的 stdin;
  3. 服务器把响应写入自己的 stdout,由客户端从 read 流中读取;
  4. ClientSession 负责把底层字节流包装成结构化请求/响应,并维护会话状态。

这也是为什么服务器代码里的 INFO Processing request of type ListToolsRequest server.py:534 日志会出现在客户端输出中间——它们来自服务器进程的 stderr/stdout,被客户端终端一并捕获展示。stdio 是本地 MCP 通信的推荐传输方式(详见课程 05-stdio-server),它天然具备进程隔离与安全边界;若需远程通信,后续课程还会介绍 HTTP Streaming(06-http-streaming)等传输方案。

六、进阶参考:更完整的客户端示例

如果希望看到覆盖错误处理、结果解析与多工具调用的完整客户端实现,仓库在 03-GettingStarted/02-client/client_example_python.py 提供了 MCPCalculatorClient 类,其亮点包括:

  • 通过 try/except 包裹会话建立、工具列表、工具调用与资源读取,打印清晰的成功/失败信息;
  • 内置 extract_text_result() 辅助方法,从 result.content 中稳健提取文本结果(兼容 hasattr 探测与 type == "text" 判断,异常时回退为 "No result");
  • 一次性演示 add、subtract、multiply、divide、help 五类工具调用,并读取第一个可用资源。

该示例的配套说明位于 03-GettingStarted/02-client/complete_examples.md,并提供了 C#、Java、TypeScript、Rust 的多语言对照版本(如 client_example_csharp.cs、client_example_java.java),便于跨语言理解同一协议行为。

七、小结与下一步

通过本文,你已经完整掌握了在 mcp-for-beginners 课程中运行 Python MCP 客户端的最小闭环:

  • 用 python -m venv venv 与 pip install "mcp[cli]" 搭建隔离环境;
  • 用 python client.py 一行命令启动"客户端 + 子进程服务器"的完整链路;
  • 理解 initialize → list_resources → list_tools → read_resource → call_tool 的协议调用序列;
  • 知道如何在 client.py 与 server.py 之间对应查找功能实现。

客户端既可以像本例一样在启动时自行拉起服务器,也可以连接到已运行的服务器进程,是测试服务器能力的有效手段(与前一课介绍的 MCP Inspector 互为补充)。下一步建议学习 03-llm-client:为客户端接入大语言模型,让 LLM 代替手工指定工具调用,实现"智能协商"式的自动化交互。

登录后查看全文
mcp-for-beginners