Learn Claude Code
s19

MCP & Plugin

Multi-Agent Platform

External Capability Bus|463 LOC|4 tools

External capabilities join the same routing, permission, and result-append path as native tools.

s00 > s01 > s02 > s03 > s04 > s05 > s06 > s07 > s08 > s09 > s10 > s11 > s12 > s13 > s14 > s15 > s16 > s17 > s18 > [ s19 ]

工具不必都写死在主程序里。外部进程也可以把能力接进你的 agent。

这一章到底在讲什么

前面所有章节里,工具基本都写在你自己的 Python 代码里。

这当然是最适合教学的起点。

但真实系统走到一定阶段以后,会很自然地遇到这个需求:

“能不能让外部程序也把工具接进来,而不用每次都改主程序?”

这就是 MCP 要解决的问题。

先用最简单的话解释 MCP

你可以先把 MCP 理解成:

一套让 agent 和外部工具程序对话的统一协议。

在教学版里,不必一开始就背很多协议细节。
你只要先抓住这条主线:

  1. 启动一个外部工具服务进程
  2. 问它“你有哪些工具”
  3. 当模型要用它的工具时,把请求转发给它
  4. 再把结果带回 agent 主循环

这已经够理解 80% 的核心机制了。

为什么这一章放在最后

因为 MCP 不是主循环的起点,而是主循环稳定之后的扩展层。

如果你还没真正理解:

  • agent loop
  • tool call
  • permission
  • task
  • worktree

那 MCP 只会看起来像又一套复杂接口。

但当你已经有了前面的心智,再看 MCP,你会发现它本质上只是:

把“工具来源”从“本地硬编码”升级成“外部可插拔”。

建议联读

最小心智模型

LLM
  |
  | asks to call a tool
  v
Agent tool router
  |
  +-- native tool  -> 本地 Python handler
  |
  +-- MCP tool     -> 外部 MCP server
                        |
                        v
                    return result

最小系统里最重要的三件事

1. 有一个 MCP client

它负责:

  • 启动外部进程
  • 发送请求
  • 接收响应

2. 有一个工具名前缀规则

这是为了避免命名冲突。

最常见的做法是:

mcp__{server}__{tool}

比如:

mcp__postgres__query
mcp__browser__open_tab

这样一眼就知道:

  • 这是 MCP 工具
  • 它来自哪个 server
  • 它原始工具名是什么

3. 有一个统一路由器

路由器只做一件事:

  • 如果是本地工具,就交给本地 handler
  • 如果是 MCP 工具,就交给 MCP client

Plugin 又是什么

如果 MCP 解决的是“外部工具怎么通信”,
那 plugin 解决的是“这些外部工具配置怎么被发现”。

最小 plugin 可以非常简单:

.claude-plugin/
  plugin.json

里面写:

  • 插件名
  • 版本
  • 它提供哪些 MCP server
  • 每个 server 的启动命令是什么

最小配置长什么样

{
  "name": "my-db-tools",
  "version": "1.0.0",
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"]
    }
  }
}

这个配置并不复杂。

它本质上只是在告诉主程序:

“如果你想接这个 server,就用这条命令把它拉起来。”

最小实现步骤

第一步:写一个 MCPClient

它至少要有三个能力:

  • connect()
  • list_tools()
  • call_tool()

第二步:把外部工具标准化成 agent 能看懂的工具定义

也就是说,把 MCP server 暴露的工具,转成 agent 工具池里的统一格式。

第三步:加前缀

这样主程序就能区分:

  • 本地工具
  • 外部工具

第四步:写一个 router

if tool_name.startswith("mcp__"):
    return mcp_router.call(tool_name, arguments)
else:
    return native_handler(arguments)

第五步:仍然走同一条权限管道

这是非常关键的一点:

MCP 工具虽然来自外部,但不能绕开 permission。

不然你等于在系统边上开了个安全后门。

如果你想把这一层再收得更稳,最好再把结果也标准化回同一条总线:

{
    "source": "mcp",
    "server": "figma",
    "tool": "inspect",
    "status": "ok",
    "preview": "...",
}

这表示:

  • 路由前要过共享权限闸门
  • 路由后不论本地还是远程,结果都要转成主循环看得懂的统一格式

