MCP 接入本地工具:把线上消息摊开看握手、tools/call、权限和错误分层
MCP 接入本地工具把线上消息摊开看握手、tools/call、权限和错误分层环境Windows 11、OpenJDK 11.0.32.1Temurin纯 JDK 单文件实验无第三方依赖说明本文在单 JVM 内模拟 MCP over stdio 的线上消息消息格式、方法名和错误分层与 MCP 规范一致真实部署请用官方 SDKJava 侧有官方io.modelcontextprotocolSDK。文中手写的极简 JSON 解析器仅为零依赖教学生产环境请用 Jackson。目录问题SDK 把协议藏起来了出错时不知道在看什么MCP 是什么不是什么实测一个完整会话的六步线上消息设计要点一权限必须在 server 侧强制执行设计要点二错误分两层别用混设计要点三inputSchema 是模型唯一的工具说明书这个教学模型和真实 MCP 的差距小结问题SDK 把协议藏起来了出错时不知道在看什么想给本地 Agent 接工具现在的标准答案是 MCPModel Context Protocol。但照着 SDK 文档起了一个 server 之后大多数人包括我对线上实际跑了什么都说不清楚——握手发了什么工具列表长什么样模型传了越权参数时错误是从哪一层返回的不知道这些排查模型调不动工具这类问题就只能在 SDK 的日志里碰运气。我的办法是绕开 SDK用纯 JDK 模拟一遍 MCP over stdio 的线上消息客户端和 server 在同一个 JVM 里用字符串收发 JSON-RPC每条消息原样打印。结论先说MCP 的线上协议比直觉简单得多JSON-RPC 2.0stdio 上每行一条消息核心方法就是initialize、tools/list、tools/call。权限控制必须在server 侧强制执行不能指望模型自觉也不能只靠 client 提示。错误分两层协议错误方法不存在走 JSON-RPC 的error字段工具执行失败含权限拒绝走result.contentisErrortrue。用混了模型就失去自我修正的机会。MCP 是什么不是什么一句话MCP 是 Anthropic 在 2024 年底开源的应用层协议解决Agent 应用client和工具/数据源server之间的标准化连接问题。它经常被拿来和 function calling 混淆区别很实际Function calling 是模型能力模型决定要调一个工具并生成结构化参数。它发生在模型和应用之间。MCP 是应用和工具之间的协议工具长什么样、怎么调用、错误怎么返回都标准化了。它发生在应用和工具进程之间。两者的关系是接力模型通过 function calling 告诉应用我要调read_file应用作为 MCP client 把这个调用翻译成tools/call消息发给 MCP serverserver 执行后返回结果应用再把结果喂回模型。本文聚焦的是后半段。传输方式上本地工具最常用stdioclient 把 server 作为子进程启动双方通过标准输入输出通信每行一条 JSON-RPC 消息。这也是我的实验模拟的形态。实测一个完整会话的六步线上消息实验里 server 暴露两个工具add(a,b)纯计算无副作用和read_file(path)读文件有权限问题。以下全部是本机实测输出。第 1 步握手。client 发initialize声明自己支持的协议版本和能力server 回应自己的版本和能力随后 client 发initialized通知握手完成client - {jsonrpc:2.0,id:1,method:initialize,params:{protocolVersion:2025-06-18,capabilities:{},clientInfo:{name:mini-client,version:0.1}}} server - {jsonrpc:2.0,id:1,result:{protocolVersion:2025-06-18,capabilities:{tools:{}},serverInfo:{name:mini-mcp-server,version:0.1.0}}} client - {jsonrpc:2.0,method:notifications/initialized} server - (通知无响应)注意三点protocolVersion是双方协商的server 可以回应一个不同的版本让 client 降级capabilities声明 server 提供哪类能力tools、resources、promptsclient 后面只能用它声明过的notifications/initialized是通知——JSON-RPC 里没有id的消息就是通知server 不回应。真实 stdio 部署里server 如果对通知回了消息一些严格的 client 会直接断连。第 2 步发现工具。tools/list返回每个工具的名字、描述和inputSchemaJSON Schemaclient - {jsonrpc:2.0,id:2,method:tools/list,params:{}} server - {jsonrpc:2.0,id:2,result:{tools:[{name:add,description:计算两个整数的和,inputSchema:{type:object,properties:{a:{type:integer},b:{type:integer}},required:[a,b]}},{name:read_file,description:读取白名单目录内的文本文件,inputSchema:{type:object,properties:{path:{type:string}},required:[path]}}]}}这份列表之后会被应用翻译成 function calling 的工具定义喂给模型——description和inputSchema是模型能看到的唯一工具说明书写得多清楚模型就调得多准。第 3 步正常调用。tools/call的params里是工具名和arguments对象client - {jsonrpc:2.0,id:3,method:tools/call,params:{name:add,arguments:{a:3,b:4}}} server - {jsonrpc:2.0,id:3,result:{content:[{type:text,text:7}],isError:false}}返回的content是一个数组元素可以是 text、image 等资源类型——一个工具一次可以返回多段内容这个设计和消息结构对齐方便多模态工具。第 4 步读白名单内的文件正常client - {jsonrpc:2.0,id:4,method:tools/call,params:{name:read_file,arguments:{path:demo-data/notes.txt}}} server - {jsonrpc:2.0,id:4,result:{content:[{type:text,text:MCP 学习笔记先跑通握手再谈工具。}],isError:false}}第 5 步模型试图读白名单外的文件被 server 拒绝client - {jsonrpc:2.0,id:5,method:tools/call,params:{name:read_file,arguments:{path:C:/Windows/System32/drivers/etc/hosts}}} server - {jsonrpc:2.0,id:5,result:{content:[{type:text,text:权限拒绝read_file 只允许读取 demo-data/ 内的文件收到 C:/Windows/System32/drivers/etc/hosts}],isError:true}}第 6 步client 调用了 server 没声明的方法协议层报错client - {jsonrpc:2.0,id:6,method:resources/list,params:{}} server - {jsonrpc:2.0,id:6,error:{code:-32601,message:Method not found: resources/list}}第 5 步和第 6 步的失败走的是完全不同的通道这就是下一节的重点。设计要点一权限必须在 server 侧强制执行read_file的权限检查实现只有两行但位置是刻意选的——在server 的工具执行体里caseread_file:{StringpathString.valueOf(args.get(path));if(path.contains(..)||!path.startsWith(FILE_WHITELIST)){thrownewSecurityException(权限拒绝read_file 只允许读取 FILE_WHITELIST 内的文件收到 path);}returnnewString(Files.readAllBytes(Paths.get(path)),UTF-8);}为什么不能只靠 client 或模型因为威胁模型很明确工具的参数是模型生成的而模型的行为不可预测——提示注入、上下文误导、单纯的幻觉都可能让它生成越权参数。把防线放在 server 侧意味着不管上游是谁、被怎么操纵越权请求都在执行前被拦下。检查项至少包括路径穿越..、白名单前缀、符号链接生产环境还要用toRealPath()解析后再比前缀防止软链绕过。对写操作发消息、改文件、执行命令还要再加一层要求人工确认。MCP 生态里常见的做法是由 client 弹确认框但 server 侧应该提供这个工具有副作用的标注MCP 的 tool annotations如destructiveHint而不是默默执行。设计要点二错误分两层别用混实测里第 5 步和第 6 步的对比值得停下来看清楚协议层错误方法不存在、消息格式非法→ JSON-RPC 的error字段code 遵循 JSON-RPC 规范-32601 Method not found、-32602 Invalid params。这层错误的含义是你的调用本身就不合法通常不该喂给模型因为模型改不了协议。工具执行错误权限拒绝、文件不存在、业务校验失败→ HTTP 意义上成功的响应result.content里放错误描述isErrortrue。这层错误应该喂回模型——错误信息写得清楚模型下一轮就能修正参数重试。这和上一篇 Function Calling 参数校验的错误信息喂回模型是同构的只是 MCP 把它在协议层面固定下来了isErrortrue的 result 就是给模型看的。如果你把权限拒绝也做成协议层errorclient 侧的 Agent 循环很可能直接中断丢掉自我修正的机会。设计要点三inputSchema 是模型唯一的工具说明书第 2 步返回的inputSchema决定了模型能调出什么样的参数。三个经验description 写给模型看不是写给人看。读取白名单目录内的文本文件这句描述里白名单目录内是故意写给模型的——它提前告诉模型边界在哪减少第 5 步那种越权尝试。schema 里能表达的约束都表达required、enum、minimum/maximum。表达不了的路径白名单才留给运行时校验。**工具宁可拆小不要合并。**一个file(path, op)同时支持读写删的工具权限检查会复杂到容易出错拆成read_file/write_file白名单策略可以分别收紧。这个教学模型和真实 MCP 的差距为了让协议可见这个实验砍掉了不少东西真实接入时要补回来真实 stdio 是独立子进程client 用ProcessBuilder启动 server 进程逐行读写 stdin/stdout。我的单 JVM 字符串传递省掉了进程管理但消息格式完全一样。能力不止 toolsMCP 还有 resources数据订阅和 prompts提示模板两类能力实验里的第 6 步resources/list报 -32601正是因为这个 server 只声明了 tools。远程 server 用 HTTPstdio 适合本地工具远程 server 走 Streamable HTTP 传输多了鉴权OAuth这一整层。解析用成熟库我的手写 JSON 解析器只支持本实验的子集真实项目用官方 SDK它同时处理了批请求、取消通知、进度通知等我全部跳过的边缘情况。看清骨架的价值依然在当你的 SDK 报connection closed时知道线上本来应该跑什么消息排查就有方向——先抓子进程的 stdin/stdout对照本文的六步看停在哪一步。小结MCP over stdio 的线上协议就是 JSON-RPC 2.0 逐行消息核心流程六步initialize、initialized 通知、tools/list、tools/call。权限在 server 侧强制执行路径穿越、白名单、真实路径解析写操作再加人工确认。错误分两层协议错误走error字段工具执行错误走resultisErrortrue后者是给模型自我修正用的别用混。description和inputSchema是模型唯一的工具说明书值得像写 API 文档一样认真写。

