🤖 AI Agent 实战 · 第 3 篇

MCP(Model Context Protocol)是什么:一次讲清协议、传输与写 Server

作者:VillaB · 发布:2026-10-27 · 更新:2026-10-27 · 分类:AI Agent

它到底解决什么问题

没有 MCP 之前,每个 AI 应用想接一个数据源(数据库、GitHub、公司内部 API),都要写一遍适配代码。N 个客户端 × M 个数据源 = N×M 份集成。

MCP 把这件事变成 N+M:数据源方写一次 server,客户端方实现一次 client,中间的协议由 MCP 定义。

类比:MCP 之于 AI 应用,类似 LSP 之于编辑器。写一次语言服务器,VS Code、Vim、JetBrains 都能用。

一、架构:client 和 server

┌──────────────┐        MCP 协议         ┌──────────────┐
│  MCP Client  │ ◄─────────────────────► │  MCP Server  │
│ (Claude 等)  │                         │ (你的工具)    │
└──────────────┘                         └──────────────┘
        │                                        │
   模型 + 对话逻辑                          真正的数据/API
  • Host:用户用的应用(如 Claude Desktop),内部为每个 server 起一个 client
  • Client:维护与某个 server 的一对一连接,负责能力协商和消息路由
  • Server:暴露工具与数据,通常是本地进程或远程服务

职责划分很关键:模型不直接连 server,是 client 把 server 提供的能力翻译成模型的工具定义。

二、三类服务端原语(最容易混淆的部分)

原语 谁控制 典型用途 类比
tools 模型决定调用 有副作用或需参数的操作 函数调用
resources 应用/用户决定读取 可 URI 定位的数据 GET 请求 / 文件
prompts 用户主动选择 预设的提示词模板 斜杠命令

判断规则很重要:

  • 读数据用 resources,别做成 tool——resource 可缓存、可按 URI 引用、不会污染上下文
  • 有副作用、需参数化执行 → tool
  • 给用户一个「一键执行某流程」的入口 → prompt

反例:把「读取项目 README」做成 read_readme 工具,是常见的设计错误——那应该是 file://README.md 这个 resource。

三、两种传输方式

传输 场景 特点
stdio 本地进程 最简单,client 直接 spawn 子进程,用标准输入输出通信
Streamable HTTP 远程服务 单个 HTTP 端点,支持流式响应与会话;取代了早期的 HTTP+SSE 方案

本地方案 99% 用 stdio;要给多个用户共享一个 server 才需要 HTTP。

四、写一个最小可用的 Python server

用官方 SDK:

pip install mcp
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("ticket-server")

@mcp.tool()
def query_ticket(ticket_id: str) -> dict:
    """查询工单详情。

    当用户询问某个工单的状态、负责人或处理进度时使用。
    不需要参数化写入时不要用本工具。

    Args:
        ticket_id: 工单号,形如 T-2026-001,必填
    """
    return {"ticket_id": ticket_id, "status": "processing", "owner": "张三"}

@mcp.resource("ticket://list")
def list_tickets() -> str:
    """返回当前所有工单的列表(只读)"""
    return "T-2026-001 processing
T-2026-002 closed"

@mcp.prompt()
def triage(ticket_id: str) -> str:
    """生成工单分诊提示词"""
    return f"请分析工单 {ticket_id} 的紧急程度,并给出处理建议。"

if __name__ == "__main__":
    mcp.run()          # 默认 stdio 传输

三个细节决定好不好用:

  1. docstring 就是给模型的 description——写清「做什么 / 何时用 / 何时不要用 / 返回什么」
  2. 返回体要有上限:列表类接口必须截断(如最多 50 条),否则一次吐几十万字符会把上下文撑爆
  3. 错误要可区分:抛出的异常信息要能区分「鉴权失败 / 不存在 / 限流 / 参数错」,Agent 才可能自我纠正

五、客户端怎么接

Claude Desktop 的配置(claude_desktop_config.json):

{
  "mcpServers": {
    "ticket": {
      "command": "python",
      "args": ["/path/to/server.py"],
      "env": { "TICKET_API_KEY": "..." }
    }
  }
}

远程 HTTP server 则用 URL 形式:

{
  "mcpServers": {
    "ticket": { "url": "https://mcp.example.com/mcp" }
  }
}

六、安全:MCP 不是"开了就安全"

这是最容易被忽略的一节。MCP server 相当于给模型开了系统权限:

风险 说明 对策
提示注入 工具返回的内容里藏指令,模型照做 工具返回内容标记为「数据」而非「指令」;对返回内容做过滤
权限过大 一个 tool 能删库 最小权限;写操作单独工具 + 二次确认
凭证泄露 key 写进配置文件被读取 用环境变量;配置文件不入库
数据外泄 恶意 server 把数据发到外部 只装可信 server;审阅开源 server 代码

最实用的三条:不确定的 server 先在隔离环境跑;写操作工具必须与人确认;给 server 的凭证只开必要权限。

七、什么时候值得上 MCP

  • 你有一个内部系统要被多个 AI 客户端用到 → 值得
  • 你只在自家一个应用里调工具 → 直接用 Function Calling 更简单
  • 只是读文档 → 可能一个文件读取工具就够,不必写完整 server

相关技能

返回文章列表