v2.0.0 unblocks v1.x and closes the full issue backlog. The selector / extraction / browser-lifecycle stack is rewritten end-to-end so the server stops breaking every time NotebookLM ships a UI tweak.
🔥 What this fixes
ask_questionworks again. v1.x has been timing out since NotebookLM removeddiv.thinking-message. v2 replaces the selector-gated wait with streaming-stability detection — an answer is final when the extracted text is identical across N consecutive 750 ms polls. (closes #43)- No more 100 % CPU loops. New
src/browser/watchdog.ts: bounded poll counts, Node-side sleep fallback, periodicpage.evaluate(() => true)health check. Wedged renderers surface a clear error instead of pegging a core. (closes #16) - No more orphan Chrome processes. SIGTERM → 5 s → SIGKILL chain at shutdown. (closes #29)
- Browser launches on macOS Tahoe and Windows again. Auto-fallback to bundled Chromium when system Chrome refuses to start; force via
BROWSER_CHANNEL=chromium. (closes #13, #19) - Notebook library load no longer crashes. Safe accessors in
src/library/metadata.tsfor entries with missingtopics/use_cases/content_types. (closes #33) - Stdio is clean. Banner and all logs go to
stderr;node dist/index.js < /dev/nullproduces 0 bytes on stdout. (closes #40) - Better error message for unknown resource URIs — clients hitting
mcp://notebooklmget pointed atnotebooklm://library. (closes #15)
🚀 New capabilities
add_sourcetool — paste URLs or text into a notebook from an agent. ReturnssourceCountBefore/Afterso the call is verifiable. (closes #25)- Audio Overview workflow — async by design:
generate_audioreturns immediately withstatus: "started" | "in_progress" | "ready", pollget_audio_status, thendownload_audio. Idempotent — existing tiles are detected. (closes #11, audio scope; Video / Slides / Quiz / Infographic tracked for a follow-up) - Citations on
ask_question— newsource_formatarg (none|inline|footnotes|json). DOM-level extraction populates a structuredsources[]field. (closes #20) - Streamable-HTTP transport —
--transport http --port 3000 [--host 0.0.0.0]. RoutesPOST /mcpandGET /healthz, MCP-spec session-id header model. Built on the SDK'sStreamableHTTPServerTransport(no Express). (closes #4, #7) - Multi-account —
--account <name>flag (orNOTEBOOKLM_ACCOUNTenv). Each account gets an isolated Chrome profile under~/.local/share/notebooklm-mcp/accounts/<name>/. No credential storage. (closes #2) - Configurable answer timeout —
ANSWER_TIMEOUT_MSenv + per-callbrowser_options.timeout_ms. Default raised 120 s → 600 s. (closes #14, #27) - Provenance + AI-generated marker —
_provenanceenvelope onask_questionresults, prefix on the answer text, configurable viaNOTEBOOKLM_AI_MARKERandNOTEBOOKLM_AI_MARKER_PREFIX. Closes the host-agent trust-boundary gap for indirect prompt injection. (closes #42) FOLLOW_UP_REMINDERis opt-in now viaNOTEBOOKLM_FOLLOW_UP_REMINDER=true(default off). The previous append tripped prompt-injection guards on safety-trained host agents. (closes #28)get_audio_statustool — non-blocking probe that returnsready | in_progress | not_started. Pair with asyncgenerate_audioanddownload_audio.
🏗️ Architecture rewrite
Selector registry — a single file Google can break
All NotebookLM-facing CSS / aria selectors live in src/notebooklm/selectors.ts. UI changes from Google now require touching exactly one file. Anchors are class- and [role="*"]-based with Material-Symbols icon names as fallbacks; the modal anchor is [role="dialog"] (race-free vs. the .mdc-dialog--open animation class). The registry covers EN, DE, FR, ES, PT, IT, NL and JA NotebookLM locales.
Browser lifecycle as its own module
src/browser/browser-manager.tsowns launch / dispose, withprofileStrategy: auto | single | isolatedto fall back to an isolated per-instance profile when the base profile is lockedsrc/browser/chromium-fallback.tsfor the channel-failure → bundled-Chromium retrysrc/browser/watchdog.tsfor the bounded-poll + health-check pattern reused across chat extraction, citation extraction, and source ingestion
Session recovery
findChatInput() recovery: 2× Escape → URL clean → reload — fixes ask_question failing after add_source or after a citation source-panel was left open.
Source ingestion (src/notebooklm/sources.ts)
- Robust dialog open: sidebar button →
?addSource=trueURL fallback - Snapshot count after fill, before submit
- UUID-redirect detection for pasted-text uploads
- Dual-anchor
countSources()+ 90 s post-submit poll with[role="alert"]error surfacing
MCP-spec compliance
- Server-level
instructionsstring with cross-tool workflow guide — clients merge it into the system prompt automatically - Tool descriptions condensed to what + when;
annotations(readOnlyHint/destructiveHint/idempotentHint/openWorldHint/title) on every tool
⚠️ Migration notes (v1 → v2)
FOLLOW_UP_REMINDERis off by default. SetNOTEBOOKLM_FOLLOW_UP_REMINDER=trueto keep the old append.answerTimeoutMsdefault raised 120 s → 600 s. SetANSWER_TIMEOUT_MS=120000to keep the old fail-fast ceiling.- Answer text is now prefixed with the AI-generated marker by default. Set
NOTEBOOKLM_AI_MARKER=falseto disable (not recommended for host-agent safety). - Resource URI scheme is
notebooklm://…. Clients that built URLs starting withmcp://need to update. - v1 is no longer supported.
🧰 Tooling & DX
- ESLint flat config + Prettier;
npm run lint,npm run format,npm run check(format-check + lint + build in one) - Type-safe build with zero
as anycasts; DOM types enabled for in-page evaluations (lib: ["ES2022", "DOM", "DOM.Iterable"]) - Default viewport raised 1024×768 → 1920×1080 so NotebookLM doesn't drop into the mobile Studio layout
add_source,generate_audio,download_audio,get_audio_statusaccept ashow_browserflag for live debugging
📖 Docs
Full README rewrite plus refreshed docs/configuration.md, docs/tools.md, docs/troubleshooting.md, docs/usage-guide.md — covering install, client wiring (Claude Code, Cursor, Codex, generic), authentication, transports, multi-account, full tool list, profiles, citations, provenance, configuration, migration. WSL2 + WSLg is documented as supported; WSL1 is not. (closes #32, #8)
Stats: 47 files changed, 6 270 insertions(+), 1 712 deletions(−)
🙏 Acknowledgements
Several community PRs and reports shaped v2.0.0. Their ideas live on in the new code even where the final implementation took a different shape:
- @joaocarlos (#23) — diagnosed the 100 % CPU zombie-page loop and prototyped the bounded-poll + health-check pattern. Shipped as
src/browser/watchdog.ts. - @joaocarlos (#24) — DOM citation extraction. Shipped as
source_formatonask_question+src/notebooklm/citations.ts. - @Toryn02 (#44) — argued for an
ANSWER_TIMEOUT_MSenv var. Shipped exactly as proposed. - @leo-dower (#37) — surfaced the prompt-injection-flag conflict around
FOLLOW_UP_REMINDER. Shipped as opt-in (default off). - @dave-007 (#41) — Studio artifact generation via direct
batchexecuteRPC. Audio Overview shipped via browser automation in v2.0.0; the RPC notes will guide the rest of the Studio surface in a follow-up. - Plus every issue reporter whose precise repros made each fix traceable.
Thank you all 🙌
📦 Issue closeout — full v1 backlog cleared
Bugs fixed: #43 · #42 · #40 · #33 · #29 · #28 · #27 · #19 · #16 · #15 · #14 · #13
Features shipped: #25 · #20 · #11 · #8 · #7 · #4 · #2
Docs & housekeeping: #32 · #36
Won't fix (by design): #17 (browser automation is the design choice; direct batchexecute clients exist elsewhere)
Wrong project (Python notebooklm-mcp-server on PyPI): #21 · #30 · #34 · #35 · #38 · #39