Skip to content
AI中级阅读约 1 分钟

MCP 模型上下文协议 ​

本篇定位

讲清楚 MCP(Model Context Protocol)到底解决什么问题、Host/Client/Server 怎么分工,并用官方 Python SDK 从零写一个能跑的运维 MCP Server(查 K8s pod、查 Prometheus 指标),让你的 Agent/Claude Code/Cursor 用一套标准接口接你内部系统。 本篇版本:MCP 规范 2026-07-28(当前稳定版)、官方 Python SDK mcp 2.2.0(要求 Python ≥ 3.10)、官方 TypeScript SDK @modelcontextprotocol/sdk 1.30.0。所有版本以官网当前稳定版为准。

一、为什么需要 MCP ​

1.1 小白类比:M×N 集成灾难 vs USB-C 标准 ​

假设你有 M 个 AI 客户端(Claude Desktop、Cursor、你自己写的 LangGraph Agent、IDE 插件……),和 N 个内部系统(K8s、Prometheus、MySQL、Git、飞书……)。

没有 MCP 时:每接一个新系统,每个客户端都得单独写一套对接代码。M 个客户端 × N 个系统 = M×N 套集成,是个平方级的噩梦。

类比:以前每个电器一个充电器,手机一个口、笔记本一个口、相机又一个口,包里一堆线。USB-C 出来后,大家统一用这个口,一根线通吃。 MCP 就是 AI 世界的"USB-C 标准接口":每个系统只要实现一次 MCP Server,所有支持 MCP 的客户端都能直接用,变成 M + N。

1.2 一句话定义 ​

MCP 是一个开放协议,规定了"AI 应用(Host)如何用统一的方式去发现并调用外部系统提供的工具、读取其数据、复用其提示词模板"。 底层走 JSON-RPC。

二、核心概念:Host / Client / Server ​

角色是谁干什么类比
Host(宿主)你正在用的 AI 应用:Claude Desktop、Cursor、Claude Code、你写的 LangGraph 程序拥有 LLM、决定何时调用工具电脑/手机
Client(客户端)Host 内部的一个模块负责和某个 MCP Server 握手、按协议收发消息主板上的 USB-C 控制器
Server(服务端)你写的/别人提供的小进程对外暴露 Tools、Resources、PromptsU 盘、移动硬盘等外设

一个 Host 可以挂多个 Client,每个 Client 连一个 Server。Host 里的 LLM 看到所有 Server 汇总来的"工具清单",自己决定调哪个。

三、传输方式 Transport ​

MCP 规定了 Client 和 Server 之间怎么通信,两种主流:

Transport怎么跑适用特点
stdioServer 是个本地子进程,Host 通过它的标准输入/输出收发 JSON-RPC本地开发、接本机 CLI 工具(kubectl、数据库)最简单,不用开端口,Server 由 Host 拉起
Streamable HTTPServer 跑成一个 HTTP 服务,Host 通过 URL 连团队共享、远端部署、容器化可远程访问、可水平扩展,2026-07-28 规范主推无状态 HTTP 核心

历史上早期还有个 SSE(Server-Sent Events) 单向流式传输,2026-07-28 新规范已用 Streamable HTTP 统一取代(无状态核心、可在普通 HTTP 基础设施上扩展),新写 Server 直接上 Streamable HTTP,别再用老 SSE 模式。

四、三大原语(Tools / Resources / Prompts) ​

MCP Server 对外能提供三类东西,外加两个进阶能力:

原语谁来主动用通俗解释运维例子
Tools(工具)LLM 自主决定调用一个"会产生副作用/会算"的函数get_pods(namespace)、query_promql(expr)
Resources(资源)由用户/应用指定一段可读的数据/文件,只读某台机器的 /etc/nginx/nginx.conf、某个 incident 的记录
Prompts(提示模板)用户在 Host 里显式选择预定义好的提示词模板"帮我分析这段 nginx 报错日志"一键模板
进阶能力方向说明
SamplingServer → Host 反向Server 反过来请求 Host 里的 LLM 帮忙生成内容(少见)
RootsHost → ServerHost 告诉 Server"你只能在这些目录/范围内活动",用于沙箱边界

