200 行代码实现 MCP 协议:让 AI "动手干活"

0 阅读5分钟

200 行代码实现 MCP 协议:让 AI "动手干活"

什么是 MCP?

MCP(Model Context Protocol,模型上下文协议)是由 Anthropic 推出的一种开放协议,旨在标准化 AI 模型与外部数据源、工具之间的交互方式。简单来说,它让大语言模型能够安全、可控地调用外部工具,就像给 AI 装上了"手脚"。

今天我们通过开源项目CatMCP,从0到1拆解MCP的Python实现,带你吃透客户端、服务器、工具调用、LLM集成的核心代码。

图片

一、项目总览:CatMCP实现框架

CatMCP是基于Python的轻量级MCP示例,核心通过标准输入输出实现客户端与服务器通信,兼容OpenAI/通义千问等大模型,自带天气查询、新闻搜索工具,代码结构清晰,非常适合学习MCP原理。

项目文件结构:

catmcp/
├── main.py          # 主入口,演示MCP客户端调用
├── stdio_client.py  # MCP客户端(子进程启动服务器、LLM交互、工具调度)
├── stdio_server.py  # MCP服务器(JSON-RPC 2.0、工具注册、请求处理)
├── requirements.txt # 依赖清单
└── .env# API密钥配置

核心技术栈:Python 3.12+、JSON-RPC 2.0、OpenAI SDK、python-dotenv。

二、核心代码逐行拆解

1. MCP服务器:stdio_server.py(工具提供方)

服务器是MCP的能力提供端,基于JSON-RPC 2.0协议,通过标准IO接收请求、执行工具、返回结果。

1.1 工具注册与定义
# 工具注册字典(核心扩展点)
TOOLS = {
    "get_weather": {
        "description""获取指定地点的天气信息",
        "inputSchema": {
            "type""object",
            "properties": {"location": {"type""string""description""城市名称"}},
            "required": ["location"],
        },
        "handler": get_weather,
    },
    "search_news": {
        "description""根据关键词搜索新闻",
        "inputSchema": {
            "type""object",
            "properties": {"query": {"type""string""description""搜索关键词"}},
            "required": ["query"],
        },
        "handler": search_news,
    },
}
  • inputSchema:严格遵循JSON Schema,定义工具入参类型、必填项,LLM自动解析调用
  • handler:工具执行函数,替换为真实API即可落地
1.2 工具实现函数
def get_weather(location: str) -> str:
    # 模拟天气数据,实际替换为天气API
    return f"{location}的天气是晴,温度是22摄氏度"

def search_news(query: str) -> str:
    # 模拟新闻数据,实际替换为新闻搜索API
    return f"搜索关键词:{query},搜索结果:国内油价24日将迎年内第六轮调整..."
1.3 JSON-RPC 2.0请求处理

服务器循环读取标准输入,解析RPC请求,分发到对应方法:

def handle_request(request: dict) -> dict:
    method = request.get("method")
    params = request.get("params", {})
    request_id = request.get("id")

    if method == "initialize":
        # 初始化:返回协议版本、工具列表
        return {"jsonrpc""2.0""result": {"protocolVersion""0.1""tools": list(TOOLS.keys())}, "id": request_id}
    elif method == "tools/list":
        # 返回所有工具详情(含Schema)
        return {"jsonrpc""2.0""result": TOOLS, "id": request_id}
    elif method == "tools/call":
        # 执行工具调用
        tool_name = params.get("name")
        tool_params = params.get("parameters", {})
        if tool_name not in TOOLS:
            return {"jsonrpc""2.0""error": {"code": -32601"message""Method not found"}, "id": request_id}
        result = TOOLS[tool_name]["handler"](**tool_params)
        return {"jsonrpc""2.0""result": result, "id": request_id}
    else:
        return {"jsonrpc""2.0""error": {"code": -32601"message""Method not found"}, "id": request_id}

支持3个核心RPC方法:

  • initialize:初始化握手,返回协议版本
  • tools/list:向客户端暴露所有工具
  • tools/call:执行具体工具调用
1.4 服务器主循环
def run_server():
    # 持续监听标准输入,处理请求
    for line in sys.stdin:
        line = line.strip()
        if not line:
            continue
        request = json.loads(line)
        response = handle_request(request)
        print(json.dumps(response, ensure_ascii=False))
        sys.stdout.flush()
  • 基于标准IO通信,无网络依赖,本地直接运行
  • 逐行读取JSON请求,处理后返回JSON响应

