MCP工具开发实战:用Python编写并验证库存查询服务器

用官方 Python SDK v2 编写只读库存查询 MCP 工具,给出服务器和客户端完整代码,验证正常商品、零库存及未知编码,并说明模型编排、权限和真实数据边界。

想让 AI 查询业务数据,可以先把一个确定、只读、容易验收的函数公开成 MCP 工具。本文用演示库存表实现 get_stock:按商品编码返回数量,再通过独立客户端验证正常查询、库存为零和未知商品。它是工具接入层的开发实战,不包含模型自主规划,也不会创建订单。

环境与验收目标

以下代码已在 Windows、Python 3.11、官方 mcp==2.2.0 环境执行。Python SDK v2 的入口是 from mcp.server import MCPServer。如果原项目使用 v1 的 FastMCP,请先检查依赖版本,不要把两套 API 混着复制。

MCP工具开发实战:用Python编写并验证库存查询服务器

库存字典是人为设计的演示数据:PEN-001 有 18 件,BOOK-002 有 0 件。我们的目标是准确区分“库存为零”与“商品不存在”,不能把查不到的编码悄悄当成零库存。

mkdir C:\mcp-demo
cd C:\mcp-demo
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install "mcp==2.2.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.tool() 注册工具。sku: str 声明字符串输入;函数说明明确查询是只读的,不能下单或改库存。编码先去空格、转大写,再与演示表精确匹配。未知编码抛出官方 SDK 的 ToolError,使客户端收到可识别的失败结果。

返回字典提供两个字段:sku 是匹配后的编码,quantity 是整数数量。SDK 能基于类型生成输入与输出描述,但类型注解不能替代业务权限控制。如果以后接真实数据库,仍要在服务器里验证查询权限、数据范围及超时。

写一个协议客户端,不只直接调用 Python 函数

新建同目录的 check_stock.py。下面会启动服务器子进程,通过 MCP 发现工具并查询三个编码:

import asyncio
import sys
from pathlib import Path
from mcp import Client
from mcp.client.stdio import StdioServerParameters

async def main():
    server = Path(__file__).with_name("inventory_server.py")
    params = StdioServerParameters(command=sys.executable, args=[str(server)])
    async with Client(params) as client:
        listed = await client.list_tools()
        print([tool.name for tool in listed.tools])
        for sku in ["PEN-001", "BOOK-002", "MISSING"]:
            result = await client.call_tool("get_stock", {"sku": sku})
            print(sku, result.is_error, result.structured_content)
            if result.is_error:
                print(result.content)

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

sys.executable 使用正在运行客户端的 Python,避免子进程落到另一个未安装 SDK 的解释器。async with Client(...) 管理连接生命周期,退出时清理协议连接;不用自己把 JSON 消息塞进 stdin。

怎样判断这次开发成功

测试输入 预期结果 说明
工具发现 列表包含 get_stock,输入描述要求 sku 字符串 证明注册与发现有效
PEN-001 is_error=False,数量为 18 正常商品成功查询
BOOK-002 is_error=False,数量为 0 零库存是成功查询的结果
MISSING is_error=True,包含 Unknown SKU: MISSING 不存在的商品没有被伪装成零库存

正常商品和未知编码已通过实际 stdio 协议调用核对。读者应把三个输入都跑完,再考虑把工具接给模型。只在 Python 中执行 get_stock("PEN-001") 能验证函数逻辑,不能证明 MCP 发现、序列化和错误返回都正常。

接给智能体前,哪些内容还没完成

  • 模型编排: 本教程没有调用语言模型,也没有“查询后自动补货”的执行循环。宿主程序需要自己决定何时调用、如何展示结果以及何时停止。
  • 真实库存: 字典没有持久化、并发更新或库存时点;真实查询应返回数据来源和更新时间,并明确可售库存口径。
  • 权限: 这里只做只读演示。不要把修改库存、创建订单混进同一个模糊工具;具有写入行为的工具需要独立授权和幂等设计。
  • 输入范围: 编码规范化是示例规则。如果真实编码区分大小写,应删除转大写逻辑,并以业务实际规则为准。

排查 No module named mcp 时,先核对运行命令是不是虚拟环境里的 Python。发现列表为空时检查装饰器与文件是否保存;返回错误时先看 is_error 和错误内容,别让模型把失败内容改写成成功库存。

相关问答与依据

为什么选择 tool,而不是 resource? 本例要求按显式参数执行一次查询并返回结果,使用工具便于展示输入约束和错误。只读并不自动等于 resource;资源通常通过 URI 表示可读取上下文,具体选择取决于客户端任务。

没有模型账号可以练习吗? 可以。这里的服务端与测试客户端仅在本地收发协议,不使用模型密钥。后续接入具体模型宿主时,再按它的账号与权限要求配置。

参考:官方工具注册和参数说明;官方 ToolError 与错误处理;官方 Client 调用、生命周期和结果字段。

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

赞 (0)
AI小管家的头像AI小管家
Claude Code怎么接入本地MCP?配置、调用验证与移除教程
上一篇 1天前
MCP Inspector怎么调试工具?列参数、执行调用和定位错误
下一篇 1天前

相关推荐

联系我们

联系我们

1

在线咨询: QQ交谈

邮件:admin@example.com

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

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