杠精派
派聪明
0/512

热门评论

xcx0103 2026年06月09日 23:06
引用原文:MCP 的 resources 是什么,和 tools 有什么区别
@派聪明 详细讲一下
点赞
回复1 取消回复
派聪明 2026年06月09日 23:06
MCP中的 Resources 和 Tools 是两个核心概念,简单来说:**Tools 是“用来干活的”,而 Resources 是“用来读取数据的”**。 你可以把它们类比为开发中的接口:Tools 相当于 `POST`端点,它接收输入参数,并且**会改变系统状态**(例如执行点击按钮、修改文件等操作);Resources 相当于 `GET`端点,它通过 URI 进行访问,只返回内容,**只读不写**。 虽然概念明确,但在实际应用中有一个关键痛点:**当前的 LLM(大语言模型)并不能直接调用 `resources/read`**。因为现有的 Function Calling协议里只有“工具”的概念,并没有“资源”。 为了解决这个限制,PaiCLI采用了两种巧妙的处理方式来实现数据访问: 1. **将 Resources 包装成 Tools**: 系统会为每个支持 Resources 的 MCP Server 自动注册两个虚拟工具——`list_resources` 和 `read_resource`。这样一来,LLM 就可以像调用普通工具一样去调用它们。LLM 先查有哪些资源,再按 URI读取具体内容。这种方式非常适合 LLM 需要**主动探索数据**的场景。 2. **支持用户通过 `@`符号直接指定**: 用户可以在输入框里直接写 `@server:protocol://path`。PaiCLI 在把请求提交给 Agent之前,会自动把该资源的内容展开并塞进提示词里,整个过程完全不需要 LLM去决策。这种方式适用于**用户已经明确知道要读取什么资源**的场景。
点赞
回复 取消回复

10 条评论

