文章目录前言一、先分清两个容易搞混的东西Tool 和 Resource1.1 两者底层逻辑完全反过来二、只注册Resource模型绝对看不见的根本原因2.1 registerResource只是“贴告示”不是“送货上门”2.2 为什么设计成不自动全量灌入四个现实痛点三、完整四步流程资源才能真正进到模型眼里3.1 第一步MCP Server完成资源注册3.2 第二步Client调用listResources发现全部资源3.3 第三步readResource读取资源真实文本3.4 第四步塞入SystemMessage模型终于能看见四、Resource不用ToolMessage底层逻辑区分清楚五、Resource和RAG别搞混适用场景完全不同六、收尾必做关闭MCP Client释放进程七、全文核心总结一次记牢不踩坑P.S. 无意间发现了一个巨牛的人工智能教程非常通俗易懂对AI感兴趣的朋友强烈推荐去看看传送门https://blog.csdn.net/HHX_01前言做AI Agent集成MCP的时候我前几天熬到半夜三点差点把键盘砸了。我吭哧吭哧写完registerResource代码控制台打印注册成功日志干干净净一点报错没有。转头问模型文档内容模型两眼一抹黑啥都不知道。当时我内心OS我都把资料挂服务器上了模型是瞎了还是装失忆合着我写的代码全是空气后面翻透协议、搭最小Demo跑通全链路才搞懂核心误区注册资源 ≠ 模型能读到资源。今天掰开揉碎讲清楚看完再也不用通宵debug。一、先分清两个容易搞混的东西Tool 和 Resource1.1 两者底层逻辑完全反过来很多人刚上手直接把他俩当成一套东西踩坑第一步就在这。Tool是模型主动伸手要东西Resource是应用硬塞给模型看一个主动一个被动跟外卖和快递似的。Tool像外卖模型饿了主动下单Runtime接单做完把餐送回去Resource像快递App提前把包裹塞模型手里模型不用开口就能直接看。能力类型谁掌控使用时机怎么进模型上下文Tool工具大模型自己判断需不需要调用执行完成后包装成ToolMessage传给模型Resource资源上层Host应用全权说了算应用读取内容后手动塞进SystemMessage举个最简单的例子同一个MCP服务同时挂了query_user查询工具、docs://guide文档资源。用户说“查001号用户”模型自己发起Tool调用用户问“使用指南写了啥”模型能回答全靠应用提前把文档塞进去。二、只注册Resource模型绝对看不见的根本原因2.1 registerResource只是“贴告示”不是“送货上门”你在Server调用注册方法本质就是在服务器门口贴一张告示我这有一份docs://guide文档谁想读随时来拿。贴告示不代表把文档打印好塞模型手里啊总不能小区门口贴个商品广告快递自动把货送每家每户吧那不得把小区住户全淹了。这里有个关键逻辑模型能读取的内容只来自当前对话messages、绑定Tools。服务器注册资源不会自动追加进对话消息。2.2 为什么设计成不自动全量灌入四个现实痛点别吐槽协议设计反人类自动全量塞资源才是灾难。Token直接爆炸上百份文档一次性丢进去上下文直接拉满计费翻倍还降推理速度无关内容干扰判断用户只问用户查询你把全套部署文档全塞进去模型容易跑偏答非所问权限管控失效不同用户能访问的资源不一样自动加载会泄露私密文档场景匹配混乱部分资源只在特定任务生效全部常驻上下文完全没必要所以资源加载权限必须交给上层应用Host自己把控。三、完整四步流程资源才能真正进到模型眼里从Server注册到模型读取完整链路一步都不能少缺一步直接失效。3.1 第一步MCP Server完成资源注册用registerResource注册四个核心参数缺一不可资源名称、唯一URI、文件类型、返回内容的回调函数。很多人把URI当成网页链接还跑去浏览器输入打不开然后疯狂怀疑代码出错。这里的URI就是内部专属身份证docs://guide、file://xxx这种格式只给MCP客户端识别用跟互联网网址半毛钱关系没有。执行完这段代码仅完成“对外声明存在这份资源”模型这边毫无感知。3.2 第二步Client调用listResources发现全部资源Host启动MultiServerMCPClient连接本地MCP子进程调用listResources拉取所有服务的资源清单。这一步相当于你扫小区公告栏把所有告示全部看一遍知道现在有哪些资源可以读取。光看清单没用清单只有名字和地址没有正文模型还是啥都看不到。代码里需要循环遍历所有服务、服务下全部资源记录对应的serverName和uri这是后面读取的两个必填参数。3.3 第三步readResource读取资源真实文本拿着服务名资源URI调用读取接口才能拿到文档正文。有人疑惑为啥不能只传URI一台客户端能同时连三五台MCP服务不同服务完全可能出现一模一样的URI只传URI系统分不清去哪取文件直接迷路报错。读取返回的内容可能有多段文本需要循环拼接整合完整资源内容。到这一步应用才真正拿到文档文字。3.4 第四步塞入SystemMessage模型终于能看见把拼接好的资源文本封装成系统提示词和用户提问HumanMessage一起组成对话数组传给大模型。这一步就是临门一脚前面三步全是铺垫。前面忙活半天最后忘了塞SystemMessage等于快递到楼下没上楼模型照样收不到。完整链路简化版registerResource → listResources发现 → readResource读正文 → 整理文本 → SystemMessage注入 → LLM读取内容四、Resource不用ToolMessage底层逻辑区分清楚之前有同事问我读取资源为啥不用ToolMessage包装调工具却必须用我给他打了个比方一下就懂了。ToolMessage是模型主动下单后的回执必须带tool_call_id证明对应哪一次工具调用Resource是提前备好的说明书对话一开始就放在系统提示里模型没发起任何调用自然不需要回执。两种链路可以同时存在于同一个MCP服务Resource链路Host主动读取 → SystemMessage → 模型直接读取作答Tool链路模型发起调用 → Runtime执行逻辑 → ToolMessage回传结果给模型五、Resource和RAG别搞混适用场景完全不同现在做Agent的朋友一想到给模型加外部知识不是RAG就是MCP Resource经常纠结二选一其实他俩根本不冲突是互补关系。好比你随身带一本薄薄的操作手册Resource同时家里有一整柜藏书RAG向量库薄手册随时揣兜里厚藏书需要的时候再翻找。使用场景优先选择方案简短、固定、每次对话都需要的说明文档MCP Resource直接读取注入上下文海量文档需要根据用户问题检索匹配片段RAG向量检索需要执行查询、读写文件、调用外部接口MCP Tool工具调用Resource不是RAG替代品两者解决不同规模、不同加载时机的上下文需求项目里经常搭配使用。六、收尾必做关闭MCP Client释放进程之前写Demo忘记关客户端脚本跑完控制台一直挂着进程后台疯狂占内存我找了半小时才发现是MCP子进程没销毁。Node子进程启动后会持续占用stdio通信通道不手动关闭脚本永远不会正常退出后台堆一堆僵尸进程。标准稳妥写法把关闭逻辑放进finally代码块不管执行成功还是报错都会自动断开连接、销毁子进程。七、全文核心总结一次记牢不踩坑registerResource仅完成资源声明不会自动注入模型上下文资源可见完整四步listResources发现 → readResource读取 → 整理文本 → 写入SystemMessage三层权责划分清晰Server负责提供资源、Client负责读取资源、Host负责控制上下文注入、LLM负责解析内容别再幻想服务器注册完资源模型自动全知全能。AI应用的上下文控制权永远握在开发自己手里偷懒省略步骤就要通宵改bug。P.S. 无意间发现了一个巨牛的人工智能教程非常通俗易懂对AI感兴趣的朋友强烈推荐去看看传送门https://blog.csdn.net/HHX_01