- Opt-in file upload directory allowlist —
NOTEBOOKLM_ALLOWED_FILE_DIRSrestricts local file uploads to approved directories (comma/OS-path-separator-delimited). Disabled by default (#260). Thanks to @failsafesecurity! - Opt-in download output directory —
NOTEBOOKLM_DOWNLOAD_DIRkeeps downloaded artifacts inside one approved directory, on top of the existing sensitive-directory protections. Disabled by default (#261). Thanks again to @failsafesecurity! - Rejected document uploads fail fast — Non-media files NotebookLM immediately rejects now fail on the first terminal status instead of waiting out the full processing timeout; the error includes the source ID and deletion guidance (#257). Thanks to @ericvael!
- Refreshed auth cookies persisted correctly — Rotated cookies are now saved together with refreshed CSRF/session tokens, so a successful refresh no longer leaves stale credentials on disk.
- Regular notes no longer misclassified as mind maps — Mind-map discovery now excludes ordinary saved notes (#258). Thanks to @hansschenker!
- Newer (type-4) Studio mind maps download correctly — Classified by subtype and downloaded as their embedded JSON instead of being treated as quizzes/flashcards (#258). Thanks again to @hansschenker!
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, mcps-audit, config-audit, skill-audit, mcp-exfil-scan
- 1 High dependency vulnerability found and fixed —
mcp1.27.0 → 1.28.1 (CVE-2026-52869, CVE-2026-52870, CVE-2026-59950; auth-bypass/task-access/WebSocket Origin-validation issues), confirmed by both Trivy and OSV-Scanner. Fixed viauv lock --upgrade-package mcp; full test suite (1150 tests) passes after the bump. - 0 secrets in git history (665 commits, 10.32 MB; Gitleaks + TruffleHog verified)
- 0 SAST findings in project source — Semgrep OWASP+Python+Secrets clean; Bandit 0 High/Medium in src/ (Medium findings confined to test fixtures)
- mcps-audit/skill-audit high scores reviewed, no fix needed — same known false-positive pattern as prior scans: heuristics flag the project's own CDP-based cookie-extraction scripts/docs as "dangerous execution", which is the tool's documented, intentional auth mechanism, not a real vulnerability
- Full report:
docs/security-scan-report-2026-07-17.md
- Opt-in MCP tool group gating — Restrict the tools exposed to your AI agent via the
NOTEBOOKLM_DISABLED_GROUPSenv var, saving significant context-window tokens for agents that only need a subset of functionality (#254). Thanks to @KoscheiiB! - Flaky Drive-source freshness test fixed — Resolved a race condition in the parallel freshness-check test suite (#255). Thanks to @KoscheiiB!
- Hardened CDP auth — Eliminated a redundant lock-reset in
cdp.pythat could prematurely close a newly opened WebSocket (PR #253). Thanks to @insane66613! - Test storage isolation — Added
conftest.pyautouse fixtures so tests can no longer silently overwrite real user credentials in~/.notebooklm-mcp-cli/auth.json(cherry-picked from PR #252).
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, skill-audit, mcp-exfil-scan
- 0 dependency vulnerabilities — Trivy + OSV-Scanner clean (88 packages; uv.lock unchanged)
- 0 secrets in git history (650 commits, 10.23 MB; Gitleaks + TruffleHog verified)
- 0 SAST findings in project source — Semgrep OWASP+Python+Secrets clean
- Medium findings reviewed, no fix needed — Bandit
hardcoded_tmp_directory/exec_usedflags are all in test fixtures (non-production); skill-audit's 75/100 score on the packaged skill doc is a pattern-matcher false positive (flags the words "credentials"/"silently infer" in this auth-CLI's own documentation, not an actual exfiltration or hidden-action vector) - Full report:
docs/security-scan-report-2026-07-11.md
- Experimental CDP RPC transport (
NOTEBOOKLM_RPC_TRANSPORT=cdp) — Routes batchexecute RPCs and notebook chat throughfetchinside the saved NotebookLM browser profile, so Chrome supplies live browser-bound cookies. Off by default; use only whennlm doctor auth-replayshowscdp_in_pagesucceeds but normal replay fails. Seedocs/AUTHENTICATION.md. - MCP
notebook_querycancellation crash fix — The query tool is nowasyncand dispatches blocking I/O to a thread viaanyio.to_thread.run_sync(abandon_on_cancel=True), so MCP client cancellation no longer leaves the server in an inconsistent state. execute_cdp_commandacceptsresponse_timeout— Configurable WebSocket wait for long-running in-page fetches (e.g. streamed notebook queries).find_existing_nlm_chromeacceptsinclude_headless— Interactive login keeps the existing strict default; the CDP transport passesTrueto reuse profile-owned headless browsers.
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, mcps-audit, config-audit, skill-audit, mcp-exfil-scan
- 0 dependency vulnerabilities — Trivy + OSV-Scanner clean (88 packages; uv.lock unchanged)
- 0 secrets in git history (638 commits, 10.21 MB; Gitleaks + TruffleHog verified)
- 0 SAST findings in project source — Semgrep OWASP+Python+Secrets clean; Bandit 0 High/Medium in src/
- 13 Low Bandit findings fixed —
# nosecwith justification on hardcoded, list-form (noshell=True) subprocess calls and best-effortexcept Exception: passblocks, following the project's existing convention - Full test suite (1080 tests) and
ruff check/ruff format --checkpass after fixes - Full report:
docs/security-scan-report-2026-07-07.md
nlm doctor auth-replaydiagnostic command — Compares saved-cookie replay throughhttpx,httpx+RotateCookies, and optional CDP fetch from saved Chrome profile. Gives actionable verdicts for auth issues (issue #248)- Best-effort Google
RotateCookiesduring token refresh — Attempts to rotate cookies before replay to keep auth fresh nlm login --checkvalidates redirects with a real RPC — Homepage redirects now confirmed withlist_notebooksbefore reporting cookies as expired — eliminates false-positive expiry reports (Fixes #250, @laofun)- Preserved raw Chrome cookie-list across auth checks — Duplicate cookies no longer clobber each other during auth checks (Fixes #249, @laofun)
- Preferred
.google.comdomain values when flattening duplicates — Prevents stale subdomain values from overriding the correct one
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, skill-audit, mcp-exfil-scan
- 0 dependency vulnerabilities — Trivy + OSV-Scanner clean (88 packages; uv.lock unchanged)
- 0 secrets in git history (634 commits, 10.49 MB; Gitleaks + TruffleHog verified)
- 0 SAST findings in project source — Semgrep OWASP+Python+Secrets clean; Bandit 0 High/Medium in src/
- 0 fixes needed — all scanner flags were false positives (see report)
- Full report:
docs/security-scan-report-2026-07-04.md
nlm login --checkcrash fix on slow accounts — Auth checks now use a lightweight homepage probe instead of the full notebook-list RPC; notebook counts fetched as best-effort. Connect-phase RPC failures retried safely without retrying read/write timeouts (Fixes #243, PR #245, @LesleyMurfin)- CDP reuse fix with foreign Chrome on port 9222 —
find_existing_nlm_chrome()now verifies mapped Chrome PIDs still own the NLM profile's--user-data-dirand--remote-debugging-port, skips headless automation browsers, clears stale port-map entries. Exact flag matching prevents prefix matches likechrome-profile-otheror port92222from being accepted (Fixes #244, PR #246, @syf2211)
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, mcp-exfil-scan, skillspector
- 0 dependency vulnerabilities — Trivy + OSV-Scanner clean (88 packages; uv.lock unchanged from prior upgrade)
- 0 secrets in git history (627 commits, 10 MB; Gitleaks + TruffleHog verified)
- 0 SAST findings in project source — Semgrep OWASP+Python+Secrets clean on src/; Bandit 0 High/Medium in src/
- 0 fixes needed — all Bandit High findings were in .venv (third-party), not project source
- Full report:
docs/security-scan-report-2026-07-02.md
- Short Video Overview format —
video_format="short"(CLI:nlm video create <id> --format short) generates NotebookLM's new ~60-second vertical "bite-sized" video format, announced by Google on 2026-06-30. Like Cinematic, Short rejects--style/--style-promptand maps those flags into--focus. Currently English-only, rolling out to Pro/Ultra accounts. - "Refactor with NotebookLM" workflow — new reference workflow in
docs/references/workflows.mdfor iteratively refactoring documents using NotebookLM as the editing loop (PR #239, @Grobiou) - Skill trigger update — SKILL.md gains a document-refactoring entry in the workflow tree
- Folds in v0.7.8 features: studio artifact source provenance (
source_ids), actionable file upload errors, regional audio locale docs, skill capability audit
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, skill-audit, mcp-exfil-scan, skillspector
- 0 dependency vulnerabilities — Trivy + OSV-Scanner clean (88 packages; lockfile carried forward from June security upgrades)
- 0 secrets in git history (622 commits, 10 MB; Gitleaks + TruffleHog verified)
- 0 SAST findings (Semgrep OWASP+Python+Secrets / 102 files; Bandit 0 High/Medium in src/)
- All scanner flags confirmed false positives — YARA info_stealer pattern matches legitimate Chrome CDP auth code by design
- Full report:
docs/security-scan-report-2026-07-01.md
- Studio artifact source provenance —
studio_statusnow returnssource_idsper artifact, letting you trace generated podcasts, videos, and slide decks back to their source documents (PR #240, @tonhuu96) - Actionable file upload errors — file source failures now surface the concrete reason and path hint instead of a generic "Could not add file source." message
- Regional audio accent locale docs —
esvses-US/es-419behavior for Audio Overviews documented indocs/API_REFERENCE.mdanddocs/CLI_GUIDE.md - Skill capability audit — SKILL.md and MCP reference docs brought in sync with the full 39-tool MCP surface
- fix(studio): nested artifact source ID parsing corrected for all artifact types
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, skill-audit, mcp-exfil-scan
- 6 HIGH fixed — cryptography 46.0.7→49.0.0 (GHSA-537c-gmf6-5ccf); python-multipart 0.0.26→0.0.32 (CVE-2026-42561, CVE-2026-53539); starlette 1.0.0→1.3.1 (CVE-2026-48818, CVE-2026-54283)
- 6 MEDIUM fixed — authlib 1.6.10→1.7.2 (CVE-2026-41425, CVE-2026-44681); idna 3.11→3.18 (CVE-2026-45409); pydantic-settings 2.13.1→2.14.2 (GHSA-4xgf-cpjx-pc3j); starlette (CVE-2026-48710, CVE-2026-48817)
- 5 LOW resolved automatically by the above upgrades
- 0 secrets in git history (618 commits, 10 MB; Gitleaks + TruffleHog verified)
- 0 SAST findings (Semgrep OWASP+Python+Secrets / 102 files / 688 rules; Bandit 0 High in src/)
- Trivy post-fix: 0 / OSV-Scanner: 0 ✅ (full report:
docs/security-scan-report-2026-06-21.md)
- Robust multi-probe AuthHealthChecker (#219) —
AuthHealthCheckernow runs multiple parallel probes and aggregates results; header fix prevents false-stale auth on valid cookies no_proxysanitization on import — prevents httpx crash on Windows whenno_proxyenv var contains invalid values- Profile-aware headless auth refresh (#223) — headless authentication refresh now uses the configured profile instead of always defaulting to the system default
- Modern Chrome profile DB path detection (#222) — automatically detects the current Chrome profile database path format, fixing auth on newer Chrome versions
- Unified MCP auth gates for semi-stale cookies (#224, #225) — auth checking logic unified across all MCP tools; semi-stale cookies no longer cause inconsistent behavior between
studio_create,refresh_auth, and other tools - CLI Scripting & Automation guide —
docs/CLI_GUIDE.mdgains a new Scripting & Automation section with pipeline patterns
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, mcp-exfil-scan
- 0 HIGH / 0 MEDIUM in project source — no fixes required
- 0 secrets in git history (595 commits, 9.97 MB; Gitleaks + TruffleHog verified, 0 verified/unverified)
- 0 SAST findings (Semgrep OWASP+Python+Secrets / 97 files / 341 rules)
- 0 dependency vulnerabilities (Trivy + OSV-Scanner over 89 packages in
uv.lock) - Bandit Medium findings in tests only: 74 B108 (hardcoded
/tmp/in test fixtures) — accepted; 1 B102 exec in test — false positive import check - Overall risk posture: Clean ✅ (full report:
docs/security-scan-report-2026-06-10.md)
- Studio fast-track 2-step pipeline —
studio_create()now supports a direct fast-track flow for agents, reducing round-trips for audio and video artifact creation - Cinematic video artifact type — new
artifact_type=videosupport instudio_create() - Short answer fix — conversation
type=1response chunks were silently dropped, causing one-word or incomplete answers fromnotebook_query. Now correctly captured and appended - Audio download retry propagation fix (PR by @responsiblefleet area) — retry logic in
core/download.pynow correctly propagates throughservices/downloads.py; failed downloads with retryable errors no longer swallow the retry signal --jsonoutput fix forformat_item—cli/formatters.pyformat_item()now handlesdictvalues correctly;nlm notebook list --jsonno longer crashes on notebooks with metadata fields- MCP HTTP 401/403 → "stale" not "unverified" —
mcp/tools/server.pyauth status mapping tightened; HTTP 401/403 from NotebookLM API now surfaces asstatus: "stale"with anlm loginhint instead of the misleading"unverified" - New
docs/GETTING_STARTED.md— migration guide for users coming from the old split packages - 8 new contributors added to README credits
- Studio prompting guides —
data/references/studio-prompt-examples.mdandstudio-prompting-guide.mdadded (786 lines of prompting patterns)
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, skill-audit, mcp-exfil-scan
- 1 HIGH fixed — pyjwt 2.12.1 → 2.13.0 (4 CVEs: PYSEC-2026-175/176/177/178/179, max CVSS 7.4);
pyproject.tomlminimum bumped to>=2.13.0 - 0 NEW HIGH / 0 MEDIUM in project source after fix
- 0 secrets in git history (Gitleaks + TruffleHog verified)
- 0 SAST findings (Semgrep OWASP+Python+Secrets)
- 5 Low (accepted, not fixed) — Bandit B603/B607/B110 in
utils/cdp.py(Chrome subprocess launch, intentional best-effort teardown) - Overall risk posture: Clean ✅ (full report:
docs/security-scan-report-2026-06-05.md)
nlm logincrash on expired auth fixed (PR #211, @insane66613) — when stored Google session was fully expired,_validate_saved_profile()raisedClientAuthenticationError(notNLMError), which bypassed theexcept NLMError:clause and exited before Chrome could launch for interactive sign-in. Fixed by also catchingClientAuthenticationErrorinlogin_callback- MCP silent auth/studio failures fixed (PR #212, @idankatz64-commits) — three related silent-failure bugs under stale auth: (1)
refresh_auth()returnedstatus: "success"after reloading dead tokens (now runs live check + returns"expired"withnlm loginhint); (2)studio_create()had no pre-flight auth check, returnedstatus: "success"with a doomed artifact_id (now checks auth before firing); (3)studio_status()surfacedstatus: "failed"with all fields null (now synthesizes a non-nullerror_reason). 12 new tests - Bounded in-process conversation history cache (Issue #213) — long-lived MCP servers would OOM due to unbounded conversation cache. Now bounded by three env-var knobs:
NOTEBOOKLM_CONVERSATION_MAX_TURNS(default 50),NOTEBOOKLM_CONVERSATION_MAX_CONVS(default 500),NOTEBOOKLM_CONVERSATION_MAX_CHARS_PER_TURN(default 100k). FIFO trim with renumber, LRU eviction. 13 new tests - Auth-guard stale-TTL window fixed — auth-guard now records mtime of all
profiles/*/cookies.jsonfiles and invalidates the 60s cache when any of them changes (not just the config-default profile). Fixes stale auth whennlm login --profile <other>is run externally. 5 new tests - Services layer is now a full auth shim — all 6 auth symbols (
check_auth,load_cached_tokens,save_tokens_to_cache,get_cache_path,validate_cookies,AuthTokens,AuthManager) route throughservices/auth.pyshim; cli/ and mcp/ no longer import directly fromcore/ ArtifactInfogainserror_reasonfield —Nonefor healthy artifacts; synthesized string for failed artifacts; verbatim from API if future API version exposes one. Backward-compatible- Auth check cache in studio —
studio_create()caches the auth check result to avoid per-call HTTP roundtrip overhead
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, skill-audit, mcp-exfil-scan
- 0 HIGH / 0 MEDIUM in project source — no fixes required
- 0 secrets in git history (567 commits, 9.48 MB; Gitleaks + TruffleHog verified, 0 verified/unverified)
- 0 SAST findings (Semgrep OWASP+Python+Secrets / 101–149 files / 342 rules)
- 0 dependency vulnerabilities (Trivy + OSV-Scanner over 89 packages in
uv.lock) - Bandit High findings: all 22 in
.venv/third-party libs (authlib, cryptography, dns, requests) — not project source - mcp-exfil-scan / mcps-audit / config-audit: all flagged findings are false positives — self-referential patterns in security scanner tools or user's global Claude config (out of project scope per APTS)
- Overall risk posture: Clean ✅
- TOCTOU-safe credential file creation (PR #205, @Amy-Ra-lph) — credential files (
auth.json,cookies.json,metadata.json, port map) were previously created with default permissions thenchmod'd to0o600, leaving a brief window where they were world-readable. Now useos.open()+os.fdopen()so the descriptor is created with0o600from the start - Debug log cookie redaction (PR #206) — sensitive cookie values are redacted from debug log output, preventing accidental token disclosure when
--debugis enabled - GitHub Actions pinned to full commit SHAs (PR #207, @Amy-Ra-lph) — all four workflow files now pin
actions/checkout,astral-sh/setup-uv,pypa/gh-action-pypi-publish, andsoftprops/action-gh-releaseto 40-character SHAs, preventing tag-drift supply chain attacks - HTTP/SSE external-bind enforcement —
notebooklm-mcp --transport http --host 0.0.0.0(andsse) now refuse to start unlessNOTEBOOKLM_ALLOW_EXTERNAL_BIND=1is set, preventing accidental cookie exposure on untrusted networks - Auth check consistency (PR #203, @derekszen) — unified MCP and CLI auth status paths under a single
check_auth()function with a typedAuthCheckResult(TDD refactor) terminate_chrome()null-safety + cookie key whitespace handling (PR #205) —_cached_wsreference captured before try block;.strip()added to cookie key parsing insave_auth_tokens- Exponential backoff for source reconciliation polling —
_reconcile_source()now uses 1s → 2s → 4s backoff (capped at 4s) instead of fixed 1s - File path canonicalization for uploads —
add_file()now calls.expanduser().resolve()so~/Documents/file.pdfand symlinks work correctly raw_responseremoved fromquery()return — unused field that would otherwise leak raw API response text into future log aggregators- Merge note — conflict in
save_tokens_to_cache()(core/auth.py): kept local's strictercache_path.parent.chmod(0o700)(SEC-002) and adopted upstream's TOCTOU-safeos.open(..., 0o600)for the file itself — strictest possible combination
- Netscape cookie parser fixes (PR #199, @pan-long) —
nlm login --manualcookie parser fixed:#HttpOnly_lines are no longer treated as comments and silently dropped (which dropped__Secure-1PSIDTS/__Secure-3PSIDTSand caused 401s), empty-value cookies are now parsed as""instead of skipped, and tab-containing values are joined defensively. 4 regression tests added - MCP
source_adddocs alignment (PR #197, @Premshay) —source_addtool docstring and globalSKILL.mdnow list all 18 supported file types (PDF, TXT, MD, DOCX, CSV, EPUB, MP3, M4A, WAV, AAC, OGG, OPUS, MP4, JPG, JPEG, PNG, GIF, WEBP); also documents image-source ingestion for the Studio video visual-crop pipeline
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, skill-audit, mcp-exfil-scan
- 0 HIGH / 0 MEDIUM in target repo — no fixes required
- 0 secrets in git history (553 commits, 9.39 MB; Gitleaks + TruffleHog verified)
- 0 SAST findings (Semgrep OWASP+Python+Secrets / 100 files / 342 rules across configs)
- 0 dependency vulnerabilities (Trivy + OSV-Scanner over 89 packages in
uv.lock) - 5 Low (accepted, not fixed) — Bandit B603/B110 patterns in
utils/cdp.py(Windowstaskkillcleanup, hardcoded args, intentional best-effortexcept: pass) - mcp-exfil-scan — all 11 reported hits are in
~/.claude/skills/*(user's global Claude config, out of scope per APTS scope-enforcement); 0 findings in target repo - Overall risk posture: Clean — recent merge actively reduces attack surface (TOCTOU fix, GHA SHA-pinning, external-bind guard, cookie redaction)
- False-negative errors on
source_add/research_importfixed (Issue #196, @mdshearer) — NotebookLM reuses gRPC error code3for both "accepted-pending" (async processing started) and genuine rejection. A new_reconcile_source()helper pollsget_notebook_sources_with_types()after a code 3/9 error to verify whether the source actually landed — returns success if found, re-raises the original error if not. Also fixes a double-submission bug where v1 (izAoDd) URL sources triggered a spurious v2 (ozz5Z) call. 12 new unit tests (875 total upstream) - Snap Chromium profile directory fixed (PR #195, @ildella) — Snap-confined Chromium can only write to
~/snap/<name>/common/; launching with the old--user-data-dirfailed withExit code 21. Snap browsers are now detected via/snap/in the resolved binary path and redirected to~/snap/chromium/common/notebooklm-mcp-cli/chrome-profiles/. Profile lock, headless auth, and cache cleanup are all snap-aware - Audio download 403 on cross-domain CDN fixed (PR #193, @responsiblefleet) — audio artifacts returned HTTP 403 from
lh3.google.combecause_download_urlinheritedSec-Fetch-Site: none. The fix mirrors Chrome'swindow.open()header shape —Sec-Fetch-Site: cross-site+Referer: https://notebooklm.google.com/on cross-domain downloads - Merge note — conflict in
cleanup_chrome_profile_cache()(cdp.py): adopted upstream's snap-aware_clean_profile_dir()helper while keeping local's stricter SEC-007_logger.debug(...)logging instead of a silentexcept: pass
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner
- 1 MEDIUM + 1 auth-bypass fixed —
idna3.11 → 3.16 (CVE-2026-45409, CVSS 6.9: crafted input toidna.encode());starlette0.50.0 → 1.0.1 (PYSEC-2026-161 / GHSA-86qp-5c8j-p5mr: Host header not validated → auth bypass on path-based auth via MCP HTTP transport). Re-scan: clean - 5 Low (accepted, not fixed) — Bandit B110
try/except/passin_reconcile_source(research.py:400,sources.py:104, intentional re-raise of original error) + B607/B603/B110 on the Windowstaskkillhelper (cdp.py:1038-1041, controlled input) - 0 secrets in git history (540 commits, 9.34 MB; Gitleaks + TruffleHog verified)
- 0 SAST findings (Semgrep OWASP+Python+Secrets / 95 files / 191 rules)
- 0 dependency vulnerabilities after fixes (OSV-Scanner over 89 packages in
uv.lock); verified by 862 passing tests - Overall risk posture: Clean after fixes (full report:
docs/security-scan-report-2026-05-23.md)
- Windows CDP authentication reliability (PR #192, @jonathanzhan1975) — unifies browser detection in
doctor.pyto matchcdp.py(Edge supported), reduces CDP port scan timeout 2s → 1s to prevent Windows blocking, addsCREATE_NEW_PROCESS_GROUPflag for Windows process isolation, disables Edge Startup Boost via--disable-features=msEdgeStartupBoost, introduces_kill_stale_nlm_browsersto clean zombie CDP processes, and improves_summarize_browser_startup_failureto log exit codes - Merge note — kept local's
# nosec B603justification on thesubprocess.Popen(args, **kwargs)call incdp.pywhile adopting upstream's newkwargs(Windowscreationflags) form - AGENTS.md — new upstream contributor guide (260 lines) added at repo root
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner
- 0 HIGH / 0 MEDIUM — clean
- 3 Low (accepted, not fixed) — all in newly merged
_kill_process()(utils/cdp.py:940-951): B607 partial pathtaskkill(Windows System32 built-in, not user-controlled), B603 subprocess call (hardcoded args + integer PID), B110try/except/pass(intentional "best effort" semantics, documented in docstring) - 0 secrets in git history (534 commits, 9.31 MB; Gitleaks + TruffleHog verified)
- 0 SAST findings (Semgrep OWASP+Python+Secrets / 101 files)
- 0 dependency vulnerabilities (Trivy + OSV-Scanner over 89 packages in
uv.lock) - Overall risk posture: Clean (full report:
docs/security-scan-report-2026-05-18.md)
- EPUB file upload support (PR #191, @mateogon) —
.epubfiles can now be uploaded as notebook sources - Hermes Agent support —
nlm skill install hermesinstalls the NotebookLM skill for NousResearch's Hermes Agent; respects$HERMES_HOME - Windows hardening — fixed false "tool not installed" warnings,
PermissionErrornow yields an actionableicaclshint instead of a traceback, and all file I/O specifiesencoding="utf-8"to preventUnicodeDecodeErroron cp1252 systems - CLI studio status mind maps (fix) —
nlm studio statusroutes through the service layer so mind maps appear in the output - Refactor — shared
is_tool_on_system()helper incli/utils.py;TOOL_CONFIGSnow uses a typedToolConfigTypedDict
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner
- 2 HIGH + 1 MEDIUM fixed —
urllib32.6.3 → 2.7.0 (CVE-2026-44431 CVSS 8.9 cross-origin header leak; CVE-2026-44432 CVSS 8.2 decompression-bomb bypass);authlib1.6.11 → 1.7.2 (CVE-2026-44681 CVSS 6.1 OIDC open redirect). Re-scan: clean - 3 Low fixed — Bandit B110
try/except/passretry loops incli/main.py+utils/cdp.pyannotated with# nosec B110+ justification - 0 secrets in git history (530 commits, 9.29 MB; Gitleaks + TruffleHog)
- 0 SAST findings (Semgrep OWASP+Python+Secrets / 101 files; Bandit 22,782 LOC — 0 issues after annotation)
- Overall risk posture: Clean after fixes (full report:
docs/security-scan-report-2026-05-14.md)
- Cited research source import (PR #188, @zxyasfas) — new feature to import cited sources from a research run directly back into the notebook (services/research.py + CLI/MCP wrappers + docs)
- Opaque throttle errors fixed (Issue #182) —
RPCError code=8(RESOURCE_EXHAUSTED) with aUserDisplayableErrorpayload now surfaces the human-readable message instead of the raw protobuf type URL; newResourceExhaustedError(RPCError)subclass; studio creation provides retry-specific hints - Cinematic
--style-prompthonored (Issue #183, @guia-matthieu) —--style-promptwith cinematic format now maps tocustom_instructions(web UI's "Customize Video Overview" field). Validation runs before source resolution; clearer error pointing to--focuswhen--style/--style-promptrejected - Login race-condition fix (Issue #181, v0.6.5) —
nlm loginand headless flows now use deterministic DOM polling forFdrFJe/ build label before extracting cookies, eliminating premature exit and "Authentication expired" - Docs — Google AI Ultra ($249/mo) added to tested tiers (PR #184)
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, skill-audit, mcp-exfil-scan
- 1 HIGH fixed —
python-multipart0.0.26 → 0.0.28 (CVE-2026-42561, GHSA-pp6c-gr5w-3c5g, CVSS 7.5: DoS via unbounded multipart part headers). Re-scan: clean - 0 secrets in git history (521 commits, 9.19 MB; Gitleaks + TruffleHog)
- 0 SAST findings (Semgrep OWASP+Python+Secrets / 101 files; Bandit 22,679 LOC — 2 Low retry-loop
try/except/passleft as-is) - Overall risk posture: Clean after fix (full report:
docs/security-scan-report-2026-05-10.md)
- Cross-domain artifact downloads (PR #180, @laofun) — Fixed an authentication bug where
OSID/__Secure-OSIDcookies leaked during cross-domain artifact downloads (e.g. redirects fromnotebooklm.google.comtolh3.googleusercontent.com), causingServiceLoginredirects and HTML login pages instead of the actual file._download_urlnow strips service-scoped cookies for external Google hosts while preserving other auth cookies - CI hygiene — manifest version aligned across
desktop-extension/manifest.json;cdp.pyreformatted to satisfy ruff format CI gate
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner
- 0 vulnerabilities in uv.lock (88 packages, Trivy + OSV-Scanner)
- 0 secrets in git history (512 commits, 9.16 MB; Gitleaks + TruffleHog)
- 0 SAST findings (Semgrep 542 rules / 101 files; Bandit 22,414 LOC)
- Overall risk posture: Clean — no fixes required (full report:
docs/security-scan-report-2026-05-05.md)
- CDP tab creation fallback (#175) —
nlm loginnow reuses an existing tab if CDPTarget.createTargetfails (e.g. in locked-down environments where new-tab creation is blocked by enterprise policy). The reuse path is consolidated into a single pass that picks the freshest existing page - GitHub Copilot setup target (#178, @whatnick) —
nlm setupnow supports--client github-copilot, installing the skill files into the GitHub Copilot config path
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog
- 0 vulnerabilities in uv.lock (Trivy fs)
- 0 secrets in git history (507 commits, 9.15 MB; Gitleaks + TruffleHog)
- 0 SAST findings (Semgrep 542 rules / 101 files; Bandit 22,409 LOC)
- Overall risk posture: Clean — no fixes required (full report:
docs/security-scan-report-2026-05-04.md)
- Login timeout fix (#174, @SKMKZP) —
is_logged_in()now parses URL hostname viaurlparse()instead of substring-matching the full URL, fixing post-sign-in false-negative when the redirect URL containsoriginal_referer=...accounts.google.com...in the query string - Headless browser hijacking fix —
find_any_existing_cdp_browser()now skips browsers whose User-Agent containsHeadlessChrome(e.g. Perplexity MCP), preventingnlm loginfrom silently hanging 5 minutes on an invisible browser - Silent login wait loop — CLI now emits "Still waiting for sign-in... (Ns elapsed)" every 30s during the login wait (combined with local SEC-007 transient-error logging in the merge resolution)
- Refactor — extracted
_fetch_cdp_version()helper to share/json/versionlogic betweenget_debugger_url()andfind_any_existing_cdp_browser()
- Label reorganize support — new
reorganize_labelsaction (core/service/MCP/CLI). Mode[1]reorganizes all sources (replaces all labels, requires confirm); mode[0]only labels sources not yet categorized._require_notebook_id()helper extracted to deduplicate validation.docs/API_REFERENCE.mdupdated with both modes
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner
- 0 vulnerabilities in uv.lock (88 packages, Trivy + OSV-Scanner)
- 0 secrets in git history (501 commits, 9.13 MB; Gitleaks + TruffleHog)
- 0 SAST findings (Semgrep 542 rules / 101 files; Bandit 22,312 LOC)
- Overall risk posture: Clean — no fixes required
- Source Label Management — organize notebook sources into thematic categories with the new
labelMCP tool andnlm labelCLI commands. Actions:auto(AI-generated labels),list,create,rename,set_emoji,move_source,delete. Multi-label assignment supported (≥5 sources required for auto-labeling) - EOF on initialization fix (v0.5.31, Issue #171) —
_StdoutToStderrWrapperinserver.pyredirects stray text output to stderr so the stdio JSON-RPC channel stays clean (fixes EOF crashes on Windows/macOS) - WSL firewall encoding fix (PR #172, @andrepreira) —
check_firewall_rule()now handles UTF-16-LE PowerShell output, eliminating the false firewall warning duringnlm login --wsl
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner
- 0 vulnerabilities in uv.lock (88 packages scanned by Trivy + OSV-Scanner)
- 0 secrets in git history (495 commits, Gitleaks + TruffleHog)
- 0 SAST findings (Semgrep on 101 Python files, 191 rules; Bandit on
src/+scripts/) - Overall risk posture: Clean — no fixes required
- Stale
NOTEBOOKLM_COOKIESauth loop fix (Issue #170) —refresh_authnow returns an actionable error whenNOTEBOOKLM_COOKIESenv var is set, instead of silently returning false success; auth failure messages now mention the env var as the likely cause - Deprecated env vars removed —
NOTEBOOKLM_CSRF_TOKENandNOTEBOOKLM_SESSION_IDare no longer read; both values are auto-extracted and stale env vars would bypass auto-refresh - Auth troubleshooting docs — new section in
docs/AUTHENTICATION.mdcovering the env var auth trap
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, skill-audit, mcp-exfil-scan
- 0 vulnerabilities in uv.lock (88 packages scanned by Trivy + OSV-Scanner)
- 0 secrets in git history (489 commits, Gitleaks + TruffleHog)
- 0 SAST findings (Semgrep OWASP/Python/Secrets, Bandit src/)
- Suppressed 2 confirmed Bandit false positives with
# nosecannotations (B105in_utils.py,B110insources.py) - Overall risk posture: Clean
- Source
--titlefix (PR #162, @CryptoWombat) — adding a file source vianlm add file --titlenow honours the custom title; race condition onwait=Truealso fixed - Restore skill targets (Issue #163) —
codexandgemini-cliskill targets restored; Alef Agent-specific frontmatter added
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, mcp-exfil-scan
- python-dotenv upgraded 1.2.1 → 1.2.2 — fixes CVE-2026-28684 / GHSA-mf9w-mj56-hr94 (Medium, CVSS 6.6)
- Overall risk posture: Clean — 0 vulnerabilities after fix, 0 secrets in git history, 0 SAST findings
- See docs/security-scan-report-2026-04-22.md for full report
- MCP auth auto-reload (Issue #161) — MCP client now reloads automatically when cached tokens on disk are newer than the in-memory client; no more manual server restarts after
nlm login server_infoauth status (Issue #160) —server_infotool now returnsauth_statuswith local token presence and age- CLI Rich Windows fix (Issue #156 follow-up, @argonaut-cm) — all CLI Rich output now routes through
make_console();Formatterdefault uses correct console instance on Windows
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, skill-audit, mcp-exfil-scan
- authlib upgraded 1.6.9 → 1.6.11 — fixes GHSA-jj8c-mmj3-mmgv (Medium, CVSS 5.4)
- Bandit suppression — added
# nosecannotations for type-narrowing asserts, optional mind-map exception, and WSL fixed-path subprocess calls; src/ now 0 issues at all severity levels - See docs/security-scan-report-2026-04-18.md for full report
- Audio download CDN fix (Issue #158) — prefers
-dvdownload variant URL (~3 MB/s CDN) over streaming transcode URL (~30 KB/s); 47 MB file downloads in ~15s - CDP WebSocket proxy bypass (Issue #119, PR #157) —
nlm loginno longer breaks whenHTTP_PROXY/HTTPS_PROXYare set (Clash, Surge, etc.); proxy env vars are cleared around localhost CDP connections - Windows UTF-8 fix (Issue #156) — MCP server no longer crashes with
UnicodeEncodeErroron Windows cp1252 consoles when NotebookLM returns Unicode characters like→; stdout/stderr reconfigured to UTF-8 at startup - Lazy-load
NotebookLMClient— deferred import keeps stdio encoding bootstrap lightweight - CI release gate — new workflow validates all version strings are aligned before release
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, skill-audit, mcp-exfil-scan
- Overall risk posture: Clean — 0 vulnerabilities in 88 packages (Trivy + OSV-Scanner), 0 secrets in git history (Gitleaks + TruffleHog), 0 SAST findings (Semgrep + Bandit)
- See docs/security-scan-report-2026-04-16.md for full report
- HTTP 400 as auth failure (Issue #147) — Google returns 400 when CSRF token expires instead of 401/403; now triggers Layer-1 auth recovery instead of raw traceback
- Chromium auth resilience (PR #144) — improved stability; removed Firefox login support
- Source alias autodetect fix (Issue #145) — fixed alias detection using legacy client method that no longer exists
- REPL source counts fix — startup banner now shows correct source count
- Audio status=2 readiness — audio with status=2 + media URLs correctly reported as "ready"
- Studio audio URL extraction — uses media list for audio artifacts; falls back to legacy direct slot
- Full automated scan post-merge: Gitleaks, Bandit, Semgrep (OWASP/Python/Secrets), Trivy, TruffleHog, OSV-Scanner, config-audit, skill-audit, mcp-exfil-scan
- Overall risk posture: Clean — 0 vulnerabilities in Trivy after upgrade, 0 secrets in git history
- 12 CVEs resolved across 6 packages (2 Critical, 7 High, 3 Medium/Low)
diskcacheandlupa(unfixable CVEs) removed as transitive deps via fastmcp 3.x upgrade
- authlib upgraded 1.6.6 → 1.6.9 — fixes CVE-2026-27962 (CRITICAL: JWK Header Injection auth bypass), CVE-2026-28490 (HIGH: JWE padding oracle), CVE-2026-28498 (HIGH: forged OpenID Connect tokens), CVE-2026-28802 (HIGH: JWT signature verification bypass)
- fastmcp upgraded 2.14.2 → 3.2.3 — fixes CVE-2026-32871 (CRITICAL: SSRF/Path Traversal), CVE-2026-27124 (HIGH: OAuth confused deputy), CVE-2025-64340 (MEDIUM: Gemini CLI command injection); also removes
diskcache(CVE-2025-69872) andlupa(CVE-2026-34444) transitive deps - cryptography upgraded 46.0.3 → 46.0.7 — fixes CVE-2026-26007 (HIGH: SECT curve subgroup attack), CVE-2026-39892 (MEDIUM), CVE-2026-34073 (LOW: DNS constraint bypass)
- pyjwt upgraded 2.10.1 → 2.12.1 — fixes CVE-2026-32597 (HIGH: accepts unknown
critheader extensions) - python-multipart upgraded 0.0.21 → 0.0.26 — fixes CVE-2026-24486 (HIGH: arbitrary file write via path traversal)
- requests upgraded 2.32.5 → 2.33.1 — fixes CVE-2026-25645 (MEDIUM: predictable temp file)
- jaraco-context upgraded 6.0.2 → 6.1.2 — fixes GHSA-58pv-8j8x-9vj2 (HIGH, CVSS 8.6)
- pygments upgraded 2.19.2 → 2.20.0 — fixes CVE-2026-4539 (LOW: regex DoS in AdlLexer)
- WSL2 authentication support (
nlm login --wsl) — launches Windows Chrome from WSL2 with automatic firewall management and CDP cross-boundary communication (PR #138) - Thread-safety for concurrent MCP tool calls —
threading.LockinBaseClientprotects mutable state from race conditions during parallel tool invocations (PR #135) - Auto-import for research —
nlm research start --auto-importwaits for research to finish and immediately imports results (v0.5.19) - Deep Research task ID fix (Issue #140) — resolved task ID mutation causing import failures
- Verb-first CLI parity — 13 missing parameters restored across
nlm create,nlm add,nlm describe,nlm query,nlm deletecommands (Issue #141/#142) - fastmcp widened to
>=3.2.0,<4.0— resolves startup crash withfakeredis 2.35.0(Issue #141) - WSL2 doctor diagnostics —
nlm doctornow detects WSL2 environments and reports Chrome/firewall status - gRPC error code mapping — codes 5, 7, 16 now show
NOT_FOUND,PERMISSION_DENIED, etc. instead of "unknown"
notebooklm-cli.skilladded — install this skill in Claude Code for AI-assistednlmCLI workflows (auth, notebooks, sources, studio generation, research, batch operations, and more)- Skill covers all 10 artifact types with format/style options, 4 common end-to-end workflows, and error recovery guidance
- Enterprise/Workspace configurable base URL support
- Auth recovery fixes + CDP proxy bypass fix
- Python 3.13 compatibility fix
research_statuspolling loop (poll_interval,max_wait)- Async query polling fix (Issue #125)
- URL source dual RPC fallback (Issue #121)
- PEP 735 dev dependency group migration
Programmatic access to Google NotebookLM — via command-line interface (CLI) or Model Context Protocol (MCP) server.
Note: Tested with Pro/free and Google AI Ultra ($249/mo) tier accounts. May work with NotebookLM Enterprise accounts but has not been tested.
☕ If you find notebooklm-mcp-cli useful, consider buying me a coffee. It's free and built in my spare time — but testing every NotebookLM feature takes real time and resources. A coffee helps me cover it and keep shipping. Thank you! 🙏
📺 Watch the Demos
| Codex Setup + Cinematic Video & Slides |
|---|
![]() |
| General Overview | Claude Desktop | Perplexity Desktop | MCP Super Assistant |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
| CLI Overview | CLI, MCP & Skills | Setup, Doctor & mcpb | Infographics Support |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
Use nlm directly in your terminal for scripting, automation, or interactive use:
nlm notebook list # List all notebooks
nlm notebook create "Research Project" # Create a notebook
nlm source add <notebook> --url "https://..." # Add sources
nlm audio create <notebook> --confirm # Generate podcast
nlm download audio <notebook> <artifact-id> # Download audio file
nlm share public <notebook> # Enable public linkRun nlm --ai for comprehensive AI-assistant documentation.
Connect AI assistants (Claude, Gemini, Cursor, etc.) to NotebookLM:
# Automatic setup — picks the right config for each tool
nlm setup add claude-code
nlm setup add gemini
nlm setup add github-copilot
nlm setup add cursor
nlm setup add cline
nlm setup add antigravity
# Generate JSON config for any other tool
nlm setup add jsonThen use natural language: "Create a notebook about quantum computing and generate a podcast"
| Capability | CLI Command | MCP Tool |
|---|---|---|
| List notebooks | nlm notebook list |
notebook_list |
| Create notebook | nlm notebook create |
notebook_create |
| Add Sources (URL, Text, Drive, File) | nlm source add |
source_add |
| Query notebook (persists to web UI) | nlm notebook query |
notebook_query |
| Create Studio Content (Audio, Video, etc.) | nlm studio create |
studio_create |
| Revise slide decks | nlm slides revise |
studio_revise |
| Download artifacts | nlm download <type> |
download_artifact |
| Web/Drive research | nlm research start |
research_start |
| Share notebook | nlm share public/invite |
notebook_share_* |
| Sync Drive sources | nlm source sync |
source_sync_drive |
| Batch operations | nlm batch query/create/delete |
batch |
| Cross-notebook query | nlm cross query |
cross_notebook_query |
| Pipelines (multi-step workflows) | nlm pipeline run/list |
pipeline |
| Tag & smart select | nlm tag add/list/select |
tag |
| Configure AI tools | nlm setup add/remove/list |
— |
| Install AI Skills | nlm skill install/update |
— |
| Diagnose issues | nlm doctor |
— |
📚 More Documentation:
- Getting Started — Install, login, agent setup, and migration from another NotebookLM MCP
- CLI Guide — Complete command reference
- MCP Guide — All 35 MCP tools with examples
- Authentication — Setup and troubleshooting
- Remote MCP — Web/mobile connector feasibility, security, and authentication limitations
- API Reference — Internal API docs for contributors
This MCP and CLI use internal APIs that:
- Are undocumented and may change without notice
- Require cookie extraction from your browser (I have a tool for that!)
Use at your own risk for personal/experimental purposes.
🆕 Claude Desktop users: Download the extension (
.mcpbfile) → double-click → done! One-click install, no config needed.
Install from PyPI. This single package includes both the CLI and MCP server:
uv tool install notebooklm-mcp-cliuvx --from notebooklm-mcp-cli nlm --help
uvx --from notebooklm-mcp-cli notebooklm-mcppip install notebooklm-mcp-clipipx install notebooklm-mcp-cliAfter installation, you get:
nlm— Command-line interfacenotebooklm-mcp— MCP server for AI assistants
Alternative: Install from Source
# Clone the repository
git clone https://github.com/jacob-bd/notebooklm-mcp-cli.git
cd notebooklm-mcp
# Install with uv
uv tool install .# Using uv
uv tool upgrade notebooklm-mcp-cli
# Using pip
pip install --upgrade notebooklm-mcp-cli
# Using pipx
pipx upgrade notebooklm-mcp-cliAfter upgrading, restart your AI tool to reconnect to the updated MCP server:
- Claude Code: Restart the application, or use
/mcpto reconnect - Cursor: Restart the application
- Gemini CLI: Restart the CLI session
If you previously installed the separate CLI and MCP packages, you need to migrate to the unified package.
uv tool list | grep notebooklmLegacy packages to remove:
| Package | What it was |
|---|---|
notebooklm-cli |
Old CLI-only package |
notebooklm-mcp-server |
Old MCP-only package |
# Remove old CLI package (if installed)
uv tool uninstall notebooklm-cli
# Remove old MCP package (if installed)
uv tool uninstall notebooklm-mcp-serverAfter removing legacy packages, reinstall to fix symlinks:
uv tool install --force notebooklm-mcp-cliWhy
--force? When multiple packages provide the same executable,uvcan leave broken symlinks after uninstalling. The--forceflag ensures clean symlinks.
uv tool list | grep notebooklmYou should see only:
notebooklm-mcp-cli v0.2.0
- nlm
- notebooklm-mcp
Your existing cookies should still work, but if you encounter auth issues:
nlm loginNote: MCP server configuration (in Claude Code, Cursor, etc.) does not need to change — the executable name
notebooklm-mcpis the same.
If you are setting up the tool for the first time — or migrating from a browser-based NotebookLM MCP — see the Getting Started Guide. It covers install, login, agent registration, and a step-by-step migration path that avoids the "two NotebookLM servers registered" trap.
To completely remove the MCP:
# Using uv
uv tool uninstall notebooklm-mcp-cli
# Using pip
pip uninstall notebooklm-mcp-cli
# Using pipx
pipx uninstall notebooklm-mcp-cli
# Remove cached auth tokens and data (optional)
rm -rf ~/.notebooklm-mcp-cliAlso remove from your AI tools:
nlm setup remove claude-code
nlm setup remove cursor
# ... or any configured toolBefore using the CLI or MCP, you need to authenticate with NotebookLM:
# Auto mode: launches your browser, you log in, cookies extracted automatically
nlm login
# Check if already authenticated
nlm login --check
# Use a named profile (for multiple Google accounts)
nlm login --profile work
nlm login --profile personal
# Manual mode: import cookies from a file
nlm login --manual --file cookies.txt
# External CDP provider (e.g., OpenClaw-managed browser)
nlm login --provider openclaw --cdp-url http://127.0.0.1:18800Profile management:
nlm login --check # Show current auth status
nlm login switch <profile> # Switch the default profile
nlm login profile list # List all profiles with email addresses
nlm login profile delete <profile> # Delete a profile
nlm login profile rename <old> <new> # Rename a profileEach profile gets its own isolated browser session, so you can be logged into multiple Google accounts simultaneously.
If you only need the MCP server (not the CLI):
nlm login # Auto mode (launches browser)
nlm login --manual # Manual file modeHow it works: Auto mode launches a dedicated browser profile (supports Chrome, Arc, Brave, Edge, Chromium, and more), you log in to Google, and cookies are extracted automatically. Your login persists for future auth refreshes.
Prefer a specific browser? Set it with nlm config set auth.browser chromium (or brave, arc, edge, chrome, etc.). Falls back to auto-detection if the preferred browser is not found.
For detailed instructions and troubleshooting, see docs/AUTHENTICATION.md.
⚠️ Context Window Warning: This MCP provides 39 tools. Disable it when not using NotebookLM to preserve context. In Claude Code:@notebooklm-mcpto toggle. To keep it on but expose only a subset, see Selective tool exposure.
Use nlm setup to automatically configure the MCP server for your AI tools — no manual JSON editing required:
# Add to any supported tool
nlm setup add claude-code
nlm setup add claude-desktop
nlm setup add gemini
nlm setup add github-copilot
nlm setup add cursor
nlm setup add windsurf
# Generate JSON config for any other tool
nlm setup add json
# Check which tools are configured
nlm setup list
# Diagnose installation & auth issues
nlm doctorInstall the NotebookLM expert guide for your AI assistant to help it use the tools effectively. Supported for Cline, Antigravity, OpenClaw, Codex, OpenCode, Claude Code, and Gemini CLI.
# Install skill files
nlm skill install cline
nlm skill install openclaw
nlm skill install codex
nlm skill install antigravity
# Update skills
nlm skill updatenlm setup remove claude-codeIf you don't want to install the package, you can use uvx to run on-the-fly:
# Run CLI commands directly
uvx --from notebooklm-mcp-cli nlm setup add cursor
uvx --from notebooklm-mcp-cli nlm loginFor tools that use JSON config, point them to uvx:
{
"mcpServers": {
"notebooklm-mcp": {
"command": "uvx",
"args": ["--from", "notebooklm-mcp-cli", "notebooklm-mcp"]
}
}
}Manual Setup (if you prefer)
Tip: Run
nlm setup add jsonfor an interactive wizard that generates the right JSON snippet for your tool.
Claude Code / Gemini CLI support adding MCP servers via their own CLI:
claude mcp add --scope user notebooklm-mcp notebooklm-mcp
gemini mcp add --scope user notebooklm-mcp notebooklm-mcpCursor / Windsurf resolve commands from your PATH, so the command name is enough:
{
"mcpServers": {
"notebooklm-mcp": {
"command": "notebooklm-mcp"
}
}
}| Tool | Config Location |
|---|---|
| Cursor | ~/.cursor/mcp.json |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
GitHub Copilot (VS Code workspace) uses .vscode/mcp.json with a top-level servers key:
{
"servers": {
"notebooklm-mcp": {
"command": "notebooklm-mcp",
"args": []
}
}
}Claude Desktop may not resolve PATH — use the full path to the binary:
{
"mcpServers": {
"notebooklm-mcp": {
"command": "/full/path/to/notebooklm-mcp"
}
}
}Find your path with: which notebooklm-mcp
| Tool | Config Location |
|---|---|
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json |
| GitHub Copilot | .vscode/mcp.json |
📚 Full configuration details: MCP Guide — Server options, environment variables, HTTP transport, and context window management. For Claude web/mobile and public deployment, read Remote MCP Deployment first.
Simply chat with your AI tool (Claude Code, Cursor, Gemini CLI) using natural language. Here are some examples:
- "List all my NotebookLM notebooks"
- "Create a new notebook called 'AI Strategy Research'"
- "Start web research on 'enterprise AI ROI metrics' and show me what sources it finds"
- "Do a deep research on 'cloud marketplace trends' and import the top 10 sources"
- "Search my Google Drive for documents about 'product roadmap' and create a notebook"
- "Add this URL to my notebook: https://example.com/article"
- "Add this YouTube video about Kubernetes to the notebook"
- "Add my meeting notes as a text source to this notebook"
- "Import this Google Doc into my research notebook"
- "What are the key findings in this notebook?"
- "Summarize the main arguments across all these sources"
- "What does this source say about security best practices?"
- "Get an AI summary of what this notebook is about"
- "Configure the chat to use a learning guide style with longer responses"
(All queries sent from CLI or MCP automatically persist in your NotebookLM web UI chat history!)
- "Create an audio podcast overview of this notebook in deep dive format"
- "Generate a video explainer with classic visual style"
- "Make a short vertical video overview of the key idea"
- "Make a briefing doc from these sources"
- "Create flashcards for studying, medium difficulty"
- "Generate an infographic in landscape orientation with professional style"
- "Build a mind map from my research sources"
- "Create a slide deck presentation from this notebook"
- "Check which Google Drive sources are out of date and sync them"
- "Show me all the sources in this notebook with their freshness status"
- "Delete this source from the notebook"
- "Check the status of my audio overview generation"
- "Show me the sharing settings for this notebook"
- "Make this notebook public so anyone with the link can view it"
- "Disable public access to this notebook"
- "Invite user@example.com as an editor to this notebook"
- "Add a viewer to my research notebook"
Pro tip: After creating studio content (audio, video, reports, etc.), poll the status to get download URLs when generation completes.
| Component | Duration | Refresh |
|---|---|---|
| Cookies | ~2-4 weeks | Auto-refresh via headless browser (if profile saved) |
| CSRF Token | ~minutes | Auto-refreshed on every request failure |
| Session ID | Per MCP session | Auto-extracted on MCP start |
v0.1.9+: The server now automatically handles token expiration:
- Refreshes CSRF tokens immediately when expired
- Reloads cookies from disk if updated externally
- Runs headless browser auth if profile has saved login
You can also call refresh_auth() to explicitly reload tokens.
If automatic refresh fails (Google login fully expired), run nlm login again.
For suspected browser-bound auth replay failures, run nlm doctor auth-replay.
If the cdp_in_page probe succeeds while normal replay fails, see
Experimental browser-backed RPC transport.
Symptoms:
- Running
uv tool upgrade notebooklm-mcp-cliinstalls an older version (e.g., 0.1.5 instead of 0.1.9) uv cache cleandoesn't fix the issue
Why this happens: uv tool upgrade respects version constraints from your original installation. If you initially installed an older version or with a constraint, upgrade stays within those bounds by design.
Fix — Force reinstall:
uv tool install --force notebooklm-mcp-cliThis bypasses any cached constraints and installs the absolute latest version from PyPI.
Verify:
uv tool list | grep notebooklm
# Should show: notebooklm-mcp-cli v0.1.9 (or latest)- Rate limits: Free tier has ~50 queries/day
- No official support: API may change without notice
- Cookie expiration: Need to re-extract cookies every few weeks
See CLAUDE.md for detailed API documentation and how to add new features.
Full transparency: this project was built by a non-developer using AI coding assistants. If you're an experienced Python developer, you might look at this codebase and wince. That's okay.
The goal here was to scratch an itch - programmatic access to NotebookLM - and learn along the way. The code works, but it's likely missing patterns, optimizations, or elegance that only years of experience can provide.
This is where you come in. If you see something that makes you cringe, please consider contributing rather than just closing the tab. This is open source specifically because human expertise is irreplaceable. Whether it's refactoring, better error handling, type hints, or architectural guidance - PRs and issues are welcome.
Think of it as a chance to mentor an AI-assisted developer through code review. We all benefit when experienced developers share their knowledge.
Special thanks to:
- Le Anh Tuan (@latuannetnam) for contributing the HTTP transport, debug logging system, and performance optimizations.
- David Szabo-Pele (@davidszp) for the
source_get_contenttool and Linux auth fixes. - saitrogen (@saitrogen) for the research polling query fallback fix.
- devnull03 (@devnull03) for multi-browser CDP authentication support (Arc, Brave, Edge, Chromium, Vivaldi, Opera).
- VooDisss (@VooDisss) for multi-browser authentication improvements.
- codepiano (@codepiano) for the configurable DevTools timeout for the auth CLI.
- Tony Hansmann (@997unix) for contributing the
nlm setupandnlm doctorcommands and CLI Guide documentation. - Fabiana Furtado (@fabianafurtadoff) for batch operations, cross-notebook query, pipelines, and smart select/tagging (PR #90).
- Amy-Ra-lph (@Amy-Ra-lph) for security hardening: TOCTOU-safe credential storage, sensitive cookie redaction from debug logs, and pinning all CI actions to full commit SHAs (PRs #205–207).
- Kyle Brodeur (@kylebrodeur) for WSL2 authentication support with Windows Chrome integration (PR #138).
- Robiton (@Robiton) for enterprise NotebookLM support via configurable base URL (PR #114).
- pjeby (@pjeby) for connection pooling and fast startup improvements (PR #54).
- beausea (@beausea) for making the interface language configurable via the
NOTEBOOKLM_HLenvironment variable (PR #59). - JumpLao (@JumpLao) for extended audio, video, and image format support (PR #82).
- cbruyndoncx (@cbruyndoncx) for including
cited_textpassages in query output (PR #81). - zxyasfas (@zxyasfas) for cited-only research import (PR #188).
- Serdar Akın (@SERDAR-AKIN) for the multi-probe
AuthHealthCheckerthat fixes false"stale"reports for semi-stale cookies (PR #219).