world 2026年07月03日 11:29
引用原文:通知的 handler 为什么要异步执行 如果通知处理逻辑直接跑在消息读取线程里,处理逻辑内部要是发了一个 JSON-RPC 请求并等响应,就会死锁。 因为读取线程被占着,新的响应进了缓冲区但没人读,等待的响应永远读不到。典型场景就是 Server 推送 tools/list_changed,处理逻辑要调 tools/list 重新拉工具列表,结果自己等自己,死锁了。 所以 PaiCLI 用一个独立的单线程做异步派发,通知处理和消息读取完全隔离,彻底避免了这个问题。
@派聪明 为什么单线程会死锁?
点赞
回复1 取消回复
派聪明 2026年07月03日 11:29
你引用的这段文本里,**死锁的根源不是"单线程",而是"在同一个线程里既负责读消息又负责处理消息"**。 我给你拆解一下死锁的完整链条: --- ### 死锁发生的过程 假设消息读取线程叫 `Reader-Thread`: 1. **Reader-Thread** 从网络缓冲区读取到一条 `tools/list_changed` 通知 2. **Reader-Thread** 直接在原地调用通知处理逻辑 3. 处理逻辑需要发 `tools/list` 请求,并**同步等待**响应(阻塞等待) 4. 服务器收到请求,返回响应数据,数据到达**网络接收缓冲区** 5. ❗ **谁来读这个响应?** 只有 Reader-Thread 能读,但 Reader-Thread 正卡在第3步等响应,根本没去读缓冲区 6. 响应数据躺在缓冲区里,Reader-Thread 永远等不到它——**死锁** ``` Reader-Thread 被占住 → 没人读网络缓冲区 → 响应永远到不了 → Reader-Thread 永远等不到 → 死锁 ``` --- ### 为什么"独立的单线程"能解决 这里的"独立的单线程"指的是**另起一个专门的线程**来处理通知,和消息读取线程**分开**: ``` 消息读取线程(Reader-Thread): 读取消息 → 识别出通知 → 丢给处理线程 → 立即继续读下一条 通知处理线程(Handler-Thread): 收到通知 → 发 tools/list 请求 → 等待响应 ``` - Reader-Thread 把通知交给 Handler-Thread 后**立刻返回**,继续从网络缓冲区读数据 - 当 `tools/list` 的响应到达时,Reader-Thread 会读到它,然后通过请求-响应配对机制(ConcurrentHashMap + CompletableFuture),把结果交给正在等待的 Handler-Thread - **两个线程各干各的,互不阻塞** --- ### 一句话总结 > **死锁不是因为"单线程",而是因为"读消息和处理消息共用同一线程,导致处理过程中的请求响应没人读"**。单独用一个线程处理通知,就是把"读"和"处理"解耦,让读线程永远不被阻塞,从而避免自己等自己的闭环。
点赞
回复 取消回复
¤ 2026年07月01日 11:23
引用原文:也简单,有 command 字段就走 stdio,有 url 字段就走 HTTP,PaiCLI 自己判断。
@派聪明 怎么理解?
点赞
回复1 取消回复
派聪明 2026年07月01日 11:23
这段话的核心意思是:**MCP Server 的配置就两个关键字段,看字段名就能判断用哪种传输方式**。 具体来说: - **有 `command` 字段** → 走 **stdio**(标准输入输出)。Host 把 Server 当子进程启动,通过标准输入输出发消息。适合本地工具(如 git、浏览器操作),Server 跟着 Host 的生死走。 - **有 `url` 字段** → 走 **Streamable HTTP**。Host 通过 HTTP POST 发请求,Server 用 SSE 流式返回。适合云端服务、团队共享的 Server,生命周期独立。 **PaiCLI 自己判断**的意思是:解析配置文件时,你不需要手动声明传输方式,框架检查配置里存在哪个字段,自动选择对应的通信模式。 举个实际例子: ```json // 走 stdio { "command": "node", "args": ["server.js"] } // 走 HTTP { "url": "https://mcp.example.com/sse" } ``` 一个字段之差,决定了 Server 是本地子进程还是远程服务,底层通信机制完全不同——但**配置者只需要关心填 command 还是 url**,剩下的 PaiCLI 自动处理。这就是"也简单"三个字背后的设计哲学。
点赞
回复 取消回复
关点点儿 2026年06月29日 07:23
@派聪明
点赞
回复1 取消回复
派聪明 2026年06月29日 07:23
根据您提供的参考资料,MCP(Model Context Protocol)的核心内容非常清晰。请问您具体想了解哪个方面?比如: 1. **MCP是什么、解决了什么问题**(统一AI与外部工具的通信接口,避免重复开发) 2. **stdio与Streamable HTTP传输的区别**(本地子进程 vs 远程网络服务) 3. **JSON-RPC通信协议的工作机制**(Request/Response/Notification,ConcurrentHashMap+CompletableFuture配对) 4. **工具命名空间设计**(`mcp__server名__tool名` 格式) 5. **Resources与Tools的区别**(只读数据源 vs 可执行操作) 6. **MCP与Function Calling的关系**(MCP管工具来源,Function Calling管LLM选择) 7. **其他**(如schema清洗、通知机制、错误处理、CDP会话复用等) 请告诉我您想了解的具体问题,我将结合资料给出最清晰的答案。
点赞
回复 取消回复
xcx0103 2026年06月09日 23:15
引用原文::tools/list_changed 工具列表变了、resources/list_changed 资源列表变了、resources/updated 某个资源的内容更新了。
@派聪明 这几个有什么区别吗
1
回复1 取消回复
派聪明 2026年06月09日 23:15
这三者虽然都属于 MCP 的通知机制,但职责和触发的场景完全不同,具体区别如下: **1. `tools/list_changed`(工具列表变了)** * **含义**:MCP Server提供的**工具能力**发生了变化。 * **场景**:原本 Server 只能“查数据”,现在新增了“发邮件”或“删文件”的技能。Host(宿主程序)收到这个通知后,会重新拉取工具清单,让 LLM知道自己多了一个可以用的新工具。 **2. `resources/list_changed`(资源列表变了)** * **含义**:MCP Server提供的**数据源列表**发生了变化。 * **场景**:相当于目录或“菜单”更新了。比如原本只能读取 A 文件夹的数据,现在增加了对 B 文件夹的访问权限,或者某个数据库接口下线了。Host 收到通知后会更新资源目录,但此时并不代表具体文件的内容改了。 **3. `resources/updated`(资源内容更新了)** * **含义**:某个**具体资源内部的数据**发生了更新。 * **场景**:列表没变,但里面的东西变了。比如 Server提供了一个读取“系统日志”的资源,当系统日志里新写入了一条报错信息时,Server 就会推送这个通知。Host 收到后会清掉该资源的旧缓存,以便 LLM 下次读取时能拿到最新的文本内容。 **简单总结**: `tools/list_changed`管的是**“能执行什么动作”**的更新;`resources/list_changed`管的是**“有哪些数据可读”**的目录更新;`resources/updated`管的是**“具体读到的内容”**的变动。
点赞
回复 取消回复
xcx0103 2026年06月09日 23:06
引用原文:MCP 的 resources 是什么,和 tools 有什么区别
@派聪明 详细讲一下
点赞
回复1 取消回复
派聪明 2026年06月09日 23:06
MCP中的 Resources 和 Tools 是两个核心概念,简单来说:**Tools 是“用来干活的”,而 Resources 是“用来读取数据的”**。 你可以把它们类比为开发中的接口:Tools 相当于 `POST`端点,它接收输入参数,并且**会改变系统状态**(例如执行点击按钮、修改文件等操作);Resources 相当于 `GET`端点,它通过 URI 进行访问,只返回内容,**只读不写**。 虽然概念明确,但在实际应用中有一个关键痛点:**当前的 LLM(大语言模型)并不能直接调用 `resources/read`**。因为现有的 Function Calling协议里只有“工具”的概念,并没有“资源”。 为了解决这个限制,PaiCLI采用了两种巧妙的处理方式来实现数据访问: 1. **将 Resources 包装成 Tools**: 系统会为每个支持 Resources 的 MCP Server 自动注册两个虚拟工具——`list_resources` 和 `read_resource`。这样一来,LLM 就可以像调用普通工具一样去调用它们。LLM 先查有哪些资源,再按 URI读取具体内容。这种方式非常适合 LLM 需要**主动探索数据**的场景。 2. **支持用户通过 `@`符号直接指定**: 用户可以在输入框里直接写 `@server:protocol://path`。PaiCLI 在把请求提交给 Agent之前,会自动把该资源的内容展开并塞进提示词里,整个过程完全不需要 LLM去决策。这种方式适用于**用户已经明确知道要读取什么资源**的场景。
点赞
回复 取消回复

目录