Gemini CLI MCP 资源工具详解:list_mcp_resources 与 read_mcp_resource 的发现与读取机制

发布时间:2026/9/7 5:24:45
Gemini CLI MCP 资源工具详解:list_mcp_resources 与 read_mcp_resource 的发现与读取机制 Gemini CLI MCP 资源工具详解list_mcp_resources 与 read_mcp_resource 的发现与读取机制【免费下载链接】gemini-cliAn open-source AI agent that brings the power of Gemini directly into your terminal.项目地址: https://gitcode.com/GitHub_Trending/gemi/gemini-cliGemini CLI 通过两个内置工具让模型从 MCPModel Context Protocol服务器中发现并获取上下文数据list_mcp_resources负责枚举所有已连接服务器暴露的资源read_mcp_resource负责按 URI 读取单个资源的内容。本文基于官方工具文档与packages/core中的实际实现完整覆盖两个工具的参数、行为、输出格式并深入讲解底层资源注册表ResourceRegistry、resources/read调用链以及错误处理策略读完即可在自己的 MCP 服务器上正确地设计资源 URI 并验证其可被 Gemini CLI 读取。1. 两个工具的定位与总览MCP 规范中除 tools 之外服务器还可以暴露resources资源——一种由模型按需读取的只读上下文数据例如配置片段、文档、数据集条目等。Gemini CLI 为此提供了两个专属工具它们的职责分工是典型的“先发现、后检索”两步模式工具名显示名Kind是否需确认实现文件list_mcp_resourcesList MCP ResourcesSearch否只读发现list-mcp-resources.tsread_mcp_resourceRead MCP ResourceRead否只读取回read-mcp-resource.ts两个工具均为只读操作因此不触发确认流程模型可以在会话中自由调用它们来补充上下文而不会引发副作用。工具名称常量统一集中在 tool-names.ts而面向模型的描述与 JSON Schema 则来自 coreTools.ts 中的LIST_MCP_RESOURCES_DEFINITION和READ_MCP_RESOURCE_DEFINITION两个定义——从源码结构看这两个定义带有overrides(modelId)钩子意味着针对不同模型版本可以下发不同的工具描述与参数 Schema。2. list_mcp_resources枚举可用资源list_mcp_resources是一个发现类工具帮助模型理解当前有哪些外部数据源可供引用。参数serverNamestring可选按服务器名过滤仅列出该服务器暴露的资源。对应实现中的 ListMcpResourcesParams 接口export interface ListMcpResourcesParams { serverName?: string; }行为与执行流程从 ListMcpResourcesToolInvocation.execute 的实现看执行链路如下通过AgentLoopContext获取MCP Client Managerconfig.getMcpClientManager()。若管理器不可用直接返回Error: MCP Client Manager not available.错误类型为ToolErrorType.EXECUTION_FAILED。调用mcpManager.getAllResources()拿到所有已发现的资源若指定了serverName则用resources.filter((r) r.serverName serverName)做内存过滤。若过滤后为空返回No MCP resources found.或No resources found for server: name注意这种情况返回的是普通消息而非错误对象模型可据此判断是服务器无资源还是过滤条件写错。否则格式化输出资源列表。输出格式llmContent的格式为逐行纯文本每行一个资源Available MCP Resources: - myserver:test://resource1 | Resource 1 | A test resource即- ${serverName}:${uri}后跟可选的| ${name}和| ${description}。终端展示的returnDisplay则简短得多Listed N resources.。这个“给模型的完整列表 给用户的简短摘要”双通道输出模式在 Gemini CLI 的多数工具中是一致的设计。3. read_mcp_resource按 URI 读取资源内容read_mcp_resource检索由 URI 唯一标识的单个资源内容。参数uristring必填要读取的 MCP 资源 URI。对应接口为 ReadMcpResourceParams。行为与执行流程从 ReadMcpResourceToolInvocation.execute 看执行链路与一系列防御性检查如下Manager 可用性检查与 list 工具相同取不到 MCP Client Manager 时返回EXECUTION_FAILED错误。URI 非空检查uri缺失时返回Error: No URI provided.INVALID_TOOL_PARAMS。资源定位调用mcpManager.findResourceByUri(uri)。找不到时返回Error: Resource not found for URI: uri错误类型为专门的ToolErrorType.MCP_RESOURCE_NOT_FOUND——这个专用错误类型便于上层策略或日志区分“资源不存在”与其他执行故障。客户端定位通过mcpManager.getClient(resource.serverName)找到资源所属服务器的客户端找不到则返回EXECUTION_FAILED。发起读取调用client.readResource(resource.uri)最终向服务器发出 MCPresources/read请求见下文第 5 节。URI 的解析规则serverName:uri一个关键细节是findResourceByUri的解析规则。资源在注册表中的键是serverName::uri而工具接收的标识符格式是serverName:uri例如myserver:file:///data.txt。实现逻辑见 ResourceRegistry.findResourceByUrifindResourceByUri(identifier: string): MCPResource | undefined { const colonIndex identifier.indexOf(:); if (colonIndex 0) { return undefined; } const serverName identifier.substring(0, colonIndex); const uri identifier.substring(colonIndex 1); return this.resources.get(resourceKey(serverName, uri)); }它以第一个冒号为分隔点冒号之前是服务器名之后含冒号本身被切掉是资源 URI。由此可以推断两条实践约束传给read_mcp_resource的uri参数应写成服务器名:资源URI的形式与list_mcp_resources输出中每行开头的serverName:uri片段保持一致服务器名本身不能包含冒号否则会破坏解析。内容处理文本与二进制read_mcp_resource遵循 MCP 规范处理返回的{ contents: [...] }逐条遍历 content 项read-mcp-resource.ts含text字段的项直接拼接文本内容含blob字段的项二进制数据不回填原始字节而是输出占位符[Binary Data (${mimeType})]告知模型该资源是哪种 MIME 类型的二进制数据若服务器未返回任何内容llmContent为No content returned from resource.。读取失败例如服务器抛错时返回Error: Failed to read resource: message错误类型为ToolErrorType.MCP_TOOL_ERROR。4. 底层支撑ResourceRegistry 资源注册表两个工具都依赖同一份资源元数据即 ResourceRegistryresource-registry.ts。它是“跟踪从 MCP 服务器发现到的资源”的注册表核心结构是一个Mapstring, MCPResource键为${serverName}::${uri}。关键接口与语义方法说明setResourcesForServer(serverName, resources)整体替换某台服务器的资源集合先移除该服务器旧条目再重新注册并记录discoveredAt时间戳没有uri的条目会被直接跳过getAllResources()返回全部资源list_mcp_resources工具的数据来源findResourceByUri(identifier)按serverName:uri格式定位单个资源getResourcesByServer(serverName)返回某服务器的资源并按 URI 字典序排序removeResourcesByServer(serverName)/clear()按服务器清理或整体清空MCPResource在 MCP SDK 的Resource类型基础上扩展了两个字段resource-registry.tsexport interface MCPResource extends Resource { serverName: string; discoveredAt: number; }discoveredAt记录了资源发现时间可用于其他组件如上下文注入判断资源的新鲜度。5. 发现与读取的底层调用链资源并非在工具调用时才去服务器拉取而是在 MCP 客户端连接阶段就完成发现。从 McpClient 的源码结构看客户端连接后会调用discoverResources()拉取服务器资源列表并通过updateResourceRegistry()写入ResourceRegistrymcp-client.tsMcpClient还注册了通知处理器监听服务器发来的资源列表变更通知动态更新注册表因此list_mcp_resources返回的是服务器声明的最新资源集合真正读取内容时McpClient.readResource(uri)向服务器发起resources/read请求并用ReadResourceResultSchema校验响应mcp-client.tsasync readResource( uri: string, options?: { signal?: AbortSignal }, ): PromiseReadResourceResult { this.assertConnected(); return this.client!.request( { method: resources/read, params: { uri }, }, ReadResourceResultSchema, options, ); }这里注意发给服务器的params.uri是原始资源 URI例如test://resource1服务器名只用于在客户端侧路由到正确的McpClient实例。6. 集成测试中的可复制示例仓库中的 mcp-resources.test.ts 用真实的 stdio MCP 服务器完整验证了“发现 读取”全链路其中的服务器脚本可以直接作为你自建 MCP 服务器的参考模板。资源发现侧服务器只需声明resources: {}能力并处理ListResourcesRequestSchemamcp-resources.test.tsserver.setRequestHandler(ListResourcesRequestSchema, async () { return { resources: [ { uri: test://resource1, name: Resource 1, mimeType: text/plain, description: A test resource, } ], }; });内容读取侧处理ReadResourceRequestSchema并按 URI 分支返回mcp-resources.test.tsserver.setRequestHandler(ReadResourceRequestSchema, async (request) { if (request.params.uri test://resource1) { return { contents: [ { uri: test://resource1, mimeType: text/plain, text: This is the content of resource 1, } ], }; } throw new Error(Resource not found); });测试分别以 “List all available MCP resources.” 与 “Read the MCP resource test://resource1.” 两个提示驱动模型断言list_mcp_resources/read_mcp_resource被实际调用且输出包含test://resource1与content of resource 1。配套的单测还可参考 list-mcp-resources.test.ts 与 read-mcp-resource.test.ts其中覆盖了管理器缺失、资源未找到等错误分支。7. 实践要点与限制两步式使用先list_mcp_resources可加serverName过滤拿到serverName:uri形式清单再把其中的serverName:uri片段作为read_mcp_resource的uri参数URI 解析以第一个冒号切分服务器名中不要出现冒号。纯 URI 不会命中若直接把test://resource1不带服务器名前缀传给findResourceByUri解析出的“服务器名”会是test通常导致MCP_RESOURCE_NOT_FOUND。资源是只读上下文两个工具均不触发确认服务器也只需要实现 list/read 两个请求处理器即可接入二进制资源不会被灌入上下文只会留下[Binary Data (mimeType)]占位符。错误可区分MCP_RESOURCE_NOT_FOUND、MCP_TOOL_ERROR、INVALID_TOOL_PARAMS等错误类型在ToolResult.error中明确区分便于脚本化诊断。适用前提以上行为以当前仓库packages/core的实现为准要求 MCP 服务器已通过 CLI 的 MCP 配置连接成功且声明了 resources 能力若 MCP Client Manager 未初始化两个工具都会返回“MCP Client Manager not available.”错误。【免费下载链接】gemini-cliAn open-source AI agent that brings the power of Gemini directly into your terminal.项目地址: https://gitcode.com/GitHub_Trending/gemi/gemini-cli创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考