WorkBuddy + eNSP 的 MCP 到底怎么工作?——底层原理一篇讲清

前言:一句话从对话到 eNSP 回显,中间发生了什么?

打开 WorkBuddy 对话框,输入一句“帮我跑一遍单臂路由实验”,按下回车后,会发生这样一串事:

WorkBuddy 把这句话拆成若干步骤;每一步它会调用 grbj-ensp MCP 提供的某个工具;MCP 把这些工具调用翻译成 eNSP 设备的 CLI 命令送进去;设备跑完命令后回显又被 MCP 抓回来,解析成结构化结果;WorkBuddy 拿到结果再决定下一步做什么;最后把所有步骤的回显整理成一份 .docx 实验报告。

这条链路里有三个关键名词:WorkBuddy(AI Agent)、MCP(Model Context Protocol)、Skill(操作手册)。本文就是把它们一层层掀开,让一个不熟悉 AI 工具链的读者也能看懂“自然语言是怎么变成 eNSP 里的真实配置”的。

下面我们先把三个名词摆正。

一、先把三个名词摆正:WorkBuddy / MCP / Skill

很多读者第一次接触 WorkBuddy 时,会被“MCP”“Skill”“插件”“连接器”这些词绕晕。我们把它们简化成三个角色:

WorkBuddy 是“AI 操作员”。 它是跑在你电脑上的客户端,内置一个能听懂自然语言、能调用本机能力的 AI Agent。你在对话框里说的话,由它来理解和执行;它的产出——文本、文件、命令——最终会出现在你的屏幕上。

MCP 是“AI 操作员伸向工具的手”。 当 WorkBuddy 需要去 eNSP 里查一台交换机的 display vlan,它不可能自己开 eNSP 客户端、定位设备、敲命令、抓回显;它会把这件事“外包”给一个 MCP 服务端。MCP(Model Context Protocol)是一套标准协议,规定 AI 客户端与外部工具之间怎么说话。

Skill 是“AI 操作员背下的操作手册”。 你让 WorkBuddy 配一台交换机,它怎么知道要先建 VLAN、再配 Trunk、再配 VLANIF、最后验证?这不是 MCP 教的——MCP 只负责“送命令进设备、抓回显”。流程上的“什么时候该做什么”,写在 Skill 里。Skill 本质上是一份带工作流的提示词(prompt),告诉 AI 面对这类任务时该按什么步骤思考、该按什么顺序调用 MCP。

三者关系可以用一句话记:

AI(WorkBuddy Agent)= 决策者;Skill = 手册;MCP = 工具手。

决策者拿着手册指挥手去做事;手册告诉它“该做啥、按啥顺序做”;手负责“把动作真做完、把结果带回来”。在《eNSP 新玩法:交给 WorkBuddy,设备配置自动完成》的单臂路由例子里:用户说“配置单臂路由”→ Skill 提示按“建拓扑→配 VLAN→配子接口→配 DHCP→验证”五步走 → 每一步 MCP 把命令送进 eNSP。

二、MCP 是什么——把它讲成一个标准协议

MCP(Model Context Protocol)由 Anthropic 在 2024 年提出,本质是为“LLM 调用外部工具”这件事立一个标准。

2.1 为什么需要这个标准?

在 MCP 之前,每个 AI 客户端想接入一个外部工具,都得单独写一套适配代码。比如 WorkBuddy 想用 eNSP,就得自己写“怎么开连接、怎么发命令、怎么等回显”;想用 Git,又得写一套“怎么调 git 命令、怎么解析 diff”。每个工具一套实现,互不通用。

MCP 把这件事标准化了:只要你按 MCP 协议把工具能力“注册”出来,任何支持 MCP 的 AI 客户端都能直接调用,不需要再写适配。

2.2 MCP 的三层结构

MCP 协议分三层:

  1. 协议层:规定请求/响应的报文格式(基于 JSON-RPC 2.0),以及传输方式(stdio / SSE / HTTP)。
  2. 客户端层(Host):WorkBuddy 这种 AI 客户端,负责维护到各个 MCP 服务端的连接、路由消息、聚合工具列表。
  3. 服务端层(Server)grbj-ensp MCP 就是一个服务端。它把“连接 eNSP 设备、发送 CLI 命令、读取 display 回显”等能力注册成一个个 @tool(),让客户端通过协议发现并调用。

