当前位置: 首页 > news >正文

S19|MCP 与插件:多 Agent 平台 —— 外部能力总线,让外部工具安全接入

在前十八章,我们的 Agent 已经拥有完整的内部能力体系:循环、工具、计划、子代理、技能、压缩、权限、Hook、记忆、提示词流水线、错误恢复、任务系统、后台任务、定时调度、多 Agent 团队、团队协议、自主代理、Worktree 隔离,所有工具都写在本地代码里。

但真实系统走到一定阶段,会遇到一个自然的需求:能不能让外部程序也把工具接进来,而不用每次都改主程序?

这一章 S19,我们给 Agent 加上MCP 与插件系统:让外部工具通过统一协议安全接入,和本地工具处在同一控制面,实现 “外部能力总线”,让工具不再局限于本地硬编码。


本章核心信息

  • 核心闭环:插件配置发现 → MCP Server 启动 → 工具标准化注册 → 统一路由分发 → 权限检查 → 结果回流主循环
  • 工具数量:4 个
  • 核心思想:外部能力系统不该是外挂;它们应和原生工具一起处在同一控制面上

先看懂本章所有名词

  1. MCP(Model Context Protocol)
    一套让 Agent 和外部工具程序对话的统一协议,定义了如何发现工具、调用工具、接收结果的标准方式。

  2. MCP Server
    提供外部工具能力的独立进程,通过 MCP 协议暴露工具列表和调用接口,Agent 通过连接 Server 使用这些工具。

  3. 插件(Plugin)
    负责外部工具配置的声明文件,告诉主程序如何发现、启动和连接 MCP Server,包含插件名、版本、Server 配置等信息。

  4. 工具前缀规则
    区分本地工具和外部 MCP 工具的命名约定,格式为mcp__{server}__{tool},避免命名冲突,一眼就能识别工具来源。

  5. 统一路由器
    负责分发工具调用请求的核心组件,判断是本地工具还是 MCP 工具,分别交给对应的处理器处理。

  6. 外部能力总线
    所有外部工具通过 MCP 接入后,和本地工具共享同一套权限检查、结果处理、主循环回流逻辑,形成统一的能力接入体系。


这一章到底要解决什么问题?

到 S18,Agent 的所有工具都写在本地代码里,存在明显的局限性:

  • 新增工具必须修改主程序,扩展性差
  • 外部程序无法直接提供能力,只能通过硬编码集成
  • 工具来源单一,无法复用成熟的第三方服务能力
  • 无法统一管理本地和外部工具的权限、调用和结果

本章要解决的核心问题:把工具来源从 “本地硬编码” 升级为 “外部可插拔”,让外部工具通过统一协议安全接入,和本地工具共享同一控制面,实现系统的可扩展能力。


最小心智模型:外部工具接入的三层结构

LLM | | 发起工具调用请求 v Agent 工具路由器 | +-- 本地工具 → 交给本地 Python 处理器执行 | +-- MCP 工具 → 交给 MCP Client 转发给外部 Server | v MCP Server 执行工具并返回结果

一句话:MCP 不是独立的外挂系统,而是外部工具接入 Agent 的统一协议,最终和本地工具汇入同一套执行逻辑。


关键数据结构(本章灵魂)

1. 插件配置文件(plugin.json)

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

它本质上是一份配置声明,告诉主程序如何发现和启动 MCP Server。

2. MCP Server 配置