MCP服务器工作流程图:读取stdin→解析RPC→执行工具→返回stdout

图片

2. MCP客户端:stdio_client.py(调度与LLM集成)

客户端是MCP的调用方,负责启动服务器子进程、与LLM对话、解析工具调用、转发请求到服务器。

2.1 启动服务器子进程
class MCPClient:
    def __init__(self):
        # 子进程启动MCP服务器,管道通信
        self.server_process = subprocess.Popen(
            [sys.executable, "stdio_server.py"],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            encoding="utf-8"
        )
        self.initialize()

    def _send_request(self, method: str, params: dict = None) -> dict:
        # 发送JSON-RPC请求到服务器
        request_id = str(uuid.uuid4())
        request = {"jsonrpc""2.0""method": method, "params": params or {}, "id": request_id}
        self.server_process.stdin.write(json.dumps(request, ensure_ascii=False) + "\n")
        self.server_process.stdin.flush()
        # 读取服务器响应
        response = self.server_process.stdout.readline()
        return json.loads(response)
  • subprocess启动服务器,通过stdin/stdout双向通信
  • 自动生成请求ID,保证请求-响应匹配
2.2 LLM集成与工具调用
def run_agent_with_mcp(prompt: str) -> str:
    # 初始化LLM(通义千问/OpenAI兼容)
    llm = OpenAI(
        api_key=os.getenv("API_KEY"),
        base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
        model="qwen-plus"
    )
    client = MCPClient()
    # 获取服务器工具列表
    tools = client._send_request("tools/list")["result"]
    # 构造LLM支持的工具格式
    llm_tools = [{"type""function""function": {"name": k, "description": v["description"], "parameters": v["inputSchema"]}} for k, v in tools.items()]
    # LLM对话
    messages = [{"role""user""content": prompt}]
    response = llm.chat.completions.create(model="qwen-plus", messages=messages, tools=llm_tools)
    # 处理工具调用
    tool_call = response.choices[0].message.tool_calls[0]
    tool_name = tool_call.function.name
    tool_params = json.loads(tool_call.function.arguments)
    # 调用MCP服务器
    result = client._send_request("tools/call", {"name": tool_name, "parameters": tool_params})["result"]
    return result

核心流程:

  1. 从服务器获取工具清单
  2. 转换为LLM兼容格式
  3. LLM判断是否调用工具、生成入参
  4. 客户端转发调用到服务器,返回结果给LLM

MCP客户端与LLM交互流程图:用户提问→LLM决策→调用工具→返回结果

图片

3. 主入口:main.py(快速体验)

from stdio_client import run_agent_with_mcp

def main():
    # 示例1:搜索新闻
    news_result = run_agent_with_mcp("搜索今日新闻")
    print(news_result)
    # 示例2:查询天气
    weather_result = run_agent_with_mcp("查询上海天气")
    print(weather_result)

if __name__ == "__main__":
    main()

运行命令:

pip install -r requirements.txt
# 配置.env文件API_KEY
python main.py

三、扩展开发:快速添加自定义工具

stdio_server.pyTOOLS字典添加新工具,无需修改客户端代码

# 新增工具函数
def calculate(expression: str) -> str:
    try:
        return f"计算结果:{eval(expression)}"
    except:
        return "表达式错误"

# 注册到工具列表
TOOLS["calculate"] = {
    "description""计算数学表达式",
    "inputSchema": {
        "type""object",
        "properties": {"expression": {"type""string""description""数学表达式"}},
        "required": ["expression"],
    },
    "handler": calculate,
}

重启程序,LLM即可自动识别并调用新工具。

四、核心原理总结

  1. MCP本质:标准化的模型-工具通信协议,基于JSON-RPC 2.0,降低集成复杂度
  2. 通信方式:CatMCP用标准IO,轻量无网络,适合本地工具;生产可改用WebSocket/HTTP
  3. 扩展能力:工具注册+Schema声明,LLM自动理解调用,支持动态扩展
  4. 架构优势:客户端与服务器解耦,LLM无需感知工具细节,专注推理

CatMCP用不到200行核心代码,完整实现MCP协议核心流程,是学习AI工具调用的绝佳案例。替换模拟数据为真实API、优化异常处理、添加日志,即可快速落地到生产项目。

关注公众号【dev派】,发送 "agent" 获取全部源码和模板

图片