2.3 一个类比:USB-C 之于外设

可以把它类比为 USB-C。以前每接一个外设(鼠标、键盘、移动硬盘),主板要预留不同接口、写不同驱动;USB-C 之后,所有外设只要遵循 USB-C 标准,主板一个口就能接所有。MCP 对 AI 工具的意义类似——以前每接一个工具要写一套适配,有了 MCP,只要按协议把 tool 注册出来,AI 客户端就能“即插即用”。

2.4 grbj-ensp MCP 在这套标准里的角色

grbj-ensp MCP 是一个 MCP 服务端。它的职责是把 eNSP 模拟器里那些“原本要人手敲的命令”,封装成 AI 可以直接调用的 tool。比如:

  • connect_device(device_name):连接到 eNSP 内指定设备
  • send_command(device_name, command):发送一条 CLI 命令并返回结构化结果
  • verify_vlan / verify_ospf / verify_routes 等:执行标准验证命令
  • save_config / health_check 等:保存配置、做健康检查

总共十来个 tool,每个都对应一个明确的动作。MCP 不关心“这个工具怎么实现”,只关心“你能暴露成什么 tool、参数 schema 怎么填”。

三、Skill 是什么——给 AI 的“操作手册”长什么样

如果说 MCP 是“AI 操作员的工具手”,那 Skill 就是“AI 操作员背下的操作手册”。

3.1 Skill 的本质

Skill 本质上是一份 markdown 文档 + 元数据 + 可选脚本。它的核心作用是:告诉 AI 面对一类任务时该怎么思考、该按什么顺序调用工具。

比如 grbj-ensp-smart-config 这个 Skill,它的内部结构大致包含:

  • 角色定义:开头告诉 AI “你是 eNSP 网络实验配置助手”
  • 工具清单:列出可调用的 MCP tool 范围
  • 工作流模板:典型任务的步骤序列,比如“建拓扑 → 启动设备 → 基础配置 → 三层配置 → 验证 → 出报告”
  • 输出规范:实验报告需要包含哪些章节、回显需要保留哪些字段

3.2 与 MCP 的分工

Skill 和 MCP 经常被搞混,其实它们职责清晰:

  • Skill 管“什么时候该做什么”——是流程判断
  • MCP 管“具体怎么做到”——是执行实现

打个比方:Skill 是菜谱,MCP 是锅铲。菜谱告诉你“先热锅再下油,油温七成热时下菜”;锅铲负责真正把油打进去、把菜翻起来。AI 看着菜谱(Skill)指挥锅铲(MCP)做菜。

3.3 一个常见误解

很多人以为“装了 MCP 就够了”。实际上,如果你只装 MCP 不装 Skill,AI 会拿着 MCP 一通乱调——它不知道“配一台交换机该按啥顺序”,可能先配 VLANIF 再建 VLAN,结果就是配置报错返工。Skill 的存在,把“流程”这件事从通用大模型的猜测里抽出来,变成可复用的领域知识。

四、从一句自然语言到 eNSP 回显:完整调用链

到这里我们把三个名词都讲清楚了。下面把它们串起来,看一句“帮我配置单臂路由”是怎么走完全链路的。

4.1 五个角色

完整调用链涉及五个角色:

  1. 用户:在 WorkBuddy 对话框输入指令
  2. WorkBuddy Agent:内置 AI,负责理解指令、决策
  3. Skill 提示:决定 AI 该按什么流程办事
  4. MCP 客户端:WorkBuddy 内部组件,负责把 tool 调用转成 MCP 协议消息
  5. grbj-ensp MCP 服务端:接收 tool 调用、与 eNSP 设备通信
  6. eNSP 设备:被模拟的路由器/交换机,执行 CLI 命令

4.2 六个步骤

步骤 角色 动作
1 用户 输入“帮我配置单臂路由”
2 Agent 读取 Skill 提示,知道该按“建拓扑→配置”流程走
3 Agent 把“配置单臂路由”拆成若干 tool 调用(如 send_command 多次)
4 MCP 客户端 用 JSON-RPC 把每次 tool 调用送进 grbj-ensp MCP 服务端
5 MCP 服务端 通过 telnet/socket 把 CLI 命令送进 eNSP 模拟的设备
6 回传链 设备回显 → MCP 解析 → MCP 客户端 → Agent → 输出到对话