如何接到整个系统里

如果你读到这里还觉得 MCP 像“外挂”,通常是因为没有把它放回整条主回路里。

更完整的接法应该看成:

启动时
  ->
PluginLoader 找到 manifest
  ->
得到 server 配置
  ->
MCP client 连接 server
  ->
list_tools 并标准化名字
  ->
和 native tools 一起合并进同一个工具池

运行时
  ->
LLM 产出 tool_use
  ->
统一权限闸门
  ->
native route 或 mcp route
  ->
结果标准化
  ->
tool_result 回到同一个主循环

这段流程里最关键的不是“外部”两个字,而是:

进入方式不同,但进入后必须回到同一条控制面和执行面。

Plugin、MCP Server、MCP Tool 不要混成一层

这是初学者最容易在本章里打结的地方。

可以直接按下面三层记:

层级它是什么它负责什么
plugin manifest一份配置声明告诉系统要发现和启动哪些 server
MCP server一个外部进程 / 连接对象对外暴露一组能力
MCP toolserver 暴露的一项具体调用能力真正被模型点名调用

换成一句最短的话说:

  • plugin 负责“发现”
  • server 负责“连接”
  • tool 负责“调用”

只要这三层还分得清,MCP 这章的主体心智就不会乱。

这一章最关键的数据结构

1. server 配置

{
    "command": "npx",
    "args": ["-y", "..."],
    "env": {}
}

2. 标准化后的工具定义

{
    "name": "mcp__postgres__query",
    "description": "Run a SQL query",
    "input_schema": {...}
}

3. client 注册表

clients = {
    "postgres": mcp_client_instance
}

初学者最容易被带偏的地方

1. 一上来讲太多协议细节

这章最容易失控。

因为一旦开始讲完整协议生态,很快会出现:

  • transports
  • auth
  • resources
  • prompts
  • streaming
  • connection recovery

这些都存在,但不该挡住主线。

主线只有一句话:

外部工具也能像本地工具一样接进 agent。

2. 把 MCP 当成一套完全不同的工具系统

不是。

它最终仍然应该汇入你原来的工具体系:

  • 一样要注册
  • 一样要出现在工具池里
  • 一样要过权限
  • 一样要返回 tool_result

3. 忽略命名与路由

如果没有统一前缀和统一路由,系统会很快乱掉。

教学边界

这一章正文先停在 tools-first 是对的。

因为教学主线最需要先讲清的是:

  • 外部能力怎样被发现
  • 怎样被统一命名和路由
  • 怎样继续经过同一条权限与 tool_result 回流

只要这一层已经成立,读者就已经真正理解了:

MCP / plugin 不是外挂,而是接回同一控制面的外部能力入口。

transport、认证、resources、prompts、插件生命周期这些更大范围的内容,应该放到平台桥接资料里继续展开。

正文先停在 tools-first,平台层再看桥接文档

这一章的正文故意停在“外部工具如何接进 agent”这一层。
这是教学上的刻意取舍,不是缺失。

如果你准备继续补平台边界,再去看:

那篇会把 MCP 再往上补成一张平台地图,包括:

  • server 配置作用域
  • transport 类型
  • 连接状态:connected / pending / needs-auth / failed / disabled
  • tools 之外的 resources / prompts / elicitation
  • auth 该放在哪一层理解

这样安排的好处是:

  • 正文不失焦
  • 读者又不会误以为 MCP 只有一个 list_tools + call_tool

这一章和全仓库的关系

如果说前 18 章都在教你把系统内部搭起来,
s19 在教你:

如何把系统向外打开。

从这里开始,工具不再只来自你手写的 Python 文件,
还可以来自别的进程、别的系统、别的服务。

这就是为什么它适合作为最后一章。

学完这章后,你应该能回答

  • MCP 的核心到底是什么?
  • 为什么它应该放在整个学习路径的最后?
  • 为什么 MCP 工具也必须走同一条权限与路由逻辑?
  • plugin 和 MCP 分别解决什么问题?

一句话记住:MCP 的本质,不是协议名词堆砌,而是把外部工具安全、统一地接进你的 agent。