Python怎么调用MCP接口?发现工具、检查参数并读取结果

用官方 Python SDK v2 调用 MCP:启动或连接服务、分页发现工具、按 input_schema 校验参数、区分工具错误和结构化结果;附完整库存测试对象与可运行客户端。

Python 程序调用 MCP 接口,不应只硬编码一个工具名然后打印响应。一个能复用的客户端至少要连接服务器、发现工具、检查输入描述、发起调用并区分成功与失败。本文采用官方 Python SDK v2,通过本地库存工具演示这条流程;不依赖大模型账号,也不把接口调用包装成已经完成的智能体系统。

版本、依赖与可复现的服务器

本教程在 Windows、Python 3.11、mcp==2.2.0 与 jsonschema==4.26.0 环境执行。SDK v2 提供 from mcp import Client;旧教程里的 ClientSession 底层流程不作为本文接口。官方 Client 文档说明了工具列表分页、结果内容与异步生命周期。

Python怎么调用MCP接口?发现工具、检查参数并读取结果

python -m venv .venv
.\.venv\Scripts\python.exe -m pip install "mcp==2.2.0" "jsonschema==4.26.0"

准备同目录的 inventory_server.py。下面是独立可运行的测试对象,库存内容是演示数据,不是真实商业库存:

from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ToolError

mcp = MCPServer("DemoInventory")
STOCK = {"PEN-001": 18, "BOOK-002": 0}

@mcp.tool()
def get_stock(sku: str) -> dict[str, str | int]:
    """Read demo stock for an exact SKU. Does not create orders or change stock."""
    sku = sku.strip().upper()
    if sku not in STOCK:
        raise ToolError(f"Unknown SKU: {sku}")
    return {"sku": sku, "quantity": STOCK[sku]}

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

如果你已经有 MCP 服务器,可保留客户端框架,把工具名、参数与预期结果换成服务器真实公布的内容;不要仅凭工具名字猜接口。

客户端完整代码:发现后再调用

把下面保存为 client.py:

import asyncio
import sys
from pathlib import Path
from jsonschema import validate
from mcp import Client
from mcp.client.stdio import StdioServerParameters
from mcp.types import TextContent

async def main():
    server = Path(__file__).with_name("inventory_server.py")
    params = StdioServerParameters(command=sys.executable, args=[str(server)])
    async with Client(params, read_timeout_seconds=10) as client:
        tools = []
        cursor = None
        while True:
            page = await client.list_tools(cursor=cursor)
            tools.extend(page.tools)
            if page.next_cursor is None:
                break
            cursor = page.next_cursor
        tool = next((t for t in tools if t.name == "get_stock"), None)
        if tool is None:
            raise RuntimeError("get_stock is not available")
        arguments = {"sku": "PEN-001"}
        validate(arguments, tool.input_schema)
        result = await client.call_tool(tool.name, arguments)
        if result.is_error:
            raise RuntimeError(str(result.content))
        if result.structured_content is not None:
            print(result.structured_content)
        else:
            for block in result.content:
                if isinstance(block, TextContent):
                    print(block.text)

if __name__ == "__main__":
    asyncio.run(main())
.\.venv\Scripts\python.exe .\client.py

这里客户端通过 StdioServerParameters 启动本地服务,sys.executable 确保子进程使用同一个 Python 环境。async with Client(...) 进入时连接并协商,退出时断开;连接对象不应在退出上下文后继续调用。

为什么要保留这几个检查

  1. 发现列表处理分页。 list_tools() 一次得到一页,后续请求使用 page.next_cursor。本地只有一个工具时可能看不出差别,但真实服务工具多时,忽略游标可能把后面的工具误判为不存在。
  2. 先确认工具确实存在。 如果服务器升级或改名,get_stock 查找会明确失败;不会把空列表当成有效调用环境。
  3. 按服务器公布的输入 Schema 校验。 validate(arguments, tool.input_schema) 会发现缺少必填字段或明显类型不符。校验失败应修改请求,不应让模型靠猜测补业务参数。
  4. 区分工具错误与成功内容。 result.is_error 为真就停止按成功结果解析;为假时优先读取 structured_content,缺少结构化内容时才遍历文本块。

输入 Schema 校验是客户端的早期反馈,服务端仍必须自己验证参数和权限。JSON Schema 也不能判断一个合法编码是否属于当前用户、库存是否允许出售,业务规则不能交给类型校验代劳。

结果应是什么,怎样复查失败路径

本地实际运行完整客户端,得到 {'sku': 'PEN-001', 'quantity': 18}。这是演示表的确定结果,并不是对模型准确率的测评。

修改 应发生什么 处理方式
保留 {"sku":"PEN-001"} Schema 校验通过,返回数量 18 继续处理结构化结果
改为 {} 缺少必填 sku,本地校验抛出 ValidationError 补齐输入,不发起工具请求
改为 {"sku":"MISSING"} 类型合法,但服务器返回工具错误 显示“未找到商品”等清楚错误,不填默认库存
故意改错脚本路径 服务器无法启动或连接失败 检查路径与环境,不能当作工具返回空数据

未知商品的工具错误已用同一服务器进行独立协议验证。客户端还设置了 10 秒读取超时;生产环境要按实际工具耗时调整,遇到超时先核对服务端状态,尤其不要自动重试可能产生写入副作用的调用。

如果服务器是 HTTP 地址

远端或已启动的 HTTP 服务,不需要 StdioServerParameters。把连接对象改成实际 MCP URL,例如 Client("https://你的服务域名/mcp", read_timeout_seconds=10),其余发现与结果处理逻辑仍可使用。这里的域名是说明写法,不能直接执行;你需要已经部署、可访问且认证配置正确的真实地址。

本文没有验证远端认证、多页真实工具列表或生产故障恢复。客户端分页逻辑依据官方 API 编写,本地实验只有单页;如果你的服务采用认证,要按官方传输文档配置相应客户端,不能把 API 密钥硬塞进请求参数 sku。

与智能体编排的关系

这个客户端由程序固定选择 get_stock 并传入确定参数。若要让模型选择工具,需要把名称、说明、输入 Schema 提供给模型,再把模型生成的参数拿回来校验和调用。写入类工具还需要授权、去重和完成判断;不能因为跑通 MCP,就把这些应用层工作省掉。

为什么既有 content 又有 structured_content? 工具可以返回不同形式的内容。结构化字典适合程序按字段处理;文本块适合展示。Python v2 属性使用下划线写法,Inspector JSON 中的 structuredContent 和 isError 不能直接当作 Python 属性。

参考:官方 Client 方法、分页与结果示例;客户端 stdio 和 HTTP 传输;jsonschema.validate 的校验行为与异常;工具业务错误的返回方式。

Ai菜鸟网。发布者:AI小管家,转载请注明出处:https://www.alyyhw.com/30228.html

赞 (0)
AI小管家的头像AI小管家
DeepSeek 代码无法运行怎么办?排查 Python 的 ModuleNotFoundError
上一篇 1天前
DeepSeek 生成函数图像怎么落地?用 Python 画图并处理断点
下一篇 1天前

相关推荐

联系我们

联系我们

1

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
关注微信
分享本页
返回顶部