4.3 一份简化的 JSON-RPC 报文样例

MCP 协议里每次 tool 调用大致长这样(简化版):

{
  "jsonrpc": "2.0",
  "id": 7,
  "method": "tools/call",
  "params": {
    "name": "send_command",
    "arguments": {
      "device_name": "AR1",
      "command": "display vlan"
    }
  }
}

grbj-ensp MCP 服务端收到这个请求,会去 AR1 设备上敲 display vlan,把回显解析成结构化结果,再按 JSON-RPC 格式回传:

{
  "jsonrpc": "2.0",
  "id": 7,
  "result": {
    "device": "AR1",
    "command": "display vlan",
    "parsed": [
      {"vlan_id": 10, "status": "active", "ports": ["GE0/0/1"]},
      {"vlan_id": 20, "status": "active", "ports": ["GE0/0/2"]}
    ],
    "success": true
  }
}

Agent 拿到这份结构化结果,就能接着判断“下一步该配啥”。

4.4 时序图

五、贴一段真源码:MCP 服务端怎么处理一条 display 命令

理论讲完了,看一段真源码会更有感觉。下面三段代码节选自 grbj-ensp MCP 服务端(Python 实现),覆盖“tool 注册 → CLI 发送 → 回显解析”三个核心环节。

5.1 入口注册:@mcp.tool() 装饰器做了什么

from mcp.server import Server
from pydantic import Field

mcp = Server("grbj-ensp")

@mcp.tool()
def send_command(
    device_name: str = Field(..., description="eNSP 内设备名"),
    command: str = Field(..., description="要发送的 CLI 命令"),
    timeout: int = Field(30, description="等待回显超时秒数"),
) -> dict:
    """向 eNSP 内指定设备发送单条 CLI 命令,返回结构化回显"""
    ...

这段代码解决的是什么问题:让一个普通 Python 函数“被 MCP 协议发现”。@mcp.tool() 装饰器把函数名、参数 schema(从类型注解 + Field 推导)注册成 MCP 协议里的一个 tool;AI 客户端只要握手成功,就能列出这个 tool 及其参数定义,然后按 JSON-RPC 调过来。

5.2 CLI 发送:用 pexpect 与 eNSP 设备对话

import pexpect

def _send_to_device(session, command: str, timeout: int) -> str:
    session.sendline(command)
    # 等待提示符或确认符
    idx = session.expect(
        [r"<[^>]+>",          # <Huawei> / <H3C> 等提示符
         r"\[Y/N\]",          # 配置确认提示
         r"\$",               # 退出确认
         pexpect.TIMEOUT],
        timeout=timeout,
    )
    if idx == 3:
        raise TimeoutError(f"命令 {command!r} 等待回显超时")
    raw = session.before.decode("utf-8", errors="ignore")
    return raw

这段代码解决的是什么问题:eNSP 设备的 console 本质是一个字符终端(虚拟 telnet 会话),不是结构化 API。sendline 模拟人手敲回车;expect 用正则匹配提示符,判定“命令是否已执行完”。这是 eNSP 这类模拟器通信的通用模式——没有 REST、没有 RPC,只有字符流。

5.3 回显解析:把屏幕文本变结构化结果

class DisplayParser:
    def __init__(self, command: str):
        self.command = command
        # 不同 display 命令有不同解析规则
        self._parsers = {
            "display vlan": self._parse_vlan,
            "display vrrp": self._parse_vrrp,
            "display ip routing-table": self._parse_routes,
        }

    def parse(self, raw: str) -> list[dict]:
        parser = self._parsers.get(self.command.strip())
        if not parser:
            return [{"raw": raw}]
        return parser(raw)

    def _parse_vlan(self, raw: str) -> list[dict]:
        result = []
        for line in raw.splitlines():
            # 匹配类似 "10  common  active  GE0/0/1,GE0/0/2" 的行
            m = re.match(r"\s*(\d+)\s+(\w+)\s+(\w+)\s+(.*)", line)
            if m:
                result.append({
                    "vlan_id": int(m.group(1)),
                    "type": m.group(2),
                    "status": m.group(3),
                    "ports": m.group(4).split(","),
                })
        return result