相关新闻

巴法禄全空气系统10问深度解析:送风、过滤、除湿与运行表现

巴法禄全空气系统10问深度解析:送风、过滤、除湿与运行表现

全空气系统通过风管将经过处理的空气送入不同房间,能够把温度调节、空气输送、过滤和部分湿度控制集中到一套系统中。巴法禄水牛变频全空气室内机采用多点送风、高效过滤、直流无刷EC风机等设计,并可配置光氢离子杀菌模块、负离子发生器及再热盘管等功能…

2026/10/15 4:10:47 阅读更多 →
S 空空空空空

S 空空空空空

S 空空空空空

2026/10/15 4:09:46 阅读更多 →
【AIGC实战】Python+SDXL实战:用ControlNet批量生成“英歌舞青苹果”IP,附自动化脚本与商用思路

【AIGC实战】Python+SDXL实战:用ControlNet批量生成“英歌舞青苹果”IP,附自动化脚本与商用思路

大家好,我是小江。这是我的“潮汕国潮甜品IP”系列的最新尝试——《英歌舞青苹果》。很多朋友问我:“小江,你生成的图这么精致,如果我要给一家水果店做全套包装,怎么才能保证风格统一?难道一张张抽卡吗&…

2026/10/15 4:09:46 阅读更多 →