server_config = { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-postgres"], "env": {} }

定义了启动外部 Server 的命令、参数和环境变量。

3. 标准化后的工具定义

{ "name": "mcp__postgres__query", "description": "Run a SQL query on PostgreSQL", "input_schema": { "type": "object", "properties": { "query": {"type": "string"} } } }

把 MCP Server 暴露的工具转成 Agent 能看懂的统一格式,加上mcp__前缀区分来源。

4. MCP Client 注册表

clients = { "postgres": mcp_client_instance }

记录已连接的 MCP Client 实例,方便路由器快速查找和转发请求。


最小实现代码(极简可运行)

第一步:实现一个基础的 MCPClient

class MCPClient: def __init__(self, server_config): self.config = server_config self.process = None self.tools = [] def connect(self): # 启动外部Server进程 self.process = subprocess.Popen( [self.config["command"]] + self.config["args"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) # 建立连接并获取工具列表 self.tools = self.list_tools() def list_tools(self): # 向Server请求工具列表 # 教学版简化,实际按MCP协议通信 return [{"name": "query", "description": "Run SQL query"}] def call_tool(self, tool_name, arguments): # 转发工具调用请求给Server # 教学版简化,实际按MCP协议通信 return {"status": "ok", "preview": "Query executed successfully"}

核心能力:连接 Server、获取工具列表、转发调用请求。

第二步:把外部工具标准化为 Agent 工具格式

def normalize_mcp_tools(server_name, raw_tools): normalized = [] for tool in raw_tools: # 加上mcp__前缀,格式:mcp__{server}__{tool} prefixed_name = f"mcp__{server_name}__{tool['name']}" normalized.append({ "name": prefixed_name, "description": tool["description"], "input_schema": tool.get("input_schema", {}) }) return normalized

关键:通过前缀规则区分本地和外部工具,避免命名冲突。

第三步:实现统一工具路由器

class ToolRouter: def __init__(self, native_tools, mcp_clients): self.native_tools = native_tools self.mcp_clients = mcp_clients # key: server_name, value: MCPClient def route(self, tool_name, arguments): # 判断是否为MCP工具 if tool_name.startswith("mcp__"): # 解析server名和工具名:mcp__postgres__query parts = tool_name.split("__", 2) server_name = parts[1] tool_name = parts[2] # 转发给对应的MCP Client client = self.mcp_clients[server_name] return client.call_tool(tool_name, arguments) else: # 本地工具,交给本地处理器 return self.native_tools[tool_name](arguments)

路由器只做一件事:根据工具名分发请求,不区分工具来源。

第四步:MCP 工具必须经过同一条权限管道

def check_permission(tool_name, arguments, mode): # 权限检查逻辑和本地工具完全一致 # 即使是MCP工具,也不能绕开权限闸门 if tool_name.startswith("mcp__"): # 提取server和工具信息,进行权限检查 if is_dangerous_mcp_tool(tool_name): return "deny", "Dangerous MCP tool call blocked" # 本地工具权限检查 return native_permission_check(tool_name, arguments, mode)

关键:外部工具也必须经过统一的权限检查,不能成为安全后门。

第五步:结果标准化回流主循环

def normalize_tool_result(tool_name, raw_result): if tool_name.startswith("mcp__"): parts = tool_name.split("__", 2) server_name = parts[1] return { "source": "mcp", "server": server_name, "tool": parts[2], "status": raw_result.get("status", "ok"), "preview": raw_result.get("preview", "") } else: # 本地工具结果格式 return { "source": "native", "tool": tool_name, "status": raw_result.get("status", "ok"), "preview": raw_result.get("preview", "") }

无论本地还是外部工具,结果都要转成主循环能统一处理的格式。


插件、MCP Server、MCP Tool 三层关系

初学者很容易把这三个概念混在一起,这里用表格帮你理清边界:

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

一句话总结:Plugin 负责 “发现”,Server 负责 “连接”,Tool 负责 “调用”。


如何接到前面章节的系统里

MCP 不是孤立的外挂,而是接入 Agent 已有体系的扩展层,完整链路如下:

启动时

PluginLoader 读取插件配置 -> 解析并获取MCP Server配置 -> 启动Server并建立连接 -> 获取Server的工具列表 -> 标准化工具名并合并进主程序工具池

运行时

LLM 生成工具调用请求 -> 统一权限闸门检查(和本地工具完全一致) -> 工具路由器分发请求(本地/MCP) -> 执行工具并返回结果 -> 结果标准化后回流主循环

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


初学者最容易被带偏的 3 个坑

  1. 一上来就讲太多协议细节不要一开始就陷入 transports、auth、resources 等复杂概念,主线只有一句话:外部工具也能像本地工具一样接进 Agent。

  2. 把 MCP 当成一套完全不同的工具系统它最终仍然汇入你原来的工具体系:一样要注册、一样要过权限、一样要返回 tool_result,不是独立的外挂。

  3. 忽略命名与路由规则没有统一前缀和路由,本地和外部工具会混在一起,系统很快就会混乱,无法区分工具来源。


S18 → S19 升级了什么?

模块S18S19
工具来源本地硬编码工具本地工具 + 外部可插拔 MCP 工具
扩展性新增工具需修改主程序外部工具通过插件配置接入,无需修改主程序
能力边界仅依赖开发者手写的工具可复用第三方成熟服务能力(如数据库、浏览器等)
控制面统一权限、路由、结果处理本地和外部工具共享同一控制面,无安全后门
架构地位多 Agent 并行隔离执行层系统外部能力扩展层

本章教学边界

本章先停在 “tools-first” 的主线,不展开协议细节:

  • 不深入讲 transports、认证、连接恢复等复杂协议内容
  • 不展开 resources、prompts 等 MCP 扩展能力
  • 只讲清外部工具如何被发现、命名、路由、过权限、回流主循环

这些扩展内容可以放到后续平台桥接文档中展开,正文先聚焦主线,避免读者失焦。


一句话总结本章

MCP 的本质不是协议名词堆砌,而是把外部工具安全、统一地接进你的 Agent。它让工具不再局限于本地硬编码,通过插件和 MCP 协议,让外部能力成为系统的可扩展总线,和本地工具共享同一控制面,实现真正的可扩展 Agent 平台。

http://www.jsqmd.com/news/823532/

相关文章:

  • 北京就医挂号攻略|外地患者必看,官方渠道+抢号技巧,告别号贩子 - 品牌排行榜单
  • 别再手动导数据了!用Python的pandas+pyarrow,3行代码搞定Parquet转JSON
  • RK3588平台IMX415摄像头驱动调试全流程与实战指南
  • Boss-Key:Windows下一键隐藏窗口的终极隐私保护工具
  • 3个MuJoCo物理仿真优化技巧:从卡顿到流畅的完整指南
  • 嘎嘎降AI和笔灵AI哪个更适合毕业论文:2026年达标率改写质量售后完整测评对比报告
  • 从零到一:基于Cadence的带隙基准电压源设计实战与仿真优化
  • 3分钟掌握无人机日志分析:免费在线工具让飞行数据一目了然
  • 远程办公总掉线?四大远控软件横测:谁才是“不断连之王”?
  • GaussDB定时任务管理:从基础到高级实践
  • 工程定制钢制甲级防火窗 资质齐全可验收
  • 突破性创新:Midscene.js如何用AI视觉驱动重塑跨平台自动化测试
  • 双语适配降AI工具怎么选?2026高靠谱推荐榜 全人群通用
  • Python量化交易框架解析:从数据到实盘的完整实现
  • Cursor Pro解锁技术揭秘:从限制到自由的智能破解之道
  • 如何快速部署开源捉妖雷达Web版:面向新手的完整实时妖怪追踪指南
  • 别再死记硬背了!Vivado伪双口RAM的wea、ena信号到底怎么用?一个实例讲透
  • 【气象AI辅助研究新范式】:为什么92%的国家级气象台站已在内测NotebookLM科研插件?
  • 企业级矩阵系统接口安全防护与全链路风控技术实践
  • 英雄联盟本地自动化工具完整指南:10分钟精通LeagueAkari终极教程
  • 《100 篇原创里程碑:从 LV0 到 LV4,从 0 粉到天津第 1,我做了什么》
  • 高考语文阅读理解得分率仅68.3%?DeepSeek GAOKAO测试暴露大模型语义鸿沟真相,一线教研员紧急预警!
  • 6.5A/2300V隔离栅极驱动器评估板:释放SiC MOSFET性能潜力的关键
  • Altium Designer新手避坑 10 条(1)
  • oracle 大表(1亿以上)迁移笔记一
  • 基于BMapGL与MapVGL,实战城市人流热力图可视化
  • 易服客工作室:ChatGPT排名优化指南:六大关键因素提升AI推荐可见性
  • P6210 「SWTR-4」Easy Math Problems 莫比乌斯反演(不完整.没推完)
  • 如何在10分钟内搭建AI与Figma双向通信系统:TalkToFigma MCP完整指南
  • 植物光合作用测定仪怎么样?农业科研人员关心的实测精度与选型指南 - 品牌推荐大师1