记忆法:Tools 是"手"(LLM 自己会动)、Resources 是"只读资料"、Prompts 是"现成话术"。 运维 90% 场景先用 Tools。

五、把运维系统接入 Agent 的全景 ​

六、常用 MCP Server 盘点 ​

Server提供方能干什么怎么获取
官方参考 server 仓库 modelcontextprotocol/servers官方filesystem、git、github、postgres、sqlite、fetch、puppeteer 等一批官方/参考实现GitHub 搜 modelcontextprotocol/servers
K8s / kubectl社区查 pod、deployment、日志、events社区 kubernetes-mcp-server 类项目
Prometheus/Grafana社区跑 PromQL、查告警面板Grafana 官方与社区均有
云厂商官方/社区查 ECS、对象存储、账单各家云市场
数据库官方参考postgres/sqlite 的只读查询上述官方 servers 仓库

官方 server 仓库地址:https://github.com/modelcontextprotocol/servers (里面每个目录是一个独立 server,README 有安装与配置示例)。

七、动手:用官方 SDK 写一个可跑的运维 MCP Server ​

下面用 Python SDK mcp 2.2.0 写一个"运维助手 Server":暴露两个工具——list_pods(查 K8s pod)和 query_prometheus(查 PromQL)。用 FastMCP 高层 API,几十行就能跑。

7.1 安装 ​

bash
# 建议建独立虚拟环境
python3 -m venv .venv && source .venv/bin/activate

# 写死版本,2.2.0 对应 2026-07-28 规范
pip install "mcp==2.2.0"
# 可选:下面示例用到的库
pip install "kubernetes==33.1.0" "requests==2.32.3"

7.2 完整代码 ops_server.py ​

python
# ops_server.py —— 一个最小可跑的运维 MCP Server(stdio 传输)
from mcp.server.fastmcp import FastMCP

# 1) 实例化,名字会显示在客户端的 server 列表里
mcp = FastMCP("ops-helper")

# 2) 定义工具:函数 docstring 会被自动当作工具说明喂给 LLM
@mcp.tool()
def list_pods(namespace: str = "default") -> str:
    """列出指定 namespace 下的 Pod 名称与状态。只读操作。

    Args:
        namespace: Kubernetes 命名空间,默认 default
    """
    try:
        from kubernetes import client, config
        try:
            config.load_incluster_config()      # 跑在集群里时用这个
        except Exception:
            config.load_kube_config()           # 本地开发用 ~/.kube/config
        v1 = client.CoreV1Api()
        pods = v1.list_namespaced_pod(namespace)
        lines = [f"{p.metadata.name}\t{p.status.phase}" for p in pods.items]
        return "\n".join(lines) if lines else f"namespace={namespace} 没有 Pod"
    except Exception as e:
        return f"查询失败: {e}"

@mcp.tool()
def query_prometheus(promql: str, prom_url: str = "http://127.0.0.1:9090") -> str:
    """执行一条 PromQL 瞬时查询并返回结果。只读操作。

    Args:
        promql: PromQL 表达式,如 rate(node_cpu_seconds_total[5m])
        prom_url: Prometheus 地址,默认本机 9090
    """
    import requests
    r = requests.get(f"{prom_url}/api/v1/query",
                     params={"query": promql}, timeout=10)
    r.raise_for_status()
    data = r.json()["data"]["result"]
    if not data:
        return "无数据"
    out = []
    for item in data:
        metric = ",".join(f"{k}={v}" for k, v in item["metric"].items())
        out.append(f"{metric} => {item['value'][1]}")
    return "\n".join(out)

# 3) 以 stdio 方式运行(Host 会把它当本地子进程拉起)
if __name__ == "__main__":
    mcp.run(transport="stdio")