最新新闻

静态路由实现全网可达:从路由表原理到配置与排错

静态路由实现全网可达:从路由表原理到配置与排错

做网络项目最烦的是什么?设备连好线、接口全亮,结果PC之间互相ping不通,而且怎么查都看不出问题。干这行久了你就明白,八成是路由表没配周全——数据包走到中间某台路由器,转发表里没有目标网段,报文直接被…

2026/10/15 4:58:06 阅读更多 →
AI检测原理与合规降AI率:继续教育论文写作实战指南

AI检测原理与合规降AI率:继续教育论文写作实战指南

那篇论文连我自己看完都愣了:排版干净,结构完整,引用规范,A同学写的是继续教育本科的毕业设计说明,前后只用了一个下午。学校系统给出的AI疑似度是78%,导师发来消息:“内容是你自己写的吗&#…

2026/10/15 4:58:06 阅读更多 →
Apollo-11制导计算机源码解析:从绳存储器到任务调度的工程实践

Apollo-11制导计算机源码解析:从绳存储器到任务调度的工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 4:58:06 阅读更多 →
Binder机制核心解析:从mmap一次拷贝到AIDL跨进程通信

Binder机制核心解析:从mmap一次拷贝到AIDL跨进程通信

Binder这套东西,搞Android的人早晚都得啃。很多人刚开始接触它的时候,看到的都是“进程间通信”“内核驱动”“mmap”这种抽象名词,一头扎进去就被C、C、Java三层代码绕晕了。但你要是真的花点时间把它的设计思路捋清楚,再回头去看…

2026/10/15 4:58:06 阅读更多 →
金融行业证书有哪些?按岗位方向分类梳理

金融行业证书有哪些?按岗位方向分类梳理

金融行业的证书数量多、名称混杂,初次接触时容易把从业资格、水平评价、培训证书混在一起。一个比较清晰的入手方式是先看制度属性:法定准入类、水平评价类、能力提升类。三类证书对应的岗位方向、报考条件和用途并不相同,先分清属性&#xf…

2026/10/15 4:58:06 阅读更多 →
PLC交通灯状态机设计:告别延时链,构建可靠时序逻辑

PLC交通灯状态机设计:告别延时链,构建可靠时序逻辑

简介:本资源是一份面向电气工程及其自动化专业本科生的PLC实践教学材料,聚焦S7-1200可编程控制器在八段LED显示与智能交通灯控制两大典型场景中的综合应用,解决初学者对TIA Portal V13软件操作、梯形图编程、HMI人机交互及仿真验证等核心技能…

2026/10/15 4:57:06 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →