
Goose 与 MCP Roots让根感知型 MCP 扩展精确理解你的会话工作目录【免费下载链接】goosean open source, extensible AI agent that goes beyond code suggestions - install, execute, edit, and test with any LLM项目地址: https://gitcode.com/GitHub_Trending/goose3/gooseMCP Roots 是 Model Context Protocol 的一项客户端能力它让 goose 能把当前会话的工作目录作为根root共享给支持 roots 的 MCP 扩展从而让扩展明确知道该把哪个文件夹当作本次会话的活动工作区。本文以 goose 仓库中的官方指南 mcp-roots.md 为主线并结合 mcp_client.rs 与 extension_manager.rs 的源码实现讲解 roots 的工作机制、桌面端与 CLI 的使用方式、对扩展的价值以及当前的实现边界帮助你理解并善用这一能力。MCP Roots 是什么MCP Roots 是 Model Context Protocol 规范中定义的一项客户端侧功能。goose 会自动为支持 roots 的 MCP 扩展启用它无需额外手动开启。其价值可以概括为一句话roots 让扩展不再需要猜测你想让它操作哪个目录。当一个文件相关 MCP 扩展例如代码检索、格式化、lint 工具等被接入时它需要知道当前对话针对的是哪个项目。没有 roots 时扩展可能只能依赖自定义配置或自行推断有了 rootsgoose 可以在 MCP 初始化时直接告诉它当前会话作用域内的目录并把工作区切换事件实时推送过去。goose 中 MCP Roots 的工作原理goose 在每次连接到 MCP 扩展时都会经历标准握手过程其实现位于 mcp_client.rs。roots 支持在客户端能力声明阶段被自动广播goose 的 MCP 客户端通过ClientCapabilities::builder().enable_roots()在初始化参数中声明自身支持 roots见 mcp_client.rs一个支持 roots 的扩展随后可以向 goose 发起roots/list请求获取当前的根列表把返回的根视为活动工作区边界据此限定自身的文件操作范围订阅roots/list_changed通知在会话期间根发生变化时自动响应。对应的能力声明与查询处理器都有单元测试兜底test_client_capabilities_advertise_roots断言客户端会广播 roots 能力见 mcp_client.rstest_working_dir_roots_returns_current_dir_as_root则验证返回的根结构见 mcp_client.rs。根列表的内容在 goose 中根列表目前只包含一个条目你当前会话的工作目录这一逻辑在源码中体现得十分直接。ClientHandler对list_roots的实现会调用working_dir_roots函数把保存在客户端内部的working_dir转换为标准file://URI并命名为working_directory见 mcp_client.rsfn working_dir_roots(dir: std::path::Path) - ListRootsResult { let uri url::Url::from_file_path(dir) .map(|u| u.to_string()) .unwrap_or_else(|()| format!(file://{}, dir.display())); ListRootsResult::new(vec![Root::new(uri).with_name(working_directory)]) }也就是说扩展每次查询根时拿到的就是类似file:///home/user/my-project这样的单根条目。工作目录变更时的根更新如果你在会话中切换了工作目录goose 会自动更新根并向所有已连接的扩展发送通知。从源码调用链看这一过程分为两层扩展管理器层ExtensionManager::update_working_dir会遍历当前所有已加载扩展逐个调用其客户端的update_working_dir若某个扩展更新失败仅记录failed to update roots警告日志而不会中断整体流程见 extension_manager.rsMCP 客户端层do_update_working_dir先把新的目录写入共享的working_dir状态随后调用client.peer().notify_roots_list_changed()向远端扩展推送根变更通知见 mcp_client.rs。async fn do_update_working_dir(self, new_dir: PathBuf) - Result(), Error { let client self.client.lock().await; let shared client.service().shared_working_dir(); *shared.write().await new_dir; client.peer().notify_roots_list_changed().await?; Ok(()) }这套先改状态、再广播通知的设计保证了支持 roots 的扩展能及时感知工作区变化并做出响应。在 goose 中使用 MCP Rootsgoose 中没有独立的Roots设置界面——MCP Roots 完全跟随你当前会话正在使用的工作目录。这意味着你不需要额外学习一套配置概念只需要知道在不同界面下如何切换工作目录。goose Desktop桌面端在 goose Desktop 中当前工作目录会显示在聊天窗口底部点击底部显示目录的位置选择一个不同的文件夹goose 随即更新会话工作目录已连接的根感知扩展会自动收到更新后的根。切换目录的具体操作如有需要点击侧边栏按钮打开会话列表打开一个会话使用聊天窗口底部的目录控件选择你希望 goose 与扩展工作的目标文件夹。goose CLI命令行在 goose CLI 中会话根跟随你启动 goose 时所在的目录请从你想工作的项目文件夹启动 goose例如在仓库根目录执行goose后开始对话恢复resume一个历史会话时如果当前所在目录与该会话最初的工作目录不一致goose 会提示你是否切回原会话的工作目录。关于恢复会话时的目录切换goose 的实现位于 builder.rs启动时它会比较当前目录与会话记录中保存的原始工作目录不一致且处于交互模式时会弹出确认提示例如The original working directory of this session was set to/path/to/project。Your current directory is/path/to/other。Do you want to switch back to the original working directory?若确认切换goose 会调用std::env::set_current_dir切回原目录并在原目录已不存在时报错提示。之所以能够这样做是因为会话本身持久化了工作目录从 session_manager.rs 可以看到会话表中存在working_dir TEXT NOT NULL字段每个会话都与它创建时的工作目录绑定roots 复用的正是这份同一份状态。对于 CLI 场景的最终效果是根感知扩展看到的就是 goose 在 CLI 中已经在用的那个工作区目录二者天然一致。扩展用 roots 能做什么对需要操作本地文件或理解项目结构的 MCP 扩展而言roots 是消除歧义的关键信息。没有 roots 时扩展可能需要猜用户指的是哪个文件夹或者依赖额外自定义配置如用户手动在扩展配置里填路径。有了 rootsgoose 可以直接告诉扩展当前会话作用域内的目录。例如一个扩展可以借助 roots 实现发现活动项目目录无需用户配置直接通过roots/list获知当前项目把文件操作限定在当前工作区内读文件、写文件、搜索代码都限制在根目录内降低误操作其它仓库或目录的风险避免猜测用户所指的仓库或文件夹在多个项目并行工作时每个会话的根各不相同扩展据此定位到正确目标切换项目时同步更新行为当用户在同一会话中换了工作目录扩展收到roots/list_changed通知后即可重新锚定其工作区。当前限制goose 目前每个会话只暴露单个根single root而不是多文件夹工作区multi-folder workspace。对绝大多数工作流而言这与 goose 的实际工作方式恰好吻合——任意时刻只存在一个活动的项目目录。因此如果你的目标是让某个扩展在另一个位置工作正确做法是先切换会话工作目录再让扩展继续干活而不是指望 roots 同时列出多个目录。对扩展开发者的建议如果你正在为 goose 构建 MCP 扩展支持 roots 可以让你的扩展以标准方式发现活动工作区目录而不是依赖各不相同的自定义配置项从而在不同 MCP 客户端之间获得更好的可移植性。要实现 roots 支持扩展侧需要做到在服务端能力的roots字段中声明支持并正确实现roots/list的响应可以参考 RMCP 服务端示例或官方规范中的实现订阅notifications/roots/list_changed通知在根变化时刷新内部工作区状态把获取到的根与 goose 会话中的目录保持一致——goose 侧保证单根列表始终等于会话工作目录且带working_directory名称见 mcp_client.rs。至于协议层面的详细语义根 URI 格式、命名、变更通知的时序等可直接查阅 MCP Roots 规范MCP Roots specification。小结MCP Roots 是 goose 自动启用的 MCP 客户端能力不需要单独的设置项goose 将当前会话工作目录作为唯一的根暴露给支持 roots 的扩展根名称固定为working_directoryURI 为标准file://形式切换工作目录后goose 会通过roots/list_changed通知所有已连接扩展——这条链路在源码中由 extension_manager.rs 与 mcp_client.rs 共同完成在 CLI 中会话工作目录与启动目录绑定恢复会话时若目录不一致 goose 会提示切换回原目录见 builder.rs当前实现为每会话单根如需扩展在其它位置工作请先切换会话工作目录。若你恰好是 MCP 扩展的作者把 roots 纳入扩展的能力范围意味着你的工具可以在 goose 以及其它遵循 MCP 规范的客户端中以统一、标准的方式获知当前该操作哪个项目这也是把文件类工具做得更可靠的关键一步。【免费下载链接】goosean open source, extensible AI agent that goes beyond code suggestions - install, execute, edit, and test with any LLM项目地址: https://gitcode.com/GitHub_Trending/goose3/goose创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考