7.3 先在命令行自测(不接 Host) ​

bash
# 启动自带的 MCP Inspector 可视化调试界面,浏览器里点着调工具
mcp dev ops_server.py
# 或直接命令行交互:
mcp run ops_server.py

mcp dev 会打开一个本地网页(Inspector),左边能看到 list_pods、query_prometheus 两个工具,填参数点调用,立刻看到返回——这是调试 MCP Server 最快的方式,别一开始就塞进 Claude Desktop 猜。

7.4 把它挂到 Host 里(以 Claude Desktop / Claude Code 的配置为例) ​

在 Host 的 MCP 配置文件里加一段(stdio 方式,告诉 Host 怎么拉起你的 Server):

json
{
  "mcpServers": {
    "ops-helper": {
      "command": "/绝对路径/.venv/bin/python",
      "args": ["/绝对路径/ops_server.py"]
    }
  }
}

重启 Host,它会自动拉起这个子进程、握手、把两个工具注入给 LLM。之后你在对话里说"看下 default 命名空间有哪些 pod",LLM 就会自己决定调 list_pods。

TypeScript 版本长什么样(对照)

TS SDK @modelcontextprotocol/sdk 1.30.0 用 McpServer + registerTool,思路完全一样:定义工具名、描述、输入 Schema,然后处理 handler。运维同学若团队是 JS/TS 技术栈可直接用,官方模板见 typescript-sdk 仓库 examples。

八、安全边界(生产红线重点) ​

MCP Server 手里握着你内网的真实系统,它就是一个能被 LLM 触发的后门,必须上锁:

原则怎么做
默认只读运维查询类 Server 只暴露 list_*、query_*,不暴露 delete/apply/scale
最小权限给 Server 的 K8s token、数据库账号按 namespace/库表授权,用只读账号,别用 cluster-admin
输入校验Server 内部对 LLM 传来的参数再校一遍(namespace 白名单、PromQL 禁止带 [for] 写操作之类),别信任 LLM 的"善意"
高危操作人工审批任何会改状态的工具,执行前必须 human-in-the-loop(见运维实战)
全程审计每次工具调用的入参、返回、调用者都记日志,可回放、可追责
网络收敛HTTP 传输的 Server 只监听内网,前面加鉴权(2026-07-28 规范强化了 OAuth/OIDC 授权),别裸露公网

九、常见问题排错 ​

现象原因解决
Host 里看不到我写的工具路径/解释器不对,Server 启动就崩了先用 mcp dev ops_server.py 本地跑通;检查配置里 command 用绝对路径、venv 里的 python
握手失败 / Connection closedSDK 版本与 Host 期望规范不匹配用 mcp==2.2.0;注意 v1.x(mcp<2)与 v2 不兼容,老项目临时用 mcp>=1.28,<2
工具一直不被调用docstring/参数描述写得太笼统,LLM 不知道啥时候用写清工具用途和参数含义,给例子;temperature 调低
stdio 下日志打不出来stdio 通道被 JSON-RPC 占用,print 会污染协议日志写到 stderr 或文件,不要往 stdout print
HTTP 方式连不上没开端口 / 防火墙 / 路径不对确认用 Streamable HTTP 端点;本机 curl 先打通;别再用已废弃的老 SSE 路径

生产红线

  • 永远不要给 MCP Server 生产写权限:读和写拆成两个 Server,写那个强制走人工审批。
  • 版本写死:Python 用 mcp==2.2.0,TypeScript 用 @modelcontextprotocol/sdk@1.30.0,升级前先在 Inspector 里回归。
  • HTTP 传输的 Server 必须加鉴权 + 内网隔离,严禁 0.0.0.0 裸奔到公网。
  • 每个工具都要有超时和资源上限,防止 LLM 写出一条把 Prometheus 打挂的 PromQL。
  • 定期审计工具清单:没人用的 Server 及时下线,缩小攻击面。

相关速查 ​

官方文档 ​