本地工具中心和 MCP Server 有什么区别?什么时候值得拆成独立的 MCP 服务?
简化版
本地工具中心是应用进程内的一张工具注册表:工具的名称、说明、参数和启用状态存在数据库里,运行时读出来交给模型,模型要调用时在同一个进程里按工具编码分发到本地方法执行。MCP Server 是一个独立的服务,按 MCP 协议对外暴露工具:客户端先初始化会话,用 tools/list 发现有哪些工具,用 tools/call 调用,通信走 JSON-RPC,传输用 stdio 或 HTTP。两者在「模型能看到哪些工具、怎么调用、能不能开关、有没有留痕」上效果可以等价,区别在于 MCP 多了一层跨进程、跨应用的标准协议。什么时候值得拆:工具要被多个 Agent 应用共用、要独立发版、要用别的语言实现、或者要开放给第三方 MCP 客户端时;如果工具只服务一个应用、读的都是本库的表,留在进程内更简单,调试、事务和日志都在一处。
详细版
| 维度 | 本地工具中心 | MCP Server |
|---|---|---|
| 部署 | 和应用同一个进程 | 独立进程或独立服务 |
| 工具发现 | 查本地注册表 | 客户端调用 tools/list |
| 工具调用 | 进程内按编码分发到本地方法 | 客户端发送 tools/call,服务端执行 |
| 协议 | 无(应用内部约定) | JSON-RPC 2.0 + MCP 生命周期与能力协商 |
| 复用 | 只服务本应用 | 任何兼容 MCP 的客户端都能接入 |
| 语言 | 必须和应用同一技术栈 | 服务端可以用任何语言实现 |
| 故障面 | 本地异常 | 多了跨进程通信本身的失败 |
| 调试 | 一个进程、一个控制台 | 跨进程排查,需要关联两边日志 |
判断要不要拆,问四个问题:会不会有第二个应用要用这些工具?工具要不要独立于应用发版?工具是不是更适合用另一种语言写?要不要让外部的 MCP 客户端也能用?四个都是否,就留在进程内。
完整版教学
一、两者要解决的是同一件事
不管是本地工具中心还是 MCP Server,要解决的都是:让模型知道有哪些工具、怎么调,并且能被管理。一个成熟的本地工具中心通常具备:
工具注册:编码、说明、参数说明、启用状态存在表里,后台可增删改
工具池构建:每次执行按「启用」现查,停用即从模型面前消失
统一执行:按编码分发到本地方法,执行前再校验一次启用状态
调用留痕:每次调用写一条日志,记录入参、返回、成败和耗时
MCP Server 对外提供的核心能力其实就是前三条的协议化版本:注册表对应服务端声明的工具列表,工具池构建对应客户端调用 tools/list,统一执行对应 tools/call。所以很多项目把自己的工具注册表叫作「MCP 工具」,这是沿用了 MCP 生态的叫法,并不代表实现了 MCP 协议。本地工具中心怎么做到真开关,见「工具为什么要做成数据库驱动的工具中心?停用一个工具怎么保证模型真的调不到?」。
二、MCP 多出来的是什么
MCP 在本地工具中心之上多了一层标准协议,带来几样本地做不到的东西:
| 多出来的能力 | 含义 |
|---|---|
| 跨应用复用 | 同一个 Server 可以被多个 Host 接入,工具只实现一次 |
| 语言无关 | Server 可以用 Python、TypeScript、Java 等任意语言实现,客户端不关心 |
| 进程隔离 | Server 崩溃不会拖垮主应用;可以单独限制它的权限和资源 |
| 标准发现 | 客户端不需要提前知道有哪些工具,初始化后调用 tools/list 即可 |
| 生态接入 | 可以直接接入别人写好的 MCP Server,也能被 IDE、桌面客户端等使用 |
这些能力都来自「跨进程 + 标准协议」。反过来,只要工具只在一个应用里用,这些能力大多用不上。MCP 和模型侧 Function Calling 的分工见「MCP 和 Function Calling 是什么关系?有了 Function Calling 为什么还要 MCP?」。
记忆钩子:本地工具中心是「家里的工具箱」,MCP Server 是「对外营业的工具租赁点」。只自己用,没必要开店。
三、拆出去的代价
跨进程和标准协议也有成本:
调用延迟: 本地方法调用 → 一次 JSON-RPC 往返(本机 stdio 或网络 HTTP)
故障类型: 只有业务异常 → 还要处理跨进程通信本身出的问题
部署运维: 一个服务 → 多一个要部署、监控、升级的服务
认证授权: 进程内天然可信 → 远程 Server 要认证,要管令牌和权限
数据归属: 工具直接读本库的表 → 要决定哪些数据跟着工具走、哪些留在主应用
事务边界: 工具、日志、业务数据可以在同一事务里 → 跨服务后只能各自提交
用一个示意数字感受延迟:一次 Agent 运行调 20 次工具,如果每次远程调用比本地多 30 毫秒,整次运行就多出约 0.6 秒。对一次要跑十几秒的 Agent 不算大,但对要求毫秒级响应的场景就要掂量。
四、什么时候值得拆
| 情况 | 建议 |
|---|---|
| 工具只服务一个应用,读的都是本库的表 | 留在进程内 |
| 多个 Agent 应用要用同一批工具 | 拆成 MCP Server,各应用用客户端接入 |
| 工具需要独立发版、独立扩容 | 拆 |
| 工具更适合用另一种语言实现(如数据科学库在 Python 里) | 拆 |
| 要让 IDE、桌面客户端或第三方直接使用这些工具 | 拆 |
| 工具读写主应用的核心业务表 | 慎拆,先想清楚数据归属 |
拆分也可以只拆一部分:读外部数据、可以独立部署的工具先拆出去,读主应用业务表的工具留在进程内。
五、留在进程内时,怎么为以后拆分留余地
即使现在不拆,也可以让本地工具中心的接口形状贴近 MCP,以后拆起来改动小:
工具定义用「名称 + 说明 + JSON Schema 参数」描述 ← 和 MCP 工具定义同构
提供「列出启用工具」和「按名称 + 参数调用」两个入口 ← 对应 tools/list 与 tools/call
执行结果统一成「文本内容 + 是否出错」 ← 对应调用结果的内容与错误标记
编排层只依赖「工具列表 + 调用入口」这个抽象 ← 换成远程客户端时编排不用改
这样一来,将来把某个工具换成远程 MCP Server,只是把「列出」和「调用」这两个入口的实现从本地查表、本地分发换成客户端请求,编排层和模型看到的工具定义都不变。
六、数据归属:哪些工具适合先拆
拆分最难的往往不是协议,而是「工具读的数据归谁」。按工具读写的数据,大致可以分成三类:
| 工具读写的数据 | 例子 | 拆分难度 |
|---|---|---|
| 外部数据或公共知识 | 天气、汇率、公开文档检索 | 低:工具和数据都可以整体搬走 |
| 可以独立出去的领域数据 | 技能标签库、岗位样本库、知识库 | 中:数据表跟着工具一起划到新服务 |
| 主应用的核心业务数据 | 用户画像、订单、当前任务 | 高:要么工具留在主应用,要么新服务要能访问主库 |
第三类最麻烦:如果把读用户画像的工具搬到独立服务,这个服务就要能访问主应用的用户表,等于把核心数据的访问权扩散出去;如果不想让它碰这些表,就只能把这类工具留在主应用。所以常见的拆法是先拆第一、二类,第三类留在进程内,一个 Agent 同时使用本地工具和远程 MCP 工具,对模型来说它们都只是工具定义,没有区别。
用一个示意数字看拆分范围:一个 Agent 有 5 个工具,其中 2 个读核心业务表、3 个读可独立的领域数据,按这个原则只拆 3 个,60% 的工具获得独立发版和复用能力,核心数据的访问边界不变。
七、常见误区与追问
- 误区:表名叫 mcp_tool 就是实现了 MCP。 MCP 是跨进程的标准协议;进程内的注册表和分发只是沿用了叫法。
- 误区:上了 MCP 工具就更安全。 跨进程带来隔离,但也带来认证、授权和不可信返回值的新问题。
- 误区:所有工具都应该拆成 MCP Server。 只服务一个应用的工具拆出去只增加延迟、故障面和运维成本。
- 误区:拆分只是换个调用方式。 哪些数据跟着工具走、哪些操作还能放在同一个事务里,都要重新划分。
- 误区:不拆就意味着以后拆很难。 让本地接口形状贴近「列出 + 调用」,以后拆分时编排层可以不动。
- 追问:本地的工具定义能直接当 MCP 工具定义用吗? 结构基本一致(名称、说明、JSON Schema 参数),但参数类型要显式声明;按字段名猜类型、说明写得含糊的地方,拆分前都要补齐。
- 追问:拆分后工具的调用日志写在哪边? 运行记录和步骤一般留在发起调用的主应用,Server 侧可以另有自己的访问日志,两边用请求标识关联。
八、加强记忆
本地工具中心和 MCP Server 记「同一件事、多一层协议」:两者都要让模型知道有哪些工具、怎么调,并能开关和留痕;MCP 把注册表、工具池、统一执行协议化成 tools/list 与 tools/call,多出跨应用复用、语言无关、进程隔离和标准发现。代价是调用延迟、更多故障类型、多一个服务要运维、要做认证、要重新划分数据归属和事务边界。多个应用共用、独立发版、换语言实现、开放给第三方时才值得拆;只服务一个应用就留在进程内,但接口形状贴近「列出 + 调用」,以后拆起来编排层不用改。
项目实战落地
项目里怎么做的
《AI Agent岗位匹配与求职规划系统》做的是进程内的「本地 MCP 工具中心」,教程开头就写明它不是独立进程服务:
- 工具注册:
mcp_tool表存工具编码、名称、分类、说明、入参说明、启用状态和排序,管理端维护; - 交给模型:
McpToolCallbackFactory.buildEnabledCallbacks查出启用的工具,每一条包装成一个 Spring AIToolCallback,工具名用tool_code,说明和入参说明进入工具定义;ReAct Agent 把这组回调交给ChatClient; - 执行:模型调用某个工具时,回调进入
McpToolExecutorService.execute,按toolCode在同一个 Spring Boot 进程里分发到具体的查询方法,写调用日志和步骤记录; - 五个工具:读用户画像、读岗位 JD、查技能标签、查岗位样本、检索求职知识库,读的都是同一个库里的表。
《AI Agent 智慧医院智能导诊就诊系统》在教程里把边界讲得很直白:项目不启动任何独立进程、不走 JSON-RPC、没有 Server 端;表名里带 mcp 只是沿用 MCP 生态里「工具注册表」的叫法;本地工具中心拿到的后台加工具、按池过滤、停用即失效、调用留痕这些能力,和 MCP Server 架构在效果上等价,只是少了进程通信这一层。
为什么这样取舍
- 求职项目没有拆:五个工具读的都是同一个库里的表,没有跨系统复用需求,也不需要让别的 Agent 应用接入这些工具;留在同一个进程里,步骤记录、调用日志和业务数据写在同一个库里,调试和排错都在一个后端控制台里完成。
- 什么时候才拆:工具要被多个 Agent 应用共用、需要独立发版、要用别的语言实现、或需要把工具能力开放给第三方 MCP 客户端时,拆分的价值才出现。
面试官还会追问
- 如果要把求职项目的工具中心拆成独立 MCP 服务,主应用这边哪几处要改?
mcp_tool表还要不要留,留着做什么? - 拆分之后,工具调用失败要区分哪几种情况?为什么现在不用区分?
- 拆分之后,步骤记录里的耗时还能和拆分前的历史数据直接比较吗?
学完《AI Agent岗位匹配与求职规划系统》,上面这些追问你都会迎刃而解。