这段代码解决的是什么问题:原始回显是一坨带 ANSI 控制字符的纯文本,AI 直接读会很费 token。每个 display xxx 命令都有对应 parser,知道怎么把“VID 10 active GE0/0/1”这种行抽成 {"vlan_id": 10, "status": "active", "ports": ["GE0/0/1"]} 的字典。AI 拿到的是结构化结果,下一步决策会准确得多。

5.4 这三段代码放在一起,串成什么

回头看:

  • 第一段把函数注册成 MCP tool——AI 能调用了
  • 第二段负责和设备对话——命令真送进去了、回显真拿回来了
  • 第三段负责结构化回显——AI 拿到的是结构化结果,不是乱糟糟的屏幕文本

AI 自己不需要懂华为 CLI 的细节、不需要懂正则匹配、不需要懂字符终端通信——这些都被 MCP 封装好了。AI 只负责“该调什么 tool、参数填什么、结果怎么解读、下一步做什么”。

六、从原理回到前两篇实验:为什么“分段下发”比“一次下完”更稳

讲完原理,回过头看《eNSP 新玩法:AI 接手,双核心园区网自动跑通》里的一个设计:把整个双核心园区网的配置拆成 4 段指令下发。从 MCP 的视角,这件事为什么合理?

每段指令结束后,MCP 都会返回结构化结果。 Agent 拿到结果再判断下一步——这是天然的回显驱动工作流。

反例:一次下发 200 行配置命令。MCP 会按顺序把每条命令送进设备,但任何一条错就可能影响后续;报错后 AI 也很难定位是哪一行;想要“出错就停下来”也做不精细。

对比传统脚本:传统 Python 脚本一把梭,没有回显校验,错了就全盘乱。MCP 的好处在于:每一步都是独立的 tool 调用,每步都有独立的结构化返回,每步都可独立验证、独立重试。

这就是 MCP + Skill 的本质好处:把“大任务”拆成“小 tool 调用”,让 AI 不用一次性把所有事做完,而是按步骤推进、每步可观察、错可回滚。

七、什么时候该自己写一个 MCP / Skill

很多读者看完会想问:如果我想让自己的 AI 也能指挥某个工具,是不是该自己写?

写 MCP 的场景:你手里有一个“可以被脚本化的工具”——公司内部平台、某个 CLI 设备、本地数据库、本地硬件(比如一台示波器)。只要你能用 Python/Node 跟它通信,就能套上 MCP SDK 把它暴露成 tool,让 AI 调用。

写 Skill 的场景:你希望 AI 按你定义的流程办事,而不是凭通用理解瞎跑。比如你的部门有一套“先备份再修改再验证”的运维规范,你想让 AI 严格遵守——这就该写一个 Skill,把流程写成 Skill 的工作流模板。

入门指引

  • MCP 官方文档:modelcontextprotocol.io
  • 官方 SDK:Python / Node / Go 都有
  • 参考实现:grbj-ensp MCP(本文剖析的对象),可直接看其源码学

推荐起步路径:用官方 SDK 写一个 hello-mcp,暴露一个最简单的 tool(比如让 AI 调用本地时间);跑通协议握手后,再考虑接入真实工具。

结语:工具替了双手,设计意图仍在人手里

回到《eNSP 新玩法:AI 接手,双核心园区网自动跑通》延伸思考里的同一个问题:AI 接管了这么多配置动作,学网络还有意义吗?

把 MCP + Skill 这条链路看清楚后,答案反而更清晰了:AI 接管的是“明确的需求翻译成有序的 CLI 并跑验证”这一段;它不能替工程师持有的是“为什么要用 MSTP 而不是 STP”、“VRRP 主网关为什么给 Core-SW1”、“ACL 该 deny 哪些网段”——这些设计意图必须由人在 Skill 的工作流里、或在自然语言指令里明确表达。

MCP 让 AI 的“手”伸得更远;Skill 让 AI 的“脑”知道边界;工程师的角色,是这两个之外的第三件事——定义问题。

上一篇 WorkBuddy + eNSP 的 MCP 到底怎么工作?——底层原理一篇讲清