【免费下载链接】gemini-notebook-mcp-cliProgrammatic access to Gemini Notebook - via command-line interface (CLI), Model Context Protocol (MCP) server, and AI agent skills.项目地址https://gitcode.com/gh_mirrors/not/gemini-notebook-mcp-cli点击查看免费下载导读v0.9.12 是 gemini-notebook-mcp-cli下文简称本项目针对查询链路的一次关键维护版本核心解决两个问题查询会话隔离new_conversationTrue/ CLI--new-conversation跳过笔记本持久会话查找与空答案防御空、纯空白或缺失的查询答案不再被当作成功结果返回。本文以 docs/releases/v0.9.12.md 为骨架结合 services/chat.py、core/conversation.py 及对应测试用例深入讲解该版本引入的两项机制的原理、入口与实战用法。读完本文你将掌握如何通过 CLI、MCP 工具与 REPL 三种入口开启全新会话理解空答案结构化错误的触发条件与错误元数据结构并能复现该版本的完整验证流程。一、版本背景与发布要点v0.9.12 属于项目的维护型Maintenance发布发布于 2026-08-17见 CHANGELOG.md其发布说明为 docs/releases/v0.9.12.md。该版本的变更集中在一个 GitHub Issue#297上主要包含Added查询调用方可以传new_conversationTrue启动一次独立会话而无需查找笔记本的持久聊天CLI 通过--new-conversation暴露同样行为。Fixed空、纯空白或缺失的查询答案现在会抛出结构化服务错误REPL 的/clear命令现在真正开启全新会话既有默认行为保持不变——省略会话 ID 时若笔记本存在持久聊天则继续该聊天。Verification完整测试套件 1,415 通过、39 跳过Ruff lint 与格式化检查通过使用--new-conversation的实机 CLI 查询返回了带引用的答案且会话 ID 与笔记本现有活动会话不同。下文将逐一拆解这些变更的实现细节。二、会话隔离机制new_conversation全链路解析2.1 背景NotebookLM 的持久会话模型在 v0.9.12 之前本项目查询笔记本时遵循如下规则core/conversation.py 中的判断逻辑若调用方显式传入conversation_id则直接复用该会话并尝试从进程内缓存构建历史用于多轮追问。若未传conversation_id即首次查询核心客户端会调用get_conversation_id(notebook_id)向服务端发起RPC_GET_CONVERSATIONS查找笔记本关联的持久会话 ID该 ID 正是让 CLI/MCP 聊天出现在 Web UI 聊天面板中的关键机制见 core/conversation.py。找到持久会话则续用找不到才生成新的 UUID。这套默认行为保证了「省略会话 ID 即继续笔记本持久聊天」的向后兼容但同时也意味着无法通过省略会话 ID 来开启一次与既有聊天完全隔离的独立问答。这正是 v0.9.12 引入new_conversation的原因。2.2 核心客户端层的实现在 core/conversation.py 中ConversationMixin.query()新增了new_conversation: bool False参数。其关键逻辑位于会话 ID 解析分支core/conversation.pyis_new_conversation conversation_id is None if is_new_conversation: if new_conversation: conversation_id str(uuid.uuid4()) # 直接生成本地 UUID conversation_history None # 不带任何历史 else: # 默认路径Enterprise 走本地 UUID消费版查找服务端持久会话 server_conv_id self.get_conversation_id(notebook_id, timeoutremaining_timeout()) if server_conv_id: conversation_id server_conv_id conversation_history self._build_conversation_history(conversation_id) else: conversation_id str(uuid.uuid4()) conversation_history None可以看到new_conversationTrue时完全跳过get_conversation_id服务端 RPC 调用直接以uuid.uuid4()生成全新会话 ID并让conversation_history None即请求体中params[2] None见 core/conversation.py从根源上实现会话隔离。对应的契约测试位于 tests/core/test_conversation.pytest_new_conversation_skips_server_conversation_lookup将get_conversation_id打桩为side_effectAssertionError一旦被调用即测试失败再以new_conversationTrue发起查询断言返回的conversation_id是一个 36 位 UUID 且不等于server-conv-id。该测试精确锁定了「显式新会话不得复用服务端会话」的契约。需要说明的是服务端在响应中仍可能返回自己分配的server_conv_id解析逻辑见 core/conversation.py此时核心客户端会迁移本地缓存键到服务端 ID——这是「聊天历史持久化」的底层机制与隔离语义并不冲突隔离保证的是发起时不复用既有会话而不是禁止服务端为本次问答分配新会话。2.3 服务层的透传服务层 services/chat.py 的query()与异步入口query_start()services/chat.py均新增new_conversation: bool False参数并原样透传给核心客户端query_options {} if new_conversation: query_options[new_conversation] True result client.query( notebook_idnotebook_id, query_textquery_text, source_idsresolved_source_ids, conversation_idconversation_id, timeoutbudget.remaining(), **query_options, )见 services/chat.py。透传行为有服务层测试背书tests/services/test_chat.py 的test_new_conversation_passed_through断言调用核心客户端的 kwargs 中new_conversation is True。另外异步查询query_start的后台线程执行函数_run_query_in_backgroundservices/chat.py同样携带new_conversation保证长耗时查询源码建议 source-heavy 笔记本用timeout180在异步模式下也能开启隔离会话。2.4 三种使用入口入口一CLI 一次性查询nlm notebook query命令cli/commands/notebook.py与nlm query notebook动词cli/commands/verbs.py都新增了--new-conversation开关# 默认行为继续笔记本持久聊天 nlm notebook query notebook-id 问题 # 显式开启全新会话 nlm notebook query notebook-id 问题 --new-conversation # 动词风格等价写法 nlm query notebook notebook-id 问题 --new-conversation # 与其它选项组合--json 输出、-s 指定来源、-t 超时 nlm notebook query notebook-id 问题 --new-conversation --json -s src-1,src-2 -t 180其中-t/--timeout默认 120 秒源码注释建议 source-heavy 笔记本可使用 180 秒以上cli/commands/notebook.py。该用法也被写入项目的 Agent 技能文档 data/SKILL.md并出现在 MCP 测试计划中docs/MCP_CLI_TEST_PLAN.md其中 Enterprise 场景的首次查询刻意使用--new-conversation以避免依赖持久会话网络路径。入口二MCP 工具MCP 层的notebook_query与异步notebook_query_start工具均接收new_conversation布尔参数mcp/tools/chat.py 与 mcp/tools/chat.py并透传给服务层{ name: notebook_query, arguments: { notebook_id: notebook-uuid, query: 对这批资料做一个独立于既有聊天的总结, new_conversation: true, timeout: 180 } }异步工作流为notebook_query_start→ 轮询notebook_query_status(query_id)直至completed或errormcp/tools/chat.py。查询结果状态保留 10 分钟_QUERY_TTL_SECONDS 600见 services/chat.py并发上限默认 8可通过环境变量NOTEBOOKLM_ASYNC_QUERY_MAX_INFLIGHT调整services/chat.py。入口三REPL 交互聊天REPL交互式聊天cli/commands/repl.py在此版本修复了/clear命令的语义Available Commands: /exit, /quit Exit the chat /clear Start new conversation /sources List notebook sources /help Show this help修复前的实现是/clear后下次查询仍可能续用笔记本持久会话修复后cli/commands/repl.pyelif cmd /clear: conversation_id None new_conversation True turn_number 0 console.print([green]✓[/green] Conversation cleared.\n) continue即将new_conversation置为True使下一次查询走全新会话路径查询成功后new_conversation复位为Falsecli/commands/repl.py后续追问继续使用本次返回的conversation_id。REPL 还实现了引用解析_parse_citations支持[1]、[1, 2]、[11-13]、[1, 2, 5-7]等格式见 cli/commands/repl.py与来源引用图例渲染方便验证隔离会话返回的引用指向。2.5 会话缓存的内存边界相关底层机制开启新会话意味着会话数量增长为防长驻 MCP 进程内存无界增长Issue #213核心客户端对会话缓存施加三重上限core/base.py全部可用环境变量调整环境变量默认值含义NOTEBOOKLM_CONVERSATION_MAX_TURNS50每个会话最多保留的轮次FIFO最早丢弃轮次号从 1 重排NOTEBOOKLM_CONVERSATION_MAX_CONVS500会话缓存 LRU 上限超出淘汰最久未用会话NOTEBOOKLM_CONVERSATION_MAX_CHARS_PER_TURN100_000单轮答案字符截断安全阀查询文本不截断置 0 可关闭对应上限测试场景常用完整逻辑见_cache_conversation_turncore/conversation.py并可用get_conversation_cache_stats()内省当前状态core/conversation.py。三、空答案防御机制结构化错误替代静默成功3.1 问题与修复v0.9.12 之前若服务端响应缺少答案或答案为空/纯空白查询链路可能把「无内容」当作成功结果返回导致调用方拿到空字符串却无法判断失败原因。v0.9.12 在服务层加入严格校验services/chat.pyif result: answer result.get(answer) if not isinstance(answer, str) or not answer.strip(): raise ServiceError( Query returned empty answer, user_messageThe notebook returned no answer. Please retry the query., ) ... raise ServiceError( Query returned empty result, user_messageFailed to get a response from the notebook., )两个错误分别覆盖两类情况Query returned empty answer响应对象存在但answer为空字符串、纯空白 或缺失None/ 非字符串。Query returned empty result整个响应为假值如None属于更底层的失败。3.2 结构化错误元数据ServiceErrorservices/errors.py携带面向机器消费的字段user_message、hint、debug_code、category、provider_code、retryable、suggested_actiondetails()方法只返回非空字段。空答案错误虽未显式设置这些字段保留None但其user_message已给出面向终端用户的提示而同类查询失败——例如QueryRejectedError映射services/chat.py——会生成debug_codequery_{category}的完整元数据其中category来自 Google 错误码映射表core/conversation.pyprovider_codecategoryretryablesuggested_action3invalid_argumentFalsecheck_query_arguments4deadline_exceededTrueretry_with_longer_timeout5not_foundFalsecheck_notebook_and_source_ids7permission_deniedFalsecheck_access_permissions8resource_exhaustedTrueretry_after_delay13internalTrueretry_after_delay14unavailableTrueretry_after_delay16unauthenticatedFalserun_nlm_login完整映射见 services/chat.py。CLI 端通过handle_error统一渲染MCP 端通过service_error_result转为{status: error, ...}返回mcp/tools/chat.py保证 Agent 调用方能从结构化字段中拿到可执行的建议动作。3.3 测试验证服务层测试 tests/services/test_chat.py 使用参数化用例锁定契约pytest.mark.parametrize(answer, [, , None]) def test_empty_answer_raises_service_error(self, mock_client, answer): mock_client.query.return_value {answer: answer} with pytest.raises(ServiceError, matchempty answer): query(mock_client, nb-123, question, source_ids[src-1])同时空白查询文本本身也受防护—— 会在进入网络请求前抛出ValidationErrorQuery text is required.见 services/chat.py 与 tests/services/test_chat.py。此外消费端_parse_query_response在流式解析时若完全无答案但检测到 Google 错误会先抛QueryRejectedErrorcore/conversation.py服务层再将其映射为结构化错误——三层防线层层递进。四、验证流程与回归保障4.1 自动化验证完整测试套件1,415 通过、39 跳过与 v0.9.12 发布说明一致也复现在 CHANGELOG.md代码质量门禁Ruff lint 与格式化检查通过与本次变更直接相关的测试文件tests/core/test_conversation.pynew_conversation跳过服务端会话查找契约tests/services/test_chat.py服务层参数透传tests/services/test_chat.py空答案结构化错误tests/services/test_chat.pyQueryRejectedError的结构化元数据映射。4.2 实机验证可复现发布说明记录了如下实机验证过程docs/releases/v0.9.12.md# 1. 列出笔记本取得 notebook-id nlm notebook list --json # 2. 先用默认方式查询若笔记本已有持久聊天将续用 nlm notebook query notebook-id 某问题 # 3. 用 --new-conversation 开启隔离会话观察 conversation_id nlm notebook query notebook-id 某问题 --new-conversation --json预期结果步骤 3 返回带引用的答案且其conversation_id与步骤 2 使用的活动会话 ID 不同——这正是「隔离」语义的直接证据。若遇到空答案应看到结构化错误CLI 渲染user_messageMCP 返回{status: error}而非静默的空字符串成功响应。五、向后兼容性与注意事项默认行为不变省略conversation_id且不传new_conversation时消费版账户仍会查找并续用笔记本的持久服务端会话这正是聊天出现在 Web UI 的原因Enterprise 版因流式路由不暴露消费版会话查找 RPC默认也使用本地生成的 UUIDcore/conversation.py。该兼容性由现有测试套件持续回归。new_conversation仅在conversation_id省略时生效若显式传了conversation_id会走「指定会话 缓存历史」分支core/conversation.py此时new_conversation不参与判定。REPL/clear语义修复后清空的是「会话状态」服务端历史不会因本地/clear被删除如需彻底清除服务端聊天历史应使用nlm chats delete对应服务层delete_chat_history见 services/chat.py。时间预算查询使用墙钟预算默认 120 秒source-heavy 笔记本建议 180 秒异步入口可避免 MCP 客户端超时。隔离会话与引用新会话不影响来源引用——返回结果中的citations、references含被引段落原文由_extract_citation_data从 type-1 答案块解析core/conversation.py与是否新会话无关。结语v0.9.12 以两个小而精准的修复提升了查询链路的健壮性new_conversation让「独立问答」成为一等公民CLI、MCP、REPL 三入口齐备空答案结构化错误则把「静默无内容」转变成可诊断、可自动处置的失败信号。结合 core/conversation.py、services/chat.py 及其测试你可以清晰地看到本项目如何用「核心客户端 → 服务层 → CLI/MCP/REPL」的分层设计把会话生命周期与错误语义统一管理起来——这一模式也适用于其它需要多轮会话状态管理的数据查询类工具。赞分享【免费下载链接】gemini-notebook-mcp-cliProgrammatic access to Gemini Notebook - via command-line interface (CLI), Model Context Protocol (MCP) server, and AI agent skills.项目地址https://gitcode.com/gh_mirrors/not/gemini-notebook-mcp-cli点击查看免费下载相关推荐gemini-notebook-mcp-cli v0.11.4Profile 隔离的用量Usage查询发布详解gemini notebook mcp cli v0.11.4Profile 隔离的用量Usage查询发布详解 本文围绕 gemini notebookgemini-notebook-mcp-cli v0.8.2 维护版解析nlm doctor auth-replay 认证回放诊断与 Google RotateCookies 会话保鲜机制gemini notebook mcp cli v0.8.2 维护版解析 nlm doctor auth replay 认证回放诊断与 Google Rotagemini-notebook-mcp-cli v0.9.11 维护版解析Firefox 认证后备机制与 MCP 列表参数兼容性修复gemini notebook mcp cli v0.9.11 维护版解析Firefox 认证后备机制与 MCP 列表参数兼容性修复 本篇技术指南以 gemi上一篇Yii 2 会话与 Cookie 完全指南对象化封装、自定义存储与安全加固实践下一篇agentic-awesome-skills 后端开发模式实战指南从 API 设计到可观测性的 TypeScript 服务端最佳实践创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考