github PleasePrompto/notebooklm-mcp v2.0.0
v2.0.0 — multilingual rewrite, async audio, MCP-spec descriptions

12 hours ago

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_question works again. v1.x has been timing out since NotebookLM removed div.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, periodic page.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.ts for entries with missing topics/use_cases/content_types. (closes #33)
  • Stdio is clean. Banner and all logs go to stderr; node dist/index.js < /dev/null produces 0 bytes on stdout. (closes #40)
  • Better error message for unknown resource URIs — clients hitting mcp://notebooklm get pointed at notebooklm://library. (closes #15)

🚀 New capabilities

  • add_source tool — paste URLs or text into a notebook from an agent. Returns sourceCountBefore/After so the call is verifiable. (closes #25)
  • Audio Overview workflow — async by design: generate_audio returns immediately with status: "started" | "in_progress" | "ready", poll get_audio_status, then download_audio. Idempotent — existing tiles are detected. (closes #11, audio scope; Video / Slides / Quiz / Infographic tracked for a follow-up)
  • Citations on ask_question — new source_format arg (none | inline | footnotes | json). DOM-level extraction populates a structured sources[] field. (closes #20)
  • Streamable-HTTP transport--transport http --port 3000 [--host 0.0.0.0]. Routes POST /mcp and GET /healthz, MCP-spec session-id header model. Built on the SDK's StreamableHTTPServerTransport (no Express). (closes #4, #7)
  • Multi-account--account <name> flag (or NOTEBOOKLM_ACCOUNT env). Each account gets an isolated Chrome profile under ~/.local/share/notebooklm-mcp/accounts/<name>/. No credential storage. (closes #2)
  • Configurable answer timeoutANSWER_TIMEOUT_MS env + per-call browser_options.timeout_ms. Default raised 120 s → 600 s. (closes #14, #27)
  • Provenance + AI-generated marker_provenance envelope on ask_question results, prefix on the answer text, configurable via NOTEBOOKLM_AI_MARKER and NOTEBOOKLM_AI_MARKER_PREFIX. Closes the host-agent trust-boundary gap for indirect prompt injection. (closes #42)
  • FOLLOW_UP_REMINDER is opt-in now via NOTEBOOKLM_FOLLOW_UP_REMINDER=true (default off). The previous append tripped prompt-injection guards on safety-trained host agents. (closes #28)
  • get_audio_status tool — non-blocking probe that returns ready | in_progress | not_started. Pair with async generate_audio and download_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.ts owns launch / dispose, with profileStrategy: auto | single | isolated to fall back to an isolated per-instance profile when the base profile is locked
  • src/browser/chromium-fallback.ts for the channel-failure → bundled-Chromium retry
  • src/browser/watchdog.ts for 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=true URL 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 instructions string 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_REMINDER is off by default. Set NOTEBOOKLM_FOLLOW_UP_REMINDER=true to keep the old append.
  • answerTimeoutMs default raised 120 s → 600 s. Set ANSWER_TIMEOUT_MS=120000 to keep the old fail-fast ceiling.
  • Answer text is now prefixed with the AI-generated marker by default. Set NOTEBOOKLM_AI_MARKER=false to disable (not recommended for host-agent safety).
  • Resource URI scheme is notebooklm://…. Clients that built URLs starting with mcp:// 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 any casts; 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_status accept a show_browser flag 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_format on ask_question + src/notebooklm/citations.ts.
  • @Toryn02 (#44) — argued for an ANSWER_TIMEOUT_MS env 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 batchexecute RPC. 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

Don't miss a new notebooklm-mcp release

NewReleases is sending notifications on new releases.