Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
[Unreleased]
[0.7.2] - 2026-06-08
Added
- ChatGPT File Parameter Upload Bridge (PR #220) — Enables direct upload of files provided by ChatGPT App/Action clients by resolving and downloading from the client's temporary HTTPS URL before uploading to Google NotebookLM. Thanks to @insane66613!
- ChatGPT Artifact Download Bridge (PR #220) — Allows copying generated artifacts to the local server's public directory and returning public download links when the server runs behind secure tunnels. Exposes a new
/artifacts/{filename}route in the MCP HTTP server. Thanks to @insane66613! - Transient Source Content Polling (
poll_source_contentservice function) — Automatically handles Google NotebookLM indexing states (processing, indexing, try again) via robust polling with exponential backoff when fetching raw source contents immediately after creation.
Fixed
- Sanitize
no_proxyenvironment variable (PR #221) — Fixed package import crashes on Windows systems by cleaning up theno_proxyenvironment variable on initialization beforehttpxparses it. Thanks to @insane66613! - Modern Chrome Cookie DB path detection (PR #222) — Improved the SQLite cookie database location search logic for Google Chrome to work correctly with modern Chrome setups. Thanks to @insane66613!
- Profile-aware headless refresh (PR #223) — Fixed headless login refresh to use the default/active profile configured in the CLI configuration file instead of falling back. Thanks to @insane66613!
AuthHealthCheckerAPI fallback passed wrong cookie format, causing falsestaleon semi-stale sessions (PR #225) — The API fallback flattenedprofile.cookiesto a dict, dropping domain-specific duplicates and omittingsession_id/build_label. The API probe now passesprofile.cookiesunchanged with all session fields, matchingnlm login --check. Thanks to @insane66613!server_info,refresh_auth, andstudio_createdisagreed on semi-stale auth (PR #225, Fixes #224) — These three MCP paths each ran independent auth checks, soserver_infocould reportstaleandstudio_createrefuse to run whilenotebook_listand CLI tools worked fine. All MCP auth gates now sharecredentials_are_usable()(AuthHealthChecker+ live API confirmation), eliminating split-brain results. Thanks to @insane66613!
[0.7.1] - 2026-06-06
Fixed
server_inforeported"stale"for valid semi-stale cookies (PR #219) — Google enforces different session lifecycles for the NotebookLM homepage (a navigation endpoint) and the RPC API endpoints. Cookies that are "semi-stale" — rejected by the homepage with a redirect toaccounts.google.com, but still 100% accepted by the RPC API — were causing the MCPserver_infotool (andnlm login --check) to falsely report"stale"even though every actual API tool would work fine. The newAuthHealthCheckerruns a homepage probe first and, onexpired/http_401/http_403, falls back to a liveNotebookLMClient.list_notebooks()call before deciding. The homepage headers were also upgraded to use the full browser-like_PAGE_FETCH_HEADERS(includingSec-Fetch-Dest/Sec-Fetch-Mode/Sec-Fetch-Site/Sec-Fetch-User) — without them Google was bot-detecting the homepage check and redirecting even fresh cookies, producing false"stale"reports on first probe. Results are cached for 30 seconds with mtime-based bypass, so an externalnlm loginis reflected without waiting for the TTL. The CLI and MCP now share the cache via theget_auth_health_checker()singleton inservices/auth.py. Thanks to @SERDAR-AKIN for the original multi-probe design and PR #219!
Changed
AuthHealthCheckerlives inservices/auth.py, notcore/auth.py— the multi-probe orchestration, 30-second cache, and verdict aggregation are business logic and belong in the services layer per the layering rule inCLAUDE.md/AGENTS.md/GEMINI.md.core/auth.pystays focused on the low-level auth primitives (AuthManager,AuthTokens,check_auth,save_tokens_to_cache,load_cached_tokens,_fetch_notebooklm_homepage).server_infodocstring no longer callsauth_statusa "live check" — it is cached for 30 seconds with mtime-based bypass.docs/AUTHENTICATION.mddocuments the same contract fornlm login --check(always live) vsserver_info(cached).AuthHealthReport.validis nowverdict == "configured"(was!=) — the field was inverted: it returnedTrueforstale/unverified/not_configuredreports. Pinned byTestReportValidintests/services/test_auth_health.py.- API-probe exceptions are classified as transport errors when they are —
_probe_apinow catcheshttpx.TimeoutExceptionandhttpx.RequestErrorexplicitly and emits the"network_error:"prefix so_determine_verdictcan route them to"unverified". Previously all exceptions emittedf"{type(e).__name__}: {e}", which meant a real transport error on the API path was misclassified as an auth failure ("stale"). Pinned byTestProbeApiErrorClassificationintests/services/test_auth_health.py.
[0.7.0] - 2026-06-03
Added
- Studio prompting guide and fast-track agent behavior — AI agents using the MCP skill now follow a fast-track prompting model: infer format, style, and prompt from context, emit a one-line notice, and generate immediately — no multi-question intake questionnaires. A guided preview mode (show settings + full prompt before generating) kicks in only for vague requests, high-stakes content (e.g. cinematic video), or when the user explicitly asks. Two new reference documents ship with the skill:
references/studio-prompting-guide.md(per-artifact decision trees, prompt parameters) andreferences/studio-prompt-examples.md(copy-paste templates). SKILL.md andworkflows.mdupdated throughout. - Cinematic video format —
video_format=cinematicis now documented and supported in the skill, CLI, and MCP guide. Cinematic videos take the full creative brief viafocus_prompt/--focus;--styleis not applicable.
Fixed
- Query returns thinking step instead of short answer (Issue #214) — When the AI's final answer was under 20 characters, for example
ANSWER: Cfrom a multiple-choice prompt,nlmdiscarded it and returned the longest thinking chunk instead. The 20-char guard in_extract_answer_from_chunk(both the list-form and string-form branches) was redundant with the existing type indicator atfirst_elem[4][-1](1 = answer, 2 = thinking), which is the authoritative discriminator. Removed both guards. The type indicator still routes short thinking chunks to the thinking bucket, so behavior for normal answers is unchanged. 4 new regression tests inTestShortAnswerRegressioncover: short answer wins over a longer thinking chunk, single-character answers, short thinking chunks still filtered as thinking, and the string-form first_elem path. nlm notebook createmissing--json(Issue #215) — Every other notebook verb (list,get,describe,query) already supported--json, butcreatedid not. This was a real friction point for agent workflows that need to capture the new notebook ID reliably. Added the flag; the output is the samenotebook_id/title/url/messagedict that other verbs return, so scripting just works. Thanks to @SimonMallas for the report and end-to-end test in the issue!auth_status = "stale"was misleading (Issue #215) — The MCPserver_infotool (andnlm login --check) reported"stale"for any non-configured/ non-not_configuredoutcome, which silently grouped three very different conditions together: (a) credentials are actually expired and operations will fail, (b) the live check hit a network error/timeout/non-200 and cached creds may still work, and (c) the saved profile failed to load. The new state machine splits this into two distinct values:"stale"is reserved for cases (a) and (c) where the user genuinely needs tonlm login, and a new"unverified"reports case (b) so agents don't pester users to re-auth on transient network blips. Unknown future reasons stay conservative ("stale"). No rawAuthCheckResult.reasonstrings are exposed; only the 5 stable status values. The newUnderstanding auth_statussection indocs/AUTHENTICATION.mddocuments each state and what to do.format_itemsilently discarded plain-dict results — All three formatter classes (TableFormatter,JsonFormatter,CompactFormatter) checked formodel_dump/__dict__beforeisinstance(item, dict). BecauseTypedDictinstances are plaindictat runtime (nomodel_dump, no per-instance__dict__in CPython), they fell through to the worst-case path:JsonFormatterwrapped the payload as{"value": {...}}instead of printing it flat, andCompactFormatteremittedstr(item)(the raw dict repr) instead of the notebook ID. Fixed by addingisinstance(item, dict)as the first branch in all threeformat_itemmethods.nlm notebook create --jsonand pipe capture now work correctly.- HTTP 401/403 misclassified as
"unverified"inserver_info— Thereason.startswith("http_")catch-all in_check_auth_statusmapped every non-200 response — including definitive credential-rejection codes 401 and 403 — to"unverified"("cached credentials may still work, do not prompt re-auth"). Added explicithttp_401/http_403→"stale"guards before the generalhttp_branch so agents correctly prompt re-authentication when cookies are genuinely rejected by NotebookLM.
Documentation
- New
docs/GETTING_STARTED.mdguide — First-time setup, agent registration, and a full 5-step migration path from a browser-automation–based NotebookLM MCP (the kind of setup reported in Issue #215). The migration section explicitly calls out removing any legacynotebooklmserver config as the #1 cause of "Hermes picked the wrong tool" symptoms. README is no longer carrying the migration content; the docs index now points at the new guide. (Issue #215, items 3 and 5) MCP_GUIDE.mdserver-naming note — Recommends the defaultnotebooklm-mcpserver name and warns against generic names that collide with legacy MCPs. (Issue #215, item 5)
[0.6.15] - 2026-06-01
Fixed
-
Auth-guard stale-TTL window when tokens change on disk during the cached period — The 60s auth-guard introduced in 0.6.14 cached the "auth is valid" result for 60s. If you ran
nlm login(or any flow that rewrote the auth file) during that window, the guard would still report valid and your server would use the stale tokens until the TTL elapsed. Fixed byservices.auth.get_active_auth_mtime(): the guard now records the latest mtime of the active auth storage (the legacyauth.jsonplus everycookies.jsonunderprofiles/) and invalidates the cache when any of them changes. A write to ANY profile's file invalidates the guard, regardless of which profile the CLI/MCP session is using. 5 new tests cover modern profile layout, legacy fallback, mid-migration (both files exist), fresh install (no files), and config-error defensiveness. -
Auth-guard mtime check was watching the wrong file (caught by live testing) — The first iteration of the mtime fix only watched the config's
default_profile'scookies.json. But the active profile for a CLI/MCP session can be overridden with--profile, while the config-leveldefault_profilestays put. If you rannlm login --profile <other>externally, the active profile'scookies.jsonwould be rewritten but the guard never saw it. The fix above resolves this by globbing allprofiles/*/cookies.jsonfiles. Live testing against a real Chrome login + real NotebookLM API confirmed the fix.
Changed
services/auth.pyis now a full shim, not a single-symbol re-export — The 0.6.14 release addedservices/auth.pyto routecheck_auththrough the services layer. This release extends it to cover all 6 auth symbols that the cli/ and mcp/ layers were importing directly fromcore/:check_auth,load_cached_tokens,save_tokens_to_cache,get_cache_path,validate_cookies, plus the two class symbolsAuthTokensandAuthManagervia PEP 562__getattr__. The shim is a thin layer with no business logic of its own; behavior is unchanged. The only remaining directcore.authimport in cli/ or mcp/ is inutils/cdp.py, which has a circular-import guard and is explicitly outside the layering rule's scope.
[0.6.14] - 2026-06-01
Fixed
nlm logincrash on fully expired auth (PR #211 / Issue #210) — When the stored Google session/cookies were fully expired,_validate_saved_profile()raisedClientAuthenticationError, which does not inherit fromNLMError. Theexcept NLMError:clause inlogin_callbackmissed it, so the exception bubbled up tocli_main()and exited the process before ever launching Chrome for interactive sign-in. Users had to manually delete all profiles as a workaround. Fixed by also catchingClientAuthenticationErrorin the validation catch. Thanks to @insane66613 for the fix!- MCP silent auth/studio failures (PR #212) — Three related silent-failure bugs in the MCP server under stale/expired auth:
refresh_auth()returnedstatus: "success"after reloading dead tokens from disk. A disk reload is not a successful re-auth — now runscheck_auth(live=True)after the reload and returnsstatus: "expired"with an actionablenlm loginhint if tokens are dead.studio_create()had no pre-flight auth check, so it returnedstatus: "success"with anartifact_idthat failed seconds later — sending agents into pointless polling loops. Now runscheck_auth(live=True)after the network-free confirmation preview and artifact-type validation; invalid auth returnsstatus: "error"with annlm loginhint before any doomed request is fired.studio_status()surfacedstatus: "failed"artifacts with every other fieldnulland no reason, so callers had no way to know why. The raw gRPC payload carries no error string, soget_studio_status()now synthesizes a non-nullerror_reasonfor failed artifacts while preferring any realerror_reason/failure_reason/failure_code/errorkey if a future API version exposes one. 12 new tests cover the full matrix (one is parametrized with 4 cases). Thanks to @idankatz64-commits for the comprehensive PR and tests!
- The pre-flight
check_auth(live=True)adds ~1 homepage fetch on theconfirm=Truepath ofstudio_createand on everyrefresh_auth. A network-free preview path is preserved forconfirm=False.
Changed
ArtifactInfogains an optionalerror_reasonfield — Returned by the MCPstudio_statustool.Nonefor healthy artifacts; a synthesized string for failed artifacts (with a hint to re-check auth); verbatim from the API if a realerror_reason/failure_reason/failure_code/errorkey is present. Backward-compatible: existing callers that only inspectstatusare unaffected.- Bounded in-process conversation history cache (Issue #213) — The in-process cache of conversation history used to grow without bound, so a long-lived MCP server (typical for an always-on assistant) eventually OOM'd the host. The cache is now bounded by three new env-var knobs (set any to
0to disable that specific cap):NOTEBOOKLM_CONVERSATION_MAX_TURNS(default50) — max turns kept per conversation. Older turns are FIFO-dropped; survivors are renumbered1..Nsoturn_numberstays a stable 1-indexed position in the current list.NOTEBOOKLM_CONVERSATION_MAX_CONVS(default500) — max distinct conversations cached. On overflow, the least-recently-used conversation is evicted. Writes and reads both promote to MRU.NOTEBOOKLM_CONVERSATION_MAX_CHARS_PER_TURN(default100000) — per-turn answer character cap as a safety net against pathological payloads. Queries are user input and not truncated.- Public introspection:
get_conversation_cache_stats()returns{conversations, total_turns, max_turns_per_conversation, max_conversations, max_chars_per_turn}. - 13 new tests cover defaults, env-var overrides, invalid-fallback,
0=unlimited, negative-clamp-to-zero, FIFO trim with renumber, LRU eviction on insert, LRU promotion on read, LRU promotion on write, LRU promotion when migrating to a pre-existing key, answer truncation, stats accuracy, and clear compatibility. - The
--statelessflag andNOTEBOOKLM_MCP_STATELESSenv var continue to control the MCP HTTP transport layer only — they do not affect this cache.
[0.6.13] - 2026-05-27
Security
- TOCTOU-safe credential file creation (PR #205) — All credential files (
auth.json,cookies.json,metadata.json, port map) were previously written with default permissions and thenchmod'd to0o600— leaving a brief window where the file was world-readable. Fixed usingos.open()+os.fdopen()so the file descriptor is created with0o600from the start. Thanks to @Amy-Ra-lph for the PR and thorough implementation! - HTTP and SSE external-bind enforcement — Running
notebooklm-mcp --transport http --host 0.0.0.0(or--transport sse) previously emitted a warning but still bound to the external address. The server now refuses to start unlessNOTEBOOKLM_ALLOW_EXTERNAL_BIND=1is explicitly set, preventing accidental cookie exposure on untrusted networks. The guard now covers both HTTP and SSE transports. - GitHub Actions pinned to full commit SHAs (PR #207) — All four workflow files now pin third-party actions (
actions/checkout,astral-sh/setup-uv,pypa/gh-action-pypi-publish,softprops/action-gh-release) to their full 40-character commit SHAs with a version comment for readability. Prevents tag-drift supply chain attacks. Thanks to @Amy-Ra-lph for the careful SHA verification!
Fixed
terminate_chrome()null-safety (PR #205) — On double-call,_cached_ws.close()could raiseAttributeErrorbecause_cached_wswas read after being set toNone. The reference is now captured before the try block. Thanks to @Amy-Ra-lph!- Cookie key whitespace handling (PR #205) — Added
.strip()to cookie key parsing insave_auth_tokensto handle edge cases with leading/trailing whitespace in cookie headers. - Auth check consistency (PR #203) — Unified auth checking logic under a single
check_auth()function with a typedAuthCheckResult, eliminating subtle differences between the MCP and CLI auth status paths. Thanks to @derekszen for the clean refactor!
Changed
- Exponential backoff for source reconciliation polling —
_reconcile_source()(the fallback poller that verifies a source landed after an ambiguous gRPC error) previously used a fixed 1-second delay between polls. Now uses exponential backoff (1s → 2s → 4s, capped at 4s) to reduce unnecessary API calls on slower operations. - File path canonicalization for uploads —
add_file()now calls.expanduser().resolve()on the input path, so paths like~/Documents/file.pdfwork correctly and symlinks are fully resolved before validation. raw_responsefield removed fromquery()return — Theraw_responsekey was included in the dict returned byConversationMixin.query()but was never read by any caller (services, MCP tools, or CLI). Removing it avoids leaking raw API response text into any future log aggregators or serializers.
[0.6.12] - 2026-05-24
Fixed
- Manual login Netscape cookie parser fixes (PR #199 / Issue #198) — Fixed three bugs in the Netscape/Mozilla cookie file parser used in
nlm login --manual:- Resolved a critical bug that treated
#HttpOnly_lines as comment rows and silently ignored them, which dropped essential Google authentication cookies like__Secure-1PSIDTSand__Secure-3PSIDTS(resulting in cryptic 401 errors). - Allowed empty-value cookies to be parsed with a value of
""instead of being skipped by ensuring trailing tab characters are not stripped from the end of the line. - Hardened value extraction to defensively join tab-containing cookie values instead of truncating them.
- Added 4 new test cases to prevent future regressions. Thanks to @pan-long for the comprehensive PR and excellent troubleshooting!
- Resolved a critical bug that treated
- MCP
source_addtool andSKILL.mdfile-type alignment (PR #197) — Updated thesource_addMCP tool docstring and the globalSKILL.mdguidelines to list all 18 supported file-type extensions (PDF, TXT, MD, DOCX, CSV, EPUB, MP3, M4A, WAV, AAC, OGG, OPUS, MP4, JPG, JPEG, PNG, GIF, WEBP) instead of a restricted subset. Also documented how image-bearing sources are ingested to feed the Studio video generation's visual-crop pipeline to generate on-screen visual aids in Video Overviews. Thanks to @Premshay for the excellent documentation enhancement and detailed research on the visual-crop pipeline!
[0.6.11] - 2026-05-22
Fixed
- False-negative errors on
source_addandresearch_import(Issue #196) —source_add(text, URL, Drive) andresearch_importwere reporting"Could not add ... source."errors even when NotebookLM had successfully accepted the source for asynchronous processing. Root cause: NotebookLM uses the same gRPC error code3in thewrb.frresponse envelope for both "accepted-pending" (async processing started) and "genuine rejection". Added a_reconcile_source()helper that pollsget_notebook_sources_with_types()after a code 3 or 9 error to verify whether the source actually landed. If found → returns success. If not found after polling → re-raises the original error so genuine failures still surface. Also fixed a secondary double-submission bug where URL sources on accounts using the v1 (izAoDd) RPC would trigger a spurious v2 (ozz5Z) call when v1 returned an accepted-pending code 3 — reconciliation now short-circuits the fallback if v1 actually delivered. 12 new unit tests added (total: 875 tests). Thanks to @mdshearer for the detailed report and excellent root cause analysis! - Snap Chromium profile directory (PR #195) — On Ubuntu and other distros, Chromium installed as a Snap package is confined by AppArmor and can only write to
~/snap/<snap-name>/common/. Launching with--user-data-dir=~/.notebooklm-mcp-cli/was failing withExit code 21: Failed to create a ProcessSingleton. Snap browsers are now detected via/snap/in the resolved binary path and automatically redirected to~/snap/chromium/common/notebooklm-mcp-cli/chrome-profiles/. Profile lock, headless auth, and cache cleanup are all snap-aware. Thanks to @ildella for the contribution! - Audio download 403 on cross-domain CDN (PR #193) — Audio artifacts downloaded via
nlm download audiowere returning HTTP 403 from Google's CDN (lh3.google.com) because_download_urlinheritedSec-Fetch-Site: nonefrom the page fetch headers. Google's audio CDN treats that value as an unauthorized address-bar navigation and rejects the request regardless of valid cookies. The fix mirrors the header shape Chrome uses forwindow.open()— settingSec-Fetch-Site: cross-siteandReferer: https://notebooklm.google.com/on all cross-domain artifact downloads. Verified: same notebook that returned"Download failed for audio."now produces a complete 41.7 MB AAC file. Thanks to @responsiblefleet for the thorough root cause analysis and fix!
[0.6.10] - 2026-05-15
Fixed
- Windows CDP Authentication Reliability (#192) — Major stability improvements for authentication on Windows 11. Thanks to @jonathanzhan1975 for the detailed bug report and testing!
- Improved Windows Edge detection logic in
nlm doctorto match the login flow. - Optimized CDP port scan timeouts (reduced from 2s to 1s) to prevent 20-second blocks when ports are unresponsive.
- Added process isolation for Windows via
CREATE_NEW_PROCESS_GROUP. - Added
--disable-features=msEdgeStartupBoostlaunch flag to prevent Edge's "Startup Boost" background processes from intercepting CDP sessions. - Implemented automated cleanup of stale NLM-spawned browser processes.
- Enhanced failure diagnostics to log process exit codes when browser initialization fails.
- Improved Windows Edge detection logic in
[0.6.9] - 2026-05-11
Added
- Hermes Agent Support —
nlm skill install hermesnow installs the NotebookLM skill for Hermes Agent by NousResearch. Respects the$HERMES_HOMEenvironment variable for custom install paths. - EPUB File Upload Support (PR #191) —
.epubfiles can now be uploaded as notebook sources. Thanks to @mateogon for the contribution!
Fixed
- Windows Tool Detection —
nlm skill installno longer falsely warns that tools are not installed on Windows. Detection now checks for the tool's binary on PATH and root config directory existence instead of only checking the (possibly non-existent) skills subdirectory. - Windows Permission Errors —
safe_mkdirnow catchesPermissionErrorand provides an actionable fix command (icacls) instead of a raw traceback. The update-check cache andprint_update_notification()no longer crash the CLI when the storage directory has restrictive ACLs. - Windows Encoding Errors — All
read_text()/write_text()calls now explicitly specifyencoding="utf-8"to preventUnicodeDecodeErroron Windows systems that default tocp1252. - CLI Studio Status Missing Mind Maps —
nlm studio statusnow routes through the service layer (get_studio_status) so mind maps are included in the output.
Changed
- Shared Tool Detection — Extracted
is_tool_on_system()helper intocli/utils.py, shared by bothnlm skill installandnlm setupto eliminate duplicate detection logic. - Typed Skill Config —
TOOL_CONFIGSinskill.pynow uses aToolConfigTypedDictinstead ofdict[str, Any]for better type safety. - File Upload Docs — Updated supported file types list to include
.epuband all audio/image formats actually supported by the API.
[0.6.8] - 2026-05-11
Fixed
- Conversation Query Rejection — Fixed an issue where the notebook query endpoint would reject requests with an opaque error due to strict backend requirements. Explicitly added
Content-Type: application/x-www-form-urlencoded;charset=UTF-8to the streamed query endpoint. Thanks to @fabianafurtadoff for the contribution (PR #189)!
[0.6.7] - 2026-05-10
Added
- Cited-Only Filtering for Research — Added support for filtering out non-cited sources during research imports. This includes a robust citation parser that handles standard markers (
[1]), ranges ([4-6]), and bibliography extraction. Theresearch_statuspolling output now also annotates sources with acited: boolfield for visibility. Thanks to @zxyasfas for the contribution (PR #188)!
Fixed
- Audio Download Extension Validation (Issue #185) —
nlm download audionow rejects incompatible file extensions (like.mp3or.wav) instead of writing AAC data with the wrong file extension. A helpful hint now suggests using.m4aor.mp4and provides anffmpegcommand for conversion. - Conversation Query Hangs — Replaced direct
client.post()with a freshhttpx.Client()context in conversation queries to prevent internal connection pool exhaustion or unexpected hangs during repeated querying. - Fuzzy Title Matching in Research — Upgraded the research citation title matcher from basic substring checks to whitespace-aware boundary regex, preventing false positives where a short title matches a substring of a longer word.
[0.6.6] - 2026-05-07
Fixed
-
Opaque error on capacity throttle (Issue #182) — When NotebookLM returns
RPCError code=8(RESOURCE_EXHAUSTED) with aUserDisplayableErrorpayload, the error message now surfaces the human-readable text instead of the raw protobuf type URL. AddedResourceExhaustedError(RPCError)subclass so callers can catch throttle errors distinctly. Studio artifact creation now provides retry-specific hints. Thanks to @nikolaykazakovvs-ux for the detailed report! -
Cinematic video silently ignores --style-prompt (Issue #183) —
--style-promptwith cinematic format now maps tocustom_instructions(same API field as the web UI's "Customize Video Overview" dialog) instead of being silently dropped.--stylestill rejects for cinematic since visual style codes don't apply. Validation now runs before source resolution for faster feedback. Thanks to @guia-matthieu for the report!
Changed
- Updated README to note Google AI Ultra ($249/mo) compatibility (PR #184). Thanks to @guia-matthieu!
[0.6.5] - 2026-05-05
Fixed
- Authentication Race Condition (Issue #181) — Fixed an issue where the
nlm loginCLI and headless authentication flows exited prematurely, resulting in incomplete cookie extraction and subsequent "Authentication expired" errors. Implemented deterministic DOM polling to wait for session tokens (FdrFJeor build label) before extracting cookies.
[0.6.4] - 2026-05-04
Fixed
- Cross-domain artifact downloads (PR #180) — Fixed an authentication bug where
OSIDcookies leaked during cross-domain artifact downloads, causingServiceLoginredirects. The_download_urlmethod now correctly strips service-scoped cookies for external hosts. Thanks to @laofun for this critical fix!
[0.6.3] - 2026-05-04
Fixed
- CDP tab creation failures in locked-down environments (Issue #175) — Added fallbacks to reuse existing tabs if CDP tab creation fails. Removed redundant page fetch and merged reuse loops into one pass.
[0.6.2] - 2026-04-29
Fixed
- Login timeout after Google sign-in (#174) —
is_logged_in()used substring matching on the full URL, so the post-sign-in redirect URL containingoriginal_referer=...accounts.google.com...in the query string was misidentified as a sign-in page. Now parses the URL hostname viaurlparse(). Thanks to @SKMKZP for the clear root cause analysis and fix! - Headless browser hijacking during
nlm login—find_any_existing_cdp_browser()would blindly reuse any Chrome with CDP enabled on ports 9222-9231, including headless instances from other tools (e.g. Perplexity MCP). This causednlm loginto silently hang for 5 minutes waiting for sign-in on an invisible browser. Now checks User-Agent forHeadlessChromeand skips automation browsers. - Silent login wait loop — When waiting for user sign-in, the CLI now emits status messages instead of hanging silently for up to 5 minutes with no feedback.
Changed
- Extracted
_fetch_cdp_version()helper to share/json/versionlogic betweenget_debugger_url()andfind_any_existing_cdp_browser().
[0.6.0] - 2026-04-27
Added
- Source Label Management — Organize notebook sources into thematic categories with the new
labelMCP tool andnlm labelCLI commands. Full action set:auto(AI-generated labels),list,create,rename,set_emoji,move_source, anddelete. Multi-label assignment supported — sources can belong to more than one label. Requires 5+ sources for auto-labeling.
Fixed
- WSL Firewall check encoding (#172) — PowerShell on Windows commonly returns output in UTF-16-LE, causing a
UnicodeDecodeErrorincheck_firewall_rule()that madenlm login --wslshow a false firewall warning even when the rule already existed. Fixed by addingerrors="replace"to the subprocess call. Thanks to @andrepreira for the diagnosis and clean fix!
[0.5.31] - 2026-04-26
Fixed
- EOF on Initialization (Issue #171) — The MCP
stdiotransport strictly requiresstdoutto be used only for JSON-RPC messages.fastmcpinitialization logs (and any other strayprint()calls) were corrupting thestdoutstream, causing MCP clients to crash with an EOF error on Windows and macOS. Added a dedicated_StdoutToStderrWrapperinserver.pythat intercepts all standard text output and safely redirects it tostderr, while preserving the underlying binary.bufferfor valid JSON-RPC payloads. Thanks to @swiezaczek for the thorough analysis in the issue report!
[0.5.30] - 2026-04-25
Fixed
- Auth loop when
NOTEBOOKLM_COOKIESenv var is stale (Issue #170) —refresh_authnow detects whenNOTEBOOKLM_COOKIESis set in the environment and returns a clear, actionable error instead of falsely reporting "success" while silently reloading the same stale cookies. Auth failure messages now include a note pointing to the env var when it's the likely cause. Thanks to @nobolso for the thorough root cause analysis! - Deprecated
NOTEBOOKLM_CSRF_TOKEN/NOTEBOOKLM_SESSION_IDenv vars removed — These were still being read and passed to the client constructor, which caused them to bypass auto-refresh when stale. Both are now always auto-extracted; the deprecated env vars are ignored.
Documentation
- Added troubleshooting section to
AUTHENTICATION.mdexplaining theNOTEBOOKLM_COOKIESenv var override trap, how to diagnose it, and both fix options.
[0.5.29] - 2026-04-24
Fixed
- Python 3.11 TypedDict compatibility (Issue #167) — Pydantic v2 rejects
typing.TypedDicton Python < 3.12. All 13 service files now importTypedDictfrom a centralized compat shim (services/_compat.py) that usestyping_extensionson < 3.12. Addedtyping_extensionsas an explicit dependency for Python < 3.12. Thanks to @irvinghu07 for the clear report and suggested fixes! - SOCKS proxy blocks
nlm login(Issue #167) — The CDP helper'shttpx.ClientinheritedALL_PROXYfrom the environment, causingImportError: socksio not installedon localhost CDP connections. Fixed withtrust_env=False. Thanks to @irvinghu07! - MCP
notebook_listalways returns "Authentication expired" (Issue #169) —save_tokens_to_cache()only wrote to the legacyauth.json, butload_cached_tokens()prioritizesprofiles/default/cookies.json. Tokens saved via the MCPsave_auth_tokenstool were never read back. Fixed by syncing writes to bothauth.jsonand the active profile. Thanks to @nobolso for the thorough diagnosis and file structure analysis! - Python 3.14 Windows
pathlib.mkdirregression (Issue #169) —Path.mkdir(parents=True, exist_ok=True)raisesFileExistsError(WinError 183) on Python 3.14 + Windows. Addedsafe_mkdir()wrapper applied to allmkdircalls acrossconfig.py,auth.py,base.py, andcdp.py. Thanks to @nobolso!
[0.5.28] - 2026-04-23
Fixed
- HTTP transport: default to stateless mode (Issue #165) — HTTP transport (
--transport http) now defaults to stateless sessions, preventing the MCP SDK double-response crash (AssertionError: Request already responded to) that killed entire sessions on slow Google API calls. Use--no-statelessto opt out. Thanks to @mylaser215 for the thorough root cause analysis (#165)!
Changed
- CLI flags use
BooleanOptionalAction—--stateless/--no-statelessand--debug/--no-debugare now proper toggle pairs. Environment variables (NOTEBOOKLM_MCP_STATELESS,NOTEBOOKLM_MCP_DEBUG) accepttrue/false/0/1/yes/no/on/off(case-insensitive).
Documentation
- CLI Guide: document all skill install targets (Issue #163) — Added
agents,codex,gemini-cli, andalef-agentwith install path details. Fixed missingopencodein setup clients list.
[0.5.27] - 2026-04-21
Added
- Restore skill targets for codex and gemini-cli (Issue #163) — Restored the missing target configurations for
codexandgemini-cliagent skills and added Alef Agent specific frontmatter logic. Thanks to the user who reported this issue (#163)!
Fixed
- Source: Honour
--titlewhen adding a file source (PR #162) — Fixed an issue where adding a file source via CLI ignored the user's custom title. The source upload is now fully awaited before the follow-up rename is fired to guarantee precision. Huge thanks to @CryptoWombat for this excellent contribution and thorough fix!
[0.5.26] - 2026-04-17
Added
server_inforeports local auth state (Issue #160) — Response includesauth_status(configured|stale|not_configured|error) based on cached token presence and age. This is a local disk check only, not a live Google validation; docstring clarifies. Thanks to @josuebustosn for the report and expected behavior.
Fixed
- Windows Unicode: all CLI Rich consoles use safe factory (Issue #156) — Every CLI command module and the default
Formatternow usemake_console()(safe_box,legacy_windows=Falseon Windows) instead of bareConsole(). Complements the UTF-8 stdio bootstrap from v0.5.25 and avoidsUnicodeEncodeError/ MCP EOF on legacy Windows code pages when printing API text with arrows, smart quotes, etc. Thanks again to @argonaut-cm for the original EOF / Unicode analysis (v0.5.25 thanked the stdio + Rich bootstrap; this completes CLI-wide coverage). - MCP reloads client after
nlm loginwithout manualrefresh_auth(Issue #161) —get_client()now invalidates the singleton when on-disk tokens are newer than the running client (extracted_atvs_created_at), not only when the cookie dict changes. Same-profile re-auth updates are picked up automatically. Auth expiry error message mentionsrefresh_authas a fallback. Thanks to @josuebustosn for the clear repro and suggested directions.
[0.5.25] - 2026-04-15
Fixed
- Audio download fails with 302→404 (Issue #158) — Google's audio media list contains multiple URL variants:
=m140-dv(download variant, fast CDN viadrum.usercontent.google.com, ~3 MB/s) and=m140(streaming transcode viagooglevideo.com, ~30 KB/s). The download logic now explicitly prefers the-dvvariant for bothdownload_audioand_extract_audio_media_url. Audio downloads that previously failed now complete a 47MB file in ~15 seconds. Thanks to @Victor777777 for the detailed bug report and redirect chain analysis! - CDP WebSocket broken with system proxy (Issue #119, PR #157) — When
HTTP_PROXY/HTTPS_PROXYenvironment variables are set (e.g., Clash, Surge),websocket-clientrouted localhost CDP connections through the external proxy, crashingnlm login. Fixed by temporarily clearing proxy env vars aroundwebsocket.create_connectioninexecute_cdp_command. The existing httpx fix (#119) only covered HTTP; this completes the WebSocket side. Thanks to @ahmelkholy for identifying the issue and contributing PR #157! - Windows: MCP server crashes with UnicodeEncodeError (Issue #156) — On Windows consoles using cp1252 encoding, Rich's legacy renderer crashed on Unicode characters like
→(U+2192) returned by NotebookLM, killing the MCP server process and causing client EOF disconnects. Fixed by reconfiguringstdout/stderrto UTF-8 with replacement at process startup (both CLI and MCP entry points) and settinglegacy_windows=Falseon Rich Console instances. Thanks to @argonaut-cm for the clear traceback and proposed solutions!
Changed
- Lazy-load
NotebookLMClientin package__init__—from notebooklm_tools import NotebookLMClientnow uses__getattr__to defer the heavy import until first access, keeping the stdio encoding bootstrap lightweight.
[0.5.24] - 2026-04-13
Fixed
- Studio: Surface revise RPC errors with actionable hints (PR #154) — When
slides revisefails due to an invalid artifact ID or a rejected revision request, the error now surfaces the specific Google API error code (e.g.,INVALID_ARGUMENT) along with a clear hint guiding the user to verify their artifact ID. Previously, these failures produced opaque, unhelpful error messages. Thank you @sickn33 for this fix! - WSL2: Auth broken on Chrome 136+ due to localhost-only CDP (PR #155) — Chrome 136+ ignores
--remote-debugging-address=0.0.0.0, restricting the DevTools Protocol to127.0.0.1only. This completely brokenlm login --wslfor all WSL2 users. The fix switches to a port proxy approach: Chrome launches on port 9223 (localhost) and WSL connects via port 9222 through anetsh interface portproxyrule. Temp Chrome profiles are now created on the Windows filesystem (%TEMP%) instead of WSL's/tmpto prevent "Profile error occurred" crashes. Updateddocs/WSL_SETUP.mdwith one-time setup instructions. Thank you @casjogreen for this critical fix!
[0.5.23] - 2026-04-12
Added
- Restore NotebookLM MCP and CLI runtime contracts (PR #152) — Fixed MCP tool boundary registration, normalized error payloads, and restored download/upload sync-compatible entrypoints. Thank you @sickn33 for this immense contribution!
Fixed
- Windows: Server crashes immediately on startup (Issue #150) —
os.execvpfails on Windows. Replaced withsubprocess.runto prevent immediate crashes on Windows 11 during server startup via the.mcpbbundle. Added explicitstdin=sys.stdin,stdout=sys.stdout, andstderr=sys.stderrto ensure the JSON-RPC stdio channel between Claude Desktop and the server remains properly connected across platforms. Thanks to @m3saros for diagnosing the root cause and providing the exact fix!
[0.5.22] - 2026-04-11
Added
- Studio status code parity and normalization (PR #149) — Consolidated the extraction logic for studio artifacts into a centralized
_normalize_studio_statusroutine. TheJsonFormatterhas been updated to dynamically populate returned JSON payloads with newly available artifact fields (such asaudio_url,video_url,slide_deck_url,flashcard_count) without breaking the shape expected by downstream consumers. Huge thanks to @sickn33 for this amazing contribution!
Fixed
- API
poll_studio_statusbypassing auth recovery — The corepoll_studio_statushelper function was making raw HTTP calls and dodging the standard_call_rpcpipeline. This caused it to immediately fail on400 Bad Requestexceptions whenever the user'sbuild_labelor session tokens went stale. The polling function now correctly wraps its logic in_call_rpc, securing free auth recovery loops, retries, and unified debug capability during studio polling.
[0.5.21] - 2026-04-11
Fixed
- HTTP 400 bad request causing silent auth failures (Issue #147) — Google returns
400 Bad Requestinstead of401or403when the internal CSRF token expires. Added 400 to the retryable auth status codes, which fixes auth recovery failures and prevents tracebacks (PR #148). - WSL CDP failures breaking auth (Issue #138, #144) — Native WSL connectivity has been fully added.
nlm login --wslsecurely launches and channels DevTools via0.0.0.0to safely bridge the WSL network boundary. - Pass Build Label in login check — The
nlm login --checkcommand was initiating a client without passing the configured build label, unnecessarily triggering a three-month backward fallback.
[0.5.20] - 2026-04-10
Fixed
nlm create infographiccrash when--stylenot specified (Issue #142) — The verb-first route was missing the--styleoption entirely, causing aTypeErroron invocation. Fixed alongside 12 other missing parameters across verb-first wrappers.- Multiple verb-first commands missing parameters — The verb-first CLI route (
nlm create,nlm add,nlm describe,nlm query,nlm delete) was missing 13 parameters that existed on the noun-first route:--focusonnlm create quizandnlm create flashcards;--waitand--wait-timeoutonnlm add url,nlm add text, andnlm add drive;--auto-importonnlm research start;--formatonnlm download slides;--jsononnlm describe notebook,nlm query notebook, andnlm source content; and--confirmonnlm delete alias.
Changed
- Widened
fastmcpdependency to>=2.0.0,<4.0(Issue #141) — The previous upper bound (<3.0) caused a startup crash whenfakeredis 2.35.0was installed alongsidefastmcp 2.x. Widening to<4.0resolves the incompatibility and allows users to use newer FastMCP releases without version conflicts.
Added
- Parameter parity test (
tests/cli/test_verbs_parity.py) — Automatically compares every verb-first wrapper incli/commands/verbs.pyagainst its target function to detect missing parameters. CI will now fail if a verb wrapper drifts out of sync with its noun-first counterpart.
[0.5.19] - 2026-04-09
Added
- Auto-Import for Research — Added
--auto-import/--wait-and-importflags tonlm research startto automatically wait for research to finish and immediately import.
Fixed
- Deep Research Task ID Mismatch (Issue #140) — Fixed a bug where deep research task IDs were being mutated by the backend and causing import failures. The CLI now polls the correct mutated task ID before issuing the import command.
- Empty Notebook Error Mapping — When attempting to query a notebook with 0 sources, the backend previously threw an unhelpful
API error (code 5): unknown. This now returns a clean validation error indicating the notebook is empty and needs sources added. - gRPC Error Code Mapping — Generic undocumented gRPC error codes from Google's batchexecute API (like 5, 7, 16) are now mapped to their standard names (
NOT_FOUND,PERMISSION_DENIED, etc.) instead of logging asunknown.
[0.5.18] - 2026-04-09
Added
- WSL2 Authentication Support (PR #138) — New
nlm login --wslflag launches Windows Chrome from WSL2 for seamless authentication. Includes automatic firewall rule management, cross-boundary CDP communication, and a cleanup mechanism for temporary Chrome profiles. Full setup guide atdocs/WSL_SETUP.md. Thanks to @kylebrodeur for the comprehensive implementation! - WSL2 Diagnostics —
nlm doctornow detects WSL2 environments and reports Chrome availability, Windows interop status, and firewall configuration.
Fixed
- Thread-Safety for Concurrent MCP Tool Calls (PR #135) — Added
threading.LocktoBaseClientprotecting mutable state (_reqid_counter,_conversation_cache,_source_rpc_version) from race conditions during parallel MCP tool invocations. Uses double-checked locking for singleton client initialization. Includes 7 new concurrent access tests. Thanks to @xiangyuwang1998 for the implementation! - Restored CDP WebSocket Timeout — Re-applied the 30-second timeout on
execute_cdp_command()that was inadvertently removed during the WSL2 merge. Prevents infinite hangs on stale/dropped WebSocket connections. - Restored Port Map File Permissions — Re-applied
chmod 0o600on the port map file that was inadvertently removed during the WSL2 merge. Ensures the port map is only readable by the owner.
[0.5.17] - 2026-04-07
Security
- CDP Origin Restriction (PR #133) — Chrome is now launched with
--remote-allow-originsrestricted tolocalhostand127.0.0.1only, preventing malicious webpages from connecting to the CDP debug port. Previously allowed all origins (*). Thanks to @wccheung11011001 for the security audit! - Base URL Allowlist (PR #133) — The
NOTEBOOKLM_BASE_URLenvironment variable is now validated against an allowlist of known Google domains (HTTPS only), preventing cookie exfiltration via environment injection. - Download Path Traversal Protection (PR #133) — Added
validate_output_path()to block downloads from writing to sensitive directories (.ssh,.gnupg,.aws,.kube,.claude,.config) or overwriting sensitive files (authorized_keys,id_rsa,.bashrc, etc.). - File Permission Hardening (PR #133) — Auth-related files, debug output, and the port map are now created with restrictive permissions (
0o600for files,0o700for the storage directory). Thanks to @wccheung11011001! - CDP WebSocket Timeout (PR #133) — Added a 30-second timeout to CDP WebSocket commands to prevent infinite blocking on stale or dropped connections.
Added
- Custom Visual Style Prompts for Video (PR #131) — You can now pass a custom style description when creating videos with
--style custom --style-prompt "your description"(CLI) orvideo_style_prompt(MCP). The style prompt is also returned in studio status responses. Thanks to @agarwalvipin for the implementation and live API verification! - Audio Source Support (PR #134) —
nlm source add --filenow correctly handles audio uploads (m4a, wav, mp3). Audio sources use type code 10, which was previously unrecognized. The--waitflag now handles audio's transient status 3 state (which is not a hard failure for audio, unlike other source types) and a new--wait-timeoutflag (default 600s) gives long recordings enough time to finish transcribing. Thanks to @stanleykao72 for the thorough investigation and fix! - CONTRIBUTING.md — Added a contributor guide covering architecture rules, the Chrome DevTools API capture workflow, testing requirements (both CLI and MCP), security guidelines, error handling patterns, and PR expectations.
Fixed
build_labelData Loss (PR #133) —Profile.to_dict()was silently dropping thebuild_labelfield, causing it to be lost across restarts and re-fetched from scratch. Now properly persisted. Thanks to @wccheung11011001!- Ruff Lint and Format Violations — Fixed
B904exception chaining in CDP timeout handler, and resolved format violations insources.py,config.py,test_url_source_fallback.py, andtest_studio.py.
[0.5.16] - 2026-04-04
Fixed
- URL Source Addition Failing with INVALID_ARGUMENT (Issue #121) — Fixed
source_add(URL type) failing withRPC error code 3 (INVALID_ARGUMENT)for some users due to Google migrating theadd_sourceendpoint. Implemented a dual-RPC fallback: the system tries the legacyizAoDdendpoint first, and if it returns code 3, automatically retries with the newozz5Zendpoint. The working endpoint is cached per session to avoid extra round-trips on subsequent calls. Both single and bulk URL additions (urlandurlsparameters) benefit from the fallback. Thanks to @Neophen for reporting!
Added
- 19 new unit tests for dual RPC fallback mechanism (total: 704 tests)
[0.5.15] - 2026-04-02
Added
- Async Query Polling (Issue #125) — New
notebook_query_startandnotebook_query_statusMCP tools for querying large notebooks (50+ sources) without hitting MCP client timeouts.notebook_query_startfires the query in a background thread and returns immediately with aquery_id. Pollnotebook_query_statuswith thequery_idto get the result when ready. Includes automatic TTL cleanup (10 min) for stale entries. The existingnotebook_querytool remains unchanged for backward compatibility. - 10 new unit tests for async query lifecycle (total: 685 tests)
[0.5.14] - 2026-04-01
Fixed
- Research Start Dead Parameter (Issue #123) — Fixed a bug where
nlm research start "query" --title "My Title"(and the corresponding MCP tool parametertitle) failed because the internal logic did not automatically trigger new notebook creation whentitlewas provided without anotebook_id.
[0.5.13] - 2026-03-31
Fixed
- Python 3.13 Crash in
nlm skill(Issue #122) — Fixed a crash when runningnlm skill installon Python 3.13, which was caused by using@click.option(type=Literal["user", "project"]). Replaced with standard string validation. Thanks to @zhaoguoqiao for reporting! - CDP Proxy Bypass (Issue #119) — The
httpxHTTP2 client was honoring system proxy settings even for the internal127.0.0.1CDP WebSocket acquisition call (http://127.0.0.1:9222/json). This caused connections to fail on machines running proxies. Restored theproxy=Noneargument to explicitly bypass proxies for local loopback connections. Thanks to @sjs33 for discovering and reporting this! research_statusPolling Loop (PR #120) — Restored the internal polling loop forresearch_statuswhenmax_waitis set. Previously, the parameters were ignored after a refactor, and it always returned after a single check. The tool now correctly blocks and polls until the research is completed or times out. Thanks to @byingyang for the excellent bug report, full implementation, and test suite!
[0.5.12] - 2026-03-30
Fixed
- Auth recovery skips profile-based cookies (Issue #117, Bug 1) —
_try_reload_or_headless_auth()gated Layer 2 recovery onauth.jsonexistence. If the legacy file didn't exist, valid profile-based credentials inprofiles/default/cookies.jsonwere completely skipped, falling straight through to headless auth (Layer 3). Now always callsload_cached_tokens()which checks the profile directory first, then falls back toauth.json. Thanks to @olaservo for the incredibly detailed report! --cdp-urlignored by builtin provider (Issue #117, Bug 2) —nlm login --cdp-url http://127.0.0.1:9222was ignored when using the default builtin provider, always launching a new Chrome instead. Now, when--cdp-urlis explicitly provided (even with the builtin provider), the CLI auto-routes to the existing-CDP extraction path, matching the user's intent to connect to an already-running browser. Thanks again to @olaservo!- Pre-existing lint errors blocking CI — Fixed 3 lint violations (
SIM105inauth.py,I001inbase.py,F401intest_coerce_list.py) that were blocking the CI pipeline for PR #118.
Security
- Restrict
auth.jsonfile permissions (PR #116) — Auth token cache files are now written withchmod 600(owner read/write only), preventing other local users or processes from reading active session cookies. Thanks to @tody-agent for the security audit!
[0.5.11] - 2026-03-27
Added
- Enterprise / Google Workspace support (PR #114) — Configurable base URL via
NOTEBOOKLM_BASE_URLenvironment variable. Set tohttps://notebooklm.cloud.google.com(or your organization's URL) to use NotebookLM with managed Workspace accounts. All API calls, authentication, file uploads, and URL detection are updated to use the configured base URL. Default remainshttps://notebooklm.google.comfor personal accounts (fully backward compatible). Thanks to @Robiton for this contribution!
Documentation
- Added "Enterprise / Google Workspace" section to
docs/AUTHENTICATION.md - Added
NOTEBOOKLM_BASE_URLto environment variables table indocs/MCP_GUIDE.md
[0.5.10] - 2026-03-27
Fixed
- Quiz/Flashcard
focus_promptignored (Issue #113) — Thefocus_promptparameter for quiz and flashcard generation was silently ignored due to an off-by-one error in the RPC payload structure. The backend expectsfocus_promptat array index[2](after a reservednullslot), but it was being placed at index[1]. Bothcreate_quizandcreate_flashcardsincore/studio.pynow use the correct payload layout. Thanks to @ojsed for the detailed analysis! source_idsparameter fails with string input (Issue #111) — MCP clients (Claude Desktop, Cursor, etc.) frequently serialize list parameters as JSON strings ('["a","b"]') or comma-separated strings ('a,b') instead of native Python lists, causing Pydantic validation errors. Added acoerce_list()helper inmcp/tools/_utils.pythat normalizes all input forms (JSON strings, comma-separated, single values, native lists) into properlist[T]. Applied to all 6 list parameters across 4 MCP tool files:studio_create,notebook_query,source_add,source_sync_drive,source_delete, andresearch_import. Thanks to @Carlos-OL for reporting!- Non-ASCII characters in JSON output (PR #112) — Fixed
ensure_ascii=Falsemissing fromjson.dumps()calls across core and CLI layers, causing Unicode characters to be escaped as\uXXXXin RPC request bodies and file persistence. Thanks to @rujinlong for the fix!
Added
- 13 new unit tests for
coerce_listhelper (total: 660 tests)
[0.5.9] - 2026-03-25
Fixed
- Fixed a fatal
ImportErrorin the CLI (ArtifactNotReadyError) caused by missed codebase updates during the v0.5.8 structural refactor.
[0.5.8] - 2026-03-25
Fixed/Changed
- Codebase-wide refactor to comply with comprehensive
rufflinting and formatting standards. - Fixed broken imports caused by code structure refactoring.
- A massive thank you to @nikosavola for submitting BOTH the
rufflinting and formatting refactor (PR #110) AND the GitHub Actions CI Pipeline (PR #109)! These are huge improvements to the codebase quality.
[0.5.7] - 2026-03-25
Added
- GitHub Actions CI Pipeline (PR #109) — Added a comprehensive GitHub Actions workflow that automatically runs linting (
ruff format --check,ruff check) and the full pytest suite (uv run pytest) on pull requests and pushes tomain. Linting errors now block the build, guaranteeing code quality before merge. Thanks to @nikosavola for this contribution!
[0.5.6] - 2026-03-24
Fixed
- Windows: manual cookies rejected after import (Issue #105) —
nlm login --manual --filesaved cookies correctly, but subsequent requests tonotebooklm.google.comwere rejected by Google (302 → login page) because the page-fetch headers included macOS-specific Client Hints (sec-ch-ua-platform: "macOS",sec-ch-ua,sec-ch-ua-mobile). When cookies were captured from a Windows Chrome session, the OS fingerprint mismatch caused Google to reject the session. Removed all threesec-ch-ua*headers (they're optional per spec) and switched to a platform-neutral Linux Chrome UA — making auth platform-agnostic. Also added a multi-pattern CSRF token fallback (SNlM0e→at=→FdrFJe) in_refresh_auth_tokens, and amake_console(safe_box=True)factory to preventUnicodeEncodeErrorcrashes on Windowscp1251/cp1252codepage terminals. Thanks to @pakulyaev for the detailed diagnosis and debug output! (5 new regression tests added) - Windows: IPv6 WebSocket connection error during
nlm login(Issue #108) — On Windows, Chrome's DevTools debugger binds to127.0.0.1(IPv4), butwebsocket-clientresolveslocalhostto::1(IPv6), causingPermissionError: [WinError 10013]. Added a_normalize_ws_url()helper that explicitly rewritesws://localhost:tows://127.0.0.1:at all 4 WebSocket connection sites incdp.py. Thanks to @theteleporter for the spot-on diagnosis!
[0.5.5] - 2026-03-23
Fixed
- MCP
download_artifactfailing for report/mind_map/data_table (Issue #107) — The MCPdownload_artifacttool exclusively routed throughdownload_async(), but_dispatch_async()had no handlers forreport,mind_map, ordata_table(only_dispatch_sync()did). Added these three non-streaming types to the async dispatcher so all artifact types are downloadable via the MCP tool. Thanks to @Neophen for the detailed bug report! poll_researchreturningNonefor deep research in multi-task notebooks (Issue #106) — When deep research mutates the task ID internally and the notebook has multiple research tasks,poll_researchreturnedNoneinstead of a valid task. The fallback now prefers anyin_progresstask, then falls back to the most recent task. Thanks to @Neophen for reporting!
[0.5.4] - 2026-03-22
Fixed
- Verb-style
nlm delete sourceTypeError (Issue #104) —nlm delete source <id> --confirmwas crashing withTypeError: delete_source() got an unexpected keyword argument 'source_id'. The verb-style CLI layer inverbs.pywas passingsource_id=source(singular string) but the underlying function expectssource_ids(a list). Fixed the parameter name and wrapped the value in a list. The noun-stylenlm source deletewas unaffected. Thanks to @Le-Yann for the detailed bug report and root cause analysis!
[0.5.3] - 2026-03-22
Improved
- Actionable Error Hints Across CLI & MCP (Issue #103) — All CLI commands and MCP tools now provide structured, user-friendly error messages with actionable hints (e.g., "Run 'nlm login' to authenticate" or "Run 'nlm notebook list' to see available notebooks"). Thanks to @ahnbu for suggesting this improvement!
- CLI: Consolidated error handling via centralized
handle_error()across all 13 command modules. Errors with--jsonflag now output structured JSON ({"status": "error", "error": "...", "hint": "..."}). - MCP: All 27 MCP tools now include
hintfields in error responses for AI agent consumption. - Services:
ServiceErrornow carries an optionalhintattribute, propagated fromNLMErrorexceptions. - Core:
NotebookLMError(parent ofRPCError,ArtifactError, etc.) now inherits fromNLMError, ensuring all low-level API errors are caught and handled gracefully instead of producing raw tracebacks.
- CLI: Consolidated error handling via centralized
Fixed
- Non-ASCII characters in JSON output (PR #100) — CLI JSON output (
--jsonflag) now preserves Unicode characters (e.g.,café,こんにちは) instead of escaping them as\uXXXXsequences via a sharedprint_json()helper withensure_ascii=False. Thanks to @nickyfoto for the contribution. (PR #100)
[0.5.1] - 2026-03-19
Fixed
- Deep Research Transient Errors (Issue #98) — Deep research (
--mode deep) no longer silently fails with a generic "no confirmation from API" message when Google returns a transient error. The structured error payload (e.g.,DeepResearchErrorDetailcode 3) is now properly detected and surfaced with an actionable message: "Google API error code 3 (DeepResearchErrorDetail). This is likely a transient issue. Try again in a few minutes, or use --mode fast." - Research RPC Infrastructure — Refactored
start_research()to use the standard_call_rpc()pipeline instead of raw HTTP calls. This gives deep and fast research automatic auth retry, server error retries, and enhanced debug logging for free.
Added
RPCErrorexception class — New structured error type incore/errors.pyfor Google batchexecute errors with error code, detail type, and detail data attributes. All non-auth RPC errors (not just code 16) are now properly raised.- 6 new unit tests (3 core-level, 3 service-level) for RPCError detection and user-friendly error messages (total: 634 tests)
[0.5.0] - 2026-03-18
Fixed
- Research Import Timeout (Issue #97) —
research importnow uses a 300-second default timeout (up from 120s), fixing consistent timeouts on notebooks with many sources. The timeout is configurable via--timeout/-tin CLI andtimeoutparameter in MCP. - Research Start Deadlock (Issue #97) —
research startno longer hard-exits when previous research has un-imported sources. Instead, it shows a warning and prompts interactively, so users can choose to proceed or import first. Previously, if import timed out, users were stuck — unable to import or start new research without--force.
Added
- Configurable Import Timeout —
nlm research import <notebook> <task-id> --timeout 600for extra-large notebooks. Available in both CLI (--timeout/-t) and MCP (timeoutparameter onresearch_import). Default: 300 seconds. - 2 new unit tests for timeout parameter forwarding (total: 624 tests)
[0.4.9] - 2026-03-16
Added
- CC-Claw Skill Support — Added
cc-clawas a supported tool fornlm skill install cc-claw(~/.cc-claw/workspace/skills/nlm-skill/).
Fixed
- Windows CLI Argument Parsing (Issue #96) — Fixed a bug where running
nlm add url <notebook_id> "https://..."on Windows PowerShell incorrectly parsed the URL string into a list of characters, attempting to add dozens of duplicate sources instead of one. - Service Layer Robustness — Added internal safeguards ensuring single string URL parsing never falls through to character unpacking across the API service boundary.
[0.4.8] - 2026-03-14
Added
- Native Chat History Persistence — Both the CLI (
nlm notebook query) and the MCP server now perfectly persist their chat history directly into the NotebookLM web UI. All prompts sent via CLI or MCP agents will now appear in the notebook's native chat panel, sharing the same conversational context as the web UI. (Closes #92) - OpenCode Support — Full support for OpenCode in the
nlm setupcommand (nlm setup add opencode) to automatically configure the NotebookLM MCP server for OpenCode. Includes smart config array injection and parsing. Thanks to @woohyun212 for the comprehensive implementation and thorough unit tests (PR #95, closes #95).
Fixed
- MCP Profile Switching — Fixed a bug where the MCP server wouldn't respect dynamic authentication profile changes made via
nlm login switch <profile>. The server now automatically detects token file changes and gracefully reloads the NotebookLM client in real-time, matching the active profile perfectly. - CC-Claw Skill Support — Added
cc-clawas a supported tool fornlm skill install cc-claw(~/.cc-claw/workspace/skills/nlm-skill/).
[0.4.7] - 2026-03-13
Changed
- Skill path migration:
.gemini/skills/→.agents/skills/— Starting with Gemini CLI v0.33.1,.agents/skills/is the recommended cross-tool compatible path (higher priority than.gemini/skills/).nlm skill install gemini-cliandnlm skill install codexare replaced bynlm skill install agents, which installs to~/.agents/skills/nlm-skill/. This path works for Gemini CLI, Codex, and any tool that reads.agents/skills/. Users with existinggemini-cliorcodexinstallations should runnlm skill install agentsto reinstall at the new location. - Documentation updates — Added v0.4.6 features (batch, cross-notebook, pipelines, tags) to SKILL.md, AGENTS_SECTION.md, and API_REFERENCE.md. Removed stale QUICK_REFERENCE.md.
[0.4.6] - 2026-03-12
Added
- Batch Operations — Perform actions across multiple notebooks at once. Thanks to @fabianafurtadoff for this contribution (PR #90)!
nlm batch query— Query multiple notebooks with the same questionnlm batch add-source— Add a URL to multiple notebooksnlm batch create— Create multiple notebooks at oncenlm batch delete— Delete multiple notebooks (requires--confirm)nlm batch studio— Generate artifacts across multiple notebooks- MCP: Consolidated
batchtool withactionparameter (query|add_source|create|delete|studio)
- Cross-Notebook Query — Query multiple notebooks and get aggregated answers with per-notebook citations. (PR #90, @fabianafurtadoff)
nlm cross query "question" --notebooks "id1,id2"— Ask across specific notebooksnlm cross query "question" --tags "ai,research"— Query by tag- MCP:
cross_notebook_querytool
- Pipelines — Define and execute multi-step notebook workflows. (PR #90, @fabianafurtadoff)
nlm pipeline list— List available pipelines (3 builtin: ingest-and-podcast, research-and-report, multi-format)nlm pipeline run <notebook> <pipeline-name>— Execute a pipeline- User-defined pipelines via YAML files in
~/.notebooklm-mcp-cli/pipelines/ - MCP: Consolidated
pipelinetool withactionparameter (run|list)
- Smart Select & Tagging — Tag notebooks and find relevant ones by keyword matching. (PR #90, @fabianafurtadoff)
nlm tag add <notebook> --tags "ai,research"— Add tagsnlm tag remove <notebook> --tags "ai"— Remove tagsnlm tag list— List all tagged notebooksnlm tag select "query"— Find notebooks by tag match- MCP: Consolidated
tagtool withactionparameter (add|remove|list|select)
- Studio List Types — Reference of all artifact types and their options, accessible via
studio_status(action="list_types") - 73 new unit tests covering all new service modules (total: 576 tests)
Changed
- MCP Tool Consolidation — Reduced 13 new tools to 4 consolidated tools with action parameters, keeping total MCP tools at 35 (down from what would have been 44). Follows existing patterns (
note,source_add).
Fixed
- CLI import violations — Fixed 3 CLI command files (
batch.py,cross.py,pipeline.py) importingget_clientfrommcp/tools/_utilsinstead ofcli/utils, violating architecture layering - Missing UTF-8 encoding — Added
encoding='utf-8'to 6 file I/O calls insmart_select.pyandpipeline.pyto preventUnicodeDecodeErroron Windows - Cross-notebook display crash — Fixed
sources_usedfield handling incross.pydisplay formatting (could crash on string values)
[0.4.5] - 2026-03-10
Fixed
nlm doctorcrash on Windows (Issue #87) — FixedUnicodeDecodeErrorwhen runningclaude mcp liston Windows systems with non-UTF-8 default encodings (e.g.,cp936,cp1252). Added explicitencoding="utf-8"anderrors="replace"to the subprocess call. Also added a null check forresult.stdoutto preventAttributeErrorwhen the subprocess returns no output.- Silent Chrome launch failures on Windows (Issue #86) —
launch_chrome_processwas silently swallowing allsubprocess.Popenexceptions, causingnlm loginto report the cryptic "Cannot connect to browser on port XXXX" with no indication of what went wrong. Now logs the browser path, port, and exception details so users get actionable error messages. Added debug logging for successful launches as well.
[0.4.4] - 2026-03-08
Fixed
- Complex citation parsing (PR #84) — Fixed
notebook_querydropping cited text when Google returns "direct" citation segments (integer-first elements) alongside the standard "wrapped" format. Both segment variants are now correctly handled. Thanks to @meirtsvi for this contribution! - Table citation extraction (PR #84) — When a citation references a data table, the response now includes a structured
cited_tablefield withnum_columnsandrowsdata. Table segments are indicated by a<cited_table>placeholder in thecited_textfield. - Mind map JSON missing from MCP response (Issue #83) —
studio_createfor mind maps was returning metadata (root_name,children_count) but dropping the actualmind_map_json. The full JSON now flows through to MCP clients. Thanks to @cowhi for reporting!
Added
- 17 new unit tests for citation parsing — Comprehensive test coverage for direct/wrapped segment detection, table placeholder insertion,
_extract_text_from_table_rows,_extract_table_from_detail, andcited_tablein_extract_citation_data. Total tests: 503.
[0.4.3] - 2026-03-08
Removed
nlm setup add claude-desktopremoved — Claude Desktop users should install via the.mcpbextension (download from Releases, double-click to install). The CLI-based config file editing was unreliable compared to the extension approach.nlm setup add claude-code(for the Claude Code CLI) is unchanged.
[0.4.2] - 2026-03-08
Added
- Expanded file format support (PR #82) — File uploads now accept additional formats. Thanks to @JumpLao for this contribution!
- Audio:
.m4a,.wav,.aac,.ogg,.opus(previously only.mp3) - Images:
.gif,.webp(previously only.jpg,.jpeg,.png) - Note:
.flac,.webm,.mov,.avi,.mkvwere removed from the original PR as Google's upload server does not accept them
- Audio:
- Cited text passages in query output (PR #81) —
notebook_queryresponses now include areferencesarray with the actual quoted passage text for each citation. Previously, only the source ID and citation number were returned; the passage text was already in the API response but was being discarded. Thanks to @cbruyndoncx for this contribution!- Each reference includes
source_id,citation_number, andcited_text - Backward-compatible: existing
sources_usedandcitationsfields unchanged - Flows through MCP and CLI automatically
- Each reference includes
nlm setup add all— Interactive multi-tool setup — Scans the system for installed AI tools, shows detection status, and lets you interactively choose which ones to configure with NotebookLM MCP- Detects: Claude Code, Claude Desktop, Gemini CLI, Cursor, Windsurf, Cline, Antigravity, Codex
- Shows which tools are already configured vs. newly detected
- Select
all, specific numbers, ornone
nlm setup remove all— Remove NotebookLM MCP from all configured tools at once, with explicit confirmation and safety warnings. Uses CLI-first removal (e.g.,claude mcp remove) where available.
Changed
- Codex skill path updated —
nlm skill install codexnow installs to~/.agents/skills/nlm-skill/SKILL.mdper official Codex docs, replacing the old~/.codex/AGENTS.mdpath. Users with the old installation should runnlm skill install codexto reinstall at the correct location.
[0.4.1] - 2026-03-07
Added
- Cinematic Video Format (Experimental) — Added support for NotebookLM's new "Cinematic" video format (
video_format="cinematic", format code3). This format produces higher-fidelity video overviews and is available to NotebookLM Plus/Ultra subscribers. Thanks to @ovai-felix for the detailed reverse-engineering and verified payload structure (Issue #79).- Core: Cinematic payloads use a 5-element inner options array (omitting
visual_style_code), while Explainer/Brief continue to use 6 elements - MCP:
studio_createwithvideo_format="cinematic" - CLI:
nlm video create <notebook> --format cinematic - ⚠️ Note for free/Pro users: Cinematic is gated behind NotebookLM Plus/Ultra. Free and Pro tier users will see:
"NotebookLM rejected video creation. Try again later or create from NotebookLM UI for diagnosis."— this is expected behavior, not a bug.
- Core: Cinematic payloads use a 5-element inner options array (omitting
Fixed
- Claude Desktop
.mcpbextension disconnects (Issue #78) — The.mcpbbundle was incomplete (only containedmanifest.jsonwith no entrypoint) and relied onuvxbeing in PATH, which Claude Desktop's restricted macOS environment doesn't expose. Fixed by bundling a cross-platform Python launcher (run_server.py) that defensively resolvesuvxacross common install locations (~/.local/bin,~/.cargo/bin,/opt/homebrew/bin, etc.) and using${__dirname}for reliable path resolution. Thanks to @abanoub-ashraf for the detailed diagnosis and reproduction steps.
[0.4.0] - 2026-03-05
Added
- Bulk Sharing (
notebook_share_batch) — Invite multiple collaborators to a notebook in a single API call (Issue #73). Supports mixed roles (viewer/editor) per recipient.- Core:
add_collaborators_bulk(notebook_id, recipients)onSharingMixin - Service:
invite_collaborators_bulk(client, notebook_id, recipients)with upfront validation - MCP:
notebook_share_batchtool withrecipientslist andconfirmflag - CLI:
nlm share batch <notebook> "a@gmail.com,b@gmail.com" --role viewer
- Core:
- 10 new unit tests for bulk sharing (core + services)
Fixed
- Version mismatch (Patch) — Bump internal
__version__string in__init__.pyto correctly report version (was omitted in0.3.20release).
[0.3.20] - 2026-03-04
Fixed
- Type errors, thread safety, and silent exceptions (PR #74)
- Added Double-Checked Locking (
threading.Lock) for thread-safe client initialization in MCP tools. - Surfaced previously swallowed exceptions for better debug visibility via
logger.debug(). - Fixed multiple type annotations (
str = None->str | None = None) across the codebase. - Replaced unreachable code with explicit
ValidationErrorthrowing to ensure strict type checking completeness. - Thanks to @adlewis82 for the excellent cleanup and safety improvements!
- Added Double-Checked Locking (
[0.3.19] - 2026-03-02
Fixed
- JSON output word wrapping (Issue #72) — CLI commands using
-jflag (note list,share status,export artifact,config show) were producing invalid JSON due to Rich console wrapping long strings at terminal width. JSON output now bypasses Rich and goes directly to stdout. Thanks to @pjeby for reporting.
[0.3.18] - 2026-03-02
Added
- Infographic visual styles — Infographics now support 11 visual styles matching the NotebookLM web UI:
auto_select,sketch_note,professional,bento_grid,editorial,instructional,bricks,clay,anime,kawaii,scientific. Available via MCP (infographic_styleparameter onstudio_create), CLI (--styleflag onnlm infographic create), and Python API (visual_style_codeoncreate_infographic()). Default isauto_selectfor backward compatibility.
[0.3.17] - 2026-03-02
Added
- Multi-browser support for
nlm login—nlm loginnow detects and launches any Chromium-based browser, not just Google Chrome. Supported browsers (in priority order): Google Chrome, Arc (macOS), Brave, Microsoft Edge, Chromium, Vivaldi, Opera. Checks both system and user-local install paths. Error messages now dynamically list supported browsers per platform. Thanks to @devnull03 for this contribution (PR #70). - Browser preference setting — Users can now control which browser
nlm loginuses vianlm config set auth.browser <name>. Valid values:auto(default, first found wins),chrome,arc,brave,edge,chromium,vivaldi,opera. Falls back to auto-detection if the preferred browser is not installed. Also settable viaNLM_BROWSERenv var.
Fixed
- Deep research task_id mismatch (Issue #69) —
nlm research status <nb> --task-id <id>returned "no research found" for deep research because the backend assigns a new task_id internally. Now falls back to returning the only active task when the original task_id doesn't match. Thanks to @danielbrodie for reporting.
[0.3.16] - 2026-02-28
Fixed
- Chrome profile isolation bug:
nlm logincould reuse a Chrome instance from a different NLM profile. Implemented port-to-profile mapping to guarantee strict cross-profile isolation. - Auto-retry on Google account mismatch: When switching NLM profiles (or when multiple users log in on the same machine), Chrome can cache the wrong Google login. The builtin login provider now detects
AccountMismatchError, automatically clears the stale Chrome user-data-dir, and relaunches Chrome for a fresh Google sign-in. nlm login profile deletevalidation: Profile deletion was failing for broken/invalid profiles because it strictly checked for valid cookies. Now it checks if the profile directory exists, allowing deletion of empty/corrupt profiles.
[0.3.15] - 2026-02-26
Added
nlm setup add json— Interactive JSON config generator — Runnlm setup add jsonto generate an MCP JSON config snippet for any tool not directly supported. Interactive wizard with numbered prompts lets you choose uvx vs regular mode, full path vs command name, and whether to include themcpServerswrapper. Prints syntax-highlighted JSON and offers clipboard copy on macOS.
[0.3.14] - 2026-02-26
Fixed
- MCP server instructions: incorrect parameter names — The consolidated tools summary in the MCP server instructions advertised
type=forsource_add,studio_create, anddownload_artifact, but the actual tool schemas usesource_typeandartifact_type. AI clients reading the instructions would use wrong parameter names, causing validation errors. Also added value parameter hints forsource_add.
[0.3.13] - 2026-02-26
Added
- Bulk Source Add — Add multiple URL sources in a single API call, dramatically reducing round-trips and avoiding rate limits (Issue #57).
- Core:
add_url_sources(notebook_id, urls)onSourceMixin - Service:
add_sources(client, notebook_id, sources)— batches URL sources automatically, falls back to individual calls for other types - MCP:
source_addnow accepts optionalurlslist parameter for bulk URL add - CLI:
nlm source add <notebook> --url https://a.com --url https://b.com(repeatable--urlflag)
- Core:
- Bulk Source Delete — Delete multiple sources in a single API call.
- Core:
delete_sources(source_ids)onSourceMixin - Service:
delete_sources(client, source_ids)with validation - MCP:
source_deletenow accepts optionalsource_idslist parameter for bulk delete - CLI:
nlm source delete <id1> <id2> <id3> --confirm(variadic arguments)
- Core:
- 12 new unit tests for bulk add/delete service functions (total: 443 tests)
[Unreleased / 0.3.12]
Fixed
- Source additions bypassing Token Refresh - Refactored
add_url_source,add_drive_source,add_text_source, and multiple other methods incore/sources.pyto use the unified_call_rpcmechanism instead of rawclient.postrequests. This ensures that adding sources now properly benefits from the automatic session/CSRF token refresh if authentication unexpectedly expires (Issue #62). - Notebook operations bypassing Token Refresh - Refactored
list_notebooksanddelete_notebookincore/notebooks.pyto use_call_rpc, ensuring they recover from expired CSRF tokens just like other core operations. Thanks to @byingyang for identifying this in PR #61. - OpenClaw skill path - Fixed incorrect installation path for OpenClaw skills (
workplace->workspace) in code and documentation. Thanks to @maxcanada for reporting (Issue #63). create slidesdefault format - Fixed a bug wherecreate slideswould error because it used an invalid format fallback. It now correctly defaults todetailed_deck. Added comprehensive tests for all verb defaults. (PR #64)
[0.3.11] - 2026-02-22
Added
- Auto-extract build label (
bl) - TheblURL parameter is now automatically extracted from the NotebookLM page duringnlm loginand CSRF token refresh, instead of using a hardcoded value that goes stale every few weeks. This keeps API requests current with Google's latest build without any manual steps. TheNOTEBOOKLM_BLenv var still works as an override. Thesave_auth_tokensMCP tool also extractsblfrom therequest_urlparameter when provided.
Fixed
sources_usednow populated in query responses - Thesources_usedfield was always returning[]even when the AI's answer contained citation markers like[1],[2]. Google's response includes citation-to-source mapping data that was present but never parsed. Query responses now correctly returnsources_used(list of cited source IDs) andcitations(dict mapping each citation number to its parent source ID). This also enables the REPL's citation legend feature. Thanks to @MinhDung2209 for reporting (issue #57).
[0.3.10] - 2026-02-22
Added
- Source Rename (
source_rename) — Rename any source within a notebook via new RPCb7Wfje.- MCP tool:
source_renamewithnotebook_id,source_id, andnew_titleparams - CLI:
nlm source rename <source-id> <title> --notebook <notebook-id> - Verb-first alias:
nlm rename source <source-id> <title> --notebook <notebook-id>
- MCP tool:
[0.3.9] - 2026-02-22
Added
--clearflag fornlm login- Added a--clearflag that wipes the cached Chrome profile before logging in. This solves an issue wherenlm loginwould auto-login to an old, cached account without letting the user switch profiles or emails.
Fixed
- Accurate Email Extraction - Fixed a bug in
extract_emailwhere the CLI would sometimes grab a shared note author's email off the dashboard instead of the logged-in user. The regex now prioritizes actual internal Google account fields before falling back to generic matching. - Skipping Migration on Clear - Fixed an issue where using
--clearwould cause the CLI to mistakenly run a migration step from older CLI versions, reinstating the wrong account profile.
[0.3.8] - 2026-02-22
Added
- CLI
--debugFlag -nlm --debug <command>enables debug logging across all CLI commands, showing raw API responses and internal state. Useful for diagnosing API issues.
Fixed
- Google API errors no longer silently swallowed - When Google returns an error response (e.g.,
INVALID_ARGUMENT,UserDisplayableError) instead of an answer, the CLI now surfaces a clear error message instead of returning an empty answer. Previously, queries would succeed with{'answer': ''}and no indication of what went wrong. Thanks to @MinhDung2209 for the detailed debugging that uncovered this (issue #57).
[0.3.7] - 2026-02-22
Added
- Configurable Interface Language (
NOTEBOOKLM_HL) - SetNOTEBOOKLM_HLenv var to control both the API'shlURL parameter and the default artifact creation language. Explicit--languageflags still take priority. Thanks to @beausea for this contribution (PR #59, closes #58).
[0.3.6] - 2026-02-22
Added
- Query Timeout Flag -
nlm notebook queryandnlm query notebooknow accept--timeout/-tto set query timeout in seconds (default: 120). Useful for long extraction prompts that need more processing time (closes #57).
[0.3.5] - 2026-02-21
Added
- Slide Deck Revision (
studio_revise) — Revise individual slides in an existing slide deck via new RPCKmcKPe. Creates a new artifact with revisions applied; original is never modified.- MCP tool:
studio_revisewithartifact_id,slide_instructions, andconfirmparams - CLI:
nlm slides revise <artifact-id> --slide '1 Make the title larger' --confirm
- MCP tool:
- PPTX Download Support — Download slide decks as PowerPoint (PPTX) in addition to PDF.
- CLI:
nlm download slide-deck <notebook> --format pptx - MCP:
download_artifactwithslide_deck_format="pptx"
- CLI:
- Login Profile Protection — Account mismatch guard prevents accidentally overwriting a profile with credentials from a different Google account. Use
--forceto override. - Reused Chrome Warning —
nlm loginnow warns when connecting to an existing Chrome instance instead of launching a fresh one.
Changed
- Faster Login — Connection pooling and reduced sleep durations cut
nlm logintime from ~25s to under 3s. Thanks to @pjeby for this contribution (PR #54).
[0.3.4] - 2026-02-19
Fixed
nlm loginhang on fresh install - Optimized Chrome port availability scanning (usingsocket.bindinstead ofhttpx.get) to avoid 20+ second timeouts on systems that drop network packets. Thanks to @pjeby for the diagnosis (closes #52)- Chrome "Restore Pages" Warning -
nlm loginand headless authentication now perform a graceful shutdown of Chrome via CDP (Browser.close) rather than abruptly killing the process, resolving crashes on next browser start. Again, great work by @pjeby (fixes #52)
[0.3.3] - 2026-02-16
Fixed
- OpenClaw skill path - Fixed incorrect installation path for OpenClaw skills. Now correctly uses
~/.openclaw/workspace/skills/instead of~/.openclaw/skills/.
[0.3.2] - 2026-02-14
Added
- Focus Prompt Support - Added
--focusparameter tonlm quiz createandnlm flashcards createcommands to specify custom instructions. - Improved Prompt Extraction -
studio_statusnow correctly extracts custom prompts for all artifact types (Audio, Video, Slides, Quiz, Flashcards).
Fixed
- Quiz/Flashcard Prompt Extraction - Fixed a bug where custom instructions were not being extracted for Quiz and Flashcards artifacts (wrong API index).
[0.3.1] - 2026-02-14
Added
- New AI Client Support — Added
nlm skill installsupport for:- Cline (
~/.cline/skills) - Terminal-based AI agent - Antigravity (
~/.gemini/antigravity/skills) - Advanced agentic framework - OpenClaw (
~/.openclaw/workspace/skills) - Autonomous AI agent - Codex (
~/.codex/AGENTS.md) - Now with version tracking
- Cline (
nlm setupsupport — Added automatic MCP configuration for:- Cline (
nlm setup add cline) - Antigravity (
nlm setup add antigravity)
- Cline (
nlm skill updatecommand - Update installed AI skills to the latest version. Supports updating all skills or specific tools (e.g.,nlm skill update claude-code).- Verb-first alias -
nlm update skillworks identically tonlm skill update. - Version tracking -
AGENTS.mdformats now support version tracking via injected comments.
Fixed
- Skill version validation -
nlm skill listnow correctly identifies outdated skills and prevents "unknown" version status for Codex. - Package version - Bumped to
0.3.1to match release tag.
[0.3.0] - 2026-02-13
Added
- Shared service layer (
services/) — 10 domain modules centralizing all business logic previously duplicated across CLI and MCP:errors.py: Custom error hierarchy (ServiceError,ValidationError,NotFoundError,CreationError,ExportError)chat.py: Chat configuration and notebook query logicdownloads.py: Artifact downloading with type/format resolutionexports.py: Google Docs/Sheets exportnotebooks.py: Notebook CRUD, describe, query consolidationnotes.py: Note CRUD operationsresearch.py: Research start, polling, and source importsharing.py: Public link, invite, and status managementsources.py: Source add/list/sync/delete with type validationstudio.py: Unified artifact creation (all 9 types), status, rename, delete
- 372 unit tests covering all service modules (up from 331)
Changed
- Architecture: strict layering —
cli/andmcp/are now thin wrappers delegating toservices/. Neither imports fromcore/directly. - MCP tools refactored — Significant line count reductions across all tool files (e.g., studio 461→200 lines)
- CLI commands refactored — Business logic extracted to services, CLI retains only UX concerns (prompts, spinners, formatting)
- Contributing workflow updated — New features follow:
core/client.py→services/*.py→mcp/tools/*.py+cli/commands/*.py→tests/services/
[0.2.22] - 2026-02-13
Fixed
- Fail-fast for all studio create commands — Audio, report, quiz, flashcards, slides, video, and data-table creation now exit non-zero with a clear error when the backend returns no artifact, instead of silently reporting success. Extends the infographic fix from v0.2.21 to all artifact types (closes #33)
[0.2.21] - 2026-02-13
Added
- OpenClaw CDP login provider —
nlm login --provider openclaw --cdp-url <url>allows authentication via an already-running Chrome CDP endpoint (e.g., OpenClaw-managed browser sessions) instead of launching a separate Chrome instance. Thanks to @kmfb for this contribution (PR #47) - CLI Guide documentation for
nlm setupandnlm doctor— Added Setup and Doctor command reference sections, updated workflow example, and added tips. Cherry-picked from PR #48 by @997unix
Fixed
- Infographic create false success —
nlm infographic createnow exits non-zero with a clear error when the backend returnsUserDisplayableErrorand no artifact, instead of silently reporting success (closes #46). Thanks to @kmfb (PR #47) - Studio status code 4 mapping — Studio artifact status code
4now maps to"failed"instead of"unknown", making artifact failures visible during polling. By @kmfb (PR #47)
Changed
- CDP websocket compatibility — WebSocket connections now use
suppress_origin=Truefor compatibility with managed Chrome endpoints, with fallback for olderwebsocket-clientversions
[0.2.20] - 2026-02-11
Added
- Claude Desktop Extension detection —
nlm setup listandnlm doctornow detect NotebookLM when installed as a Claude Desktop Extension (.mcpb), showing version and enabled state.
Fixed
- Shell tab completion crash — Fixed
nlm setup add <TAB>crashing withTypeErrordue to incorrect completion callback signature.
[0.2.19] - 2026-02-10
Added
- Automatic retry on server errors — Transient errors (429, 500, 502, 503, 504) are now retried up to 3 times with exponential backoff. Special thanks to @sebsnyk for the suggestion in #42.
--jsonflag for more commands — Added structured JSON output tonotebook describe,notebook query,source describe, andsource content. JSON output is also auto-detected when piping. Thanks to @sebsnyk for the request in #43.
Changed
- Error handling priority — Server error retry now executes before authentication recovery.
- AI docs & Skills updated — specific documentation on retry behavior and expanded
--jsonflags.
[0.2.18] - 2026-02-09
Added
- Claude Desktop Extension (.mcpb) — One-click install for Claude Desktop. Download the
.mcpbfile from the release page, double-click to install. No manual config editing required. - MCPB build automation —
scripts/build_mcpb.pyreads version frompyproject.toml, syncsmanifest.json, and packages the.mcpbfile. Old builds are auto-cleaned. - GitHub Actions release asset —
.mcpbfile is automatically built and attached to GitHub Releases alongside PyPI publish. nlm doctorandnlm setupdocumentation — Added to AI docs (nlm --ai) and skill file.
Changed
- Manifest uses
uvx— Claude Desktop extension now usesuvx --from notebooklm-mcp-cli notebooklm-mcpfor universal PATH compatibility.
Removed
- Cleaned up
PROJECT_RECAP.mdandtodo.md(outdated development artifacts).
[0.2.17] - 2026-02-08
Added
nlm setupcommand - Automatically configure NotebookLM MCP for AI tools (Claude Code, Claude Desktop, Gemini CLI, Cursor, Windsurf). No more manual JSON editing! Thanks to @997unix for this contribution (PR #39)nlm setup list- Show configuration status for all supported clientsnlm setup add <client>- Add MCP server config to a clientnlm setup remove <client>- Remove MCP server config
nlm doctorcommand - Diagnose installation and configuration issues in one command. Checks authentication, Chrome profiles, and AI tool configurations. Also by @997unix (PR #39)
Fixed
- Version check not running - Update notifications were never shown after CLI commands because
typer.Exitexceptions bypassed the check. Movedprint_update_notification()to afinallyblock so it always runs. - Missing import in setup.py - Fixed
import osplacement for Windows compatibility
[0.2.16] - 2026-02-05
Fixed
- Windows JSON parse errors - Added
show_banner=Falsetomcp.run()to prevent FastMCP banner from corrupting stdio JSON-RPC protocol on Windows (fixes #35) - Stdout pollution in MCP mode - Replaced
print()with logging inauth.pyandnotebooks.pyto avoid corrupting JSON-RPC output - Profile handling in login check - Fixed
nlm login --checkto use config'sdefault_profileinstead of hardcoded "default"
[0.2.15] - 2026-02-04
Fixed
- Chat REPL command broken - Fixed
nlm chat startfailing withTypeError: BaseClient.__init__() got an unexpected keyword argument 'profile'. Now uses properget_client(profile)utility and handles dict/list API responses correctly. Thanks to @eng-M-A-AbelLatif for the detailed bug report and fix in issue #25!
Removed
- Dead code cleanup - Removed unused
src/notebooklm_mcp/directory. This legacy code was not packaged or distributed but caused confusion (e.g., PR #29 targeted it thinking it was active). The active MCP server isnotebooklm_tools.mcp.server. Thanks to @NOirBRight for PR #29 which helped identify this dead code.
Changed
- Updated tests - Removed references to deleted
notebooklm_mcppackage from test suite.
Community Contributors
This release also acknowledges past community contributions that weren't properly thanked:
- @latuannetnam for HTTP transport support, debug logging, and query timeout configuration (PR #12)
- @davidszp for Linux Chrome detection fix (PR #6) and source_get_content tool (PR #1)
- @saitrogen for the research polling query fallback fix (PR #15)
[0.2.14] - 2026-02-03
Fixed
- Automatic migration from old location - Auth tokens and Chrome profiles are automatically migrated from
~/.notebooklm-mcp/to~/.notebooklm-mcp-cli/on first use. Users upgrading from older versions don't need to re-authenticate.
[0.2.13] - 2026-02-03
Fixed
- Unified storage location - Consolidated all storage to
~/.notebooklm-mcp-cli/. Previously some code still referenced the old~/.notebooklm-mcp/location, causing confusion. Now everything uses the single unified location. - Note: v0.2.13 was missing migration support - upgrade to v0.2.14 instead.
[0.2.12] - 2026-02-03
Removed
notebooklm-mcp-authstandalone command - The standalone authentication tool has been officially deprecated and removed. Usenlm logininstead, which provides all the same functionality with additional features like named profiles. The headless auth for automatic token refresh continues to work behind the scenes.
Fixed
- Auth storage inconsistency - Previously,
notebooklm-mcp-authstored tokens in a different location thannlm login, causing "Authentication expired" errors. Now there's only one auth path vianlm login. - Documentation typo - Fixed
nlm download slides→nlm download slide-deckin CLI guide.
[0.2.11] - 2026-02-02
Fixed
nlm loginnot launching Chrome - Runningnlm loginwithout arguments now properly launches Chrome for authentication instead of showing help. Workaround for v0.2.10: usenlm login -p default.
[0.2.10] - 2026-01-31
Fixed
- Version mismatch - Synchronized version numbers across all package files
[0.2.9] - 2026-01-31
Changed
- Documentation alignment - Unified MCP and CLI documentation with comprehensive test plan
- Build configuration - Moved dev dependencies to optional-dependencies for standard compatibility
Fixed
- Studio custom focus prompt - Extract custom focus prompt from correct position in API response
[0.2.7] - 2026-01-30
Removed
- Redundant CLI commands - Removed
nlm download-verbandnlm research-verb(usenlm downloadandnlm researchinstead)
Fixed
- Documentation alignment - Synchronized all CLI documentation with actual CLI behavior:
- Fixed export command syntax:
nlm export to-docs/nlm export to-sheets(notdocs/sheets) - Fixed download command syntax: use
-oflag for output path - Fixed slides format values:
detailed_deck/presenter_slides(notdetailed/presenter) - Removed non-existent
nlm mindmap listfrom documentation
- Fixed export command syntax:
[0.2.6] - 2026-01-30
Fixed
- Source List Display: Fixed source list showing empty type by using
source_type_namekey correctly
[0.2.5] - 2026-01-30
Added
- Unified Note Tool - Consolidated 4 separate note tools (
note_create,note_list,note_update,note_delete) into a singlenote(action=...)tool - CLI Shell Completion - Enabled shell tab completion for
nlm skilltool argument - Documentation Updates - Updated
SKILL.md,command_reference.md,troubleshooting.md, andworkflows.mdwith latest features
Fixed
- Fixed
nlm skill install otherautomatically switching to project level - Fixed
research_statushandling ofNonetasks in response - Fixed note creation returning failure despite success (timing issue with immediate fetch)
[0.2.4] - 2026-01-29
Added
- Skill Installer for AI Coding Assistants (
nlm skillcommands)- Install NotebookLM skills for Claude Code, OpenCode, Gemini CLI, Antigravity, Cursor, and Codex
- Support for user-level (
~/.config) and project-level installation - Parent directory validation with smart prompts (create/switch/cancel)
- Installation status tracking with
nlm skill list - Export all formats with
nlm skill install other - Unified CLI/MCP skill with intelligent tool detection logic
- Consistent
nlm-skillfolder naming across all installations - Complete documentation in AI docs (
nlm --ai)
- Integration tests for all CLI bug fixes (9 tests covering error handling, parameter passing, alias resolution)
nlm login profile renamecommand for renaming authentication profiles- Multi-profile Chrome isolation - each authentication profile now uses a separate Chrome session, allowing simultaneous logins to multiple Google accounts
- Email capture during login - profiles now display associated Google account email in
nlm login profile list - Default profile configuration -
nlm config set auth.default_profile <name>to avoid typing--profilefor every command - Auto-cleanup Chrome profile cache after authentication to save disk space
Fixed
- Fixed
console.printusing invaliderr=Trueparameter (now useserr_console = Console(stderr=True)) - Fixed verb-first commands passing OptionInfo objects instead of parameter values
- Fixed studio command parameter mismatches (format→format_code, length→length_code, etc.)
- Fixed studio methods not handling
source_ids=None(now defaults to all notebook sources)
Changed
- Consolidated auth commands under login - replaced
nlm auth status/list/deletewithnlm login --checkandnlm login profile list/delete/rename - Studio commands now work without explicit
--source-idsparameter (defaults to all sources in notebook) - Download commands now support notebook aliases (auto-resolved via
get_alias_manager().resolve()) - Added
--confirmflag tonlm alias deletecommand - Updated all documentation to reflect login command structure
[0.2.0] - 2026-01-25
Major Release: Unified CLI & MCP Package (Code Name: "Cancun Wind")
This release unifies the previously separate notebooklm-cli and notebooklm-mcp-server packages into a single notebooklm-mcp-cli package. One install now provides both the nlm CLI and notebooklm-mcp server.
Added
Unified Package
- Single
notebooklm-mcp-clipackage replaces separate CLI and MCP packages - Automatic migration from legacy packages (Chrome profiles and aliases preserved)
- Three executables:
nlm(CLI),notebooklm-mcp(MCP server),notebooklm-mcp-auth(auth tool)
File Upload
- Direct file upload via HTTP resumable protocol (PDF, TXT, Markdown, Audio)
- No browser automation needed for uploads
- File type validation with clear error messages
--waitparameter to block until source is ready
Download System
- Unified download commands for all artifact types (audio, video, reports, slides, infographics, mind maps, data tables)
- Streaming downloads with progress bars
- Interactive artifact support - Quiz and flashcards downloadable as JSON, Markdown, or HTML
- Alias support in download commands
Export to Google Workspace
- Export Data Tables to Google Sheets (
nlm export sheets) - Export Reports to Google Docs (
nlm export docs)
Notes API
- Full CRUD operations:
nlm note create/list/update/delete - MCP tools:
note_create,note_list,note_update,note_delete
Sharing API
- View sharing status and collaborators (
nlm share status) - Enable/disable public link access (
nlm share public/private) - Invite collaborators by email with role selection (
nlm share invite)
Multi-Profile Authentication
- Named profiles for multiple Google accounts (
nlm login --profile <name>) - Profile management:
nlm login profile list/delete/rename - Each profile gets isolated Chrome session (no cross-account conflicts)
Dual CLI Command Structure
- Noun-first:
nlm notebook list,nlm source add,nlm studio create - Verb-first:
nlm list notebooks,nlm add url,nlm create audio - Both styles work interchangeably
AI Coding Assistant Integration
- Skill installer for Claude Code, Cursor, Gemini CLI, Codex, OpenCode, Antigravity
nlm skill install <tool>adds NotebookLM expertise to AI assistants- User-level and project-level installation options
MCP Server Improvements
- HTTP transport mode (
notebooklm-mcp --transport http --port 8000) - Debug logging (
notebooklm-mcp --debug) - Consolidated from 45+ tools down to 28 unified tools
- Modular server architecture with mixins
Research Improvements
- Query fallback for more reliable research polling
- Better status tracking for deep research tasks
- Task ID filtering for concurrent research operations
Changed
- Storage location moved to
~/.notebooklm-mcp-cli/ - Client refactored into modular mixin architecture (BaseClient, NotebookMixin, SourceMixin, etc.)
- MCP tools consolidated (e.g., separate
notebook_add_url/text/drive→ unifiedsource_add)
[0.1.14] - 2026-01-17
Fixed
- Critical Research Stability:
poll_researchnow accepts status code6(Imported) as success, fixing "hanging" Fast Research.- Added
target_task_idfiltering topoll_researchto ensure the correct research task is returned (essential for Deep Research). - Updated
research_statusandresearch_importto use task ID filtering. research_statustool now accepts an optionaltask_idparameter.
- Missing Source Constants:
- Included the code changes for
SOURCE_TYPE_UPLOADED_FILE,SOURCE_TYPE_IMAGE, andSOURCE_TYPE_WORD_DOCthat were omitted in v0.1.13.
- Included the code changes for
[0.1.13] - 2026-01-17
Added
- Source type constants for proper identification of additional source types:
SOURCE_TYPE_UPLOADED_FILE(11): Direct file uploads (e.g., .docx uploaded directly)SOURCE_TYPE_IMAGE(13): Image files (GIF, JPEG, PNG)SOURCE_TYPE_WORD_DOC(14): Word documents via Google Drive
- Updated
SOURCE_TYPESCodeMapper withuploaded_file,image, andword_docmappings
[0.1.12] - 2026-01-16
Fixed
- Standardized source timeouts (supersedes #9)
- Renamed
DRIVE_SOURCE_TIMEOUTtoSOURCE_ADD_TIMEOUT(120s) - Applied to all source additions: Drive, URL (websites/YouTube), and Text
- Added graceful timeout handling to
add_url_sourceandadd_text_source - Prevents timeout errors when importing large websites or documents
- Renamed
[0.1.11] - 2026-01-16
Fixed
- Close Chrome after interactive authentication - Chrome is now properly terminated after
notebooklm-mcp-authcompletes, releasing the profile lock and enabling headless auth for automatic token refresh - Improve token reload from disk - Removed the 5-minute timeout when reloading tokens during auth recovery. Previously, cached tokens older than 5 minutes were ignored even if the user had just run
notebooklm-mcp-auth
These fixes resolve "Authentication expired" errors that occurred even after users re-authenticated.
[0.1.10] - 2026-01-15
Fixed
- Timeout when adding large Drive sources (fixes #9)
- Extended timeout from 30s to 120s for Drive source operations
- Large Google Slides (100+ slides) now add successfully
- Returns
status: "timeout"instead of error when timeout occurs, indicating operation may have succeeded - Added
DRIVE_SOURCE_TIMEOUTconstant inapi_client.py
[0.1.9] - 2026-01-11
Added
- Automatic re-authentication - Server now survives token expirations without restart
- Three-layer recovery: CSRF refresh → disk reload → headless Chrome auth
- Works with long-running MCP sessions (e.g., MCP Super Assistant proxy)
refresh_authMCP tool for explicit token reloadrun_headless_auth()function for background authentication (if Chrome profile has saved login)has_chrome_profile()helper to check if profile exists
Changed
launch_chrome()now returnssubprocess.Popenhandle instead ofboolfor cleanup control_call_rpc()enhanced with_deep_retryparameter for multi-layer auth recovery
[0.1.8] - 2026-01-10
Added
constants.pymodule as single source of truth for all API code-name mappingsCodeMapperclass with bidirectional lookup (name→code, code→name)- Dynamic error messages now show valid options from
CodeMapper
Changed
- BREAKING:
quiz_createnow acceptsdifficulty: str("easy"|"medium"|"hard") instead ofint(1|2|3) - All MCP tools now use
constants.CodeMapperfor input validation - All API client output now uses
constants.CodeMapperfor human-readable names - Removed ~10 static
_get_*_namehelper methods fromapi_client.py - Removed duplicate
*_codesdictionaries fromserver.pytool functions
Fixed
- Removed duplicate code block in research status parsing
[0.1.7] - 2026-01-10
Fixed
- Fixed URL source retrieval by implementing correct metadata parsing in
get_notebook_sources_with_types - Added fallback for finding source type name in
get_notebook_sources_with_types
[0.1.6] - 2026-01-10
Added
studio_statusnow includes mind maps alongside audio/video/slidesdelete_mind_map()method with two-step RPC deletionRPC_DELETE_MIND_MAPconstant for mind map deletion- Unit tests for authentication retry logic
Fixed
- Mind map deletion now works via
studio_delete(fixes #7) notebook_querynow acceptssource_idsas JSON string for compatibility with some AI clients (fixes #5)- Deleted/tombstone mind maps are now filtered from
list_mind_mapsresponses - Token expiration handling with auto-retry on RPC Error 16 and HTTP 401/403
Changed
- Updated
blversion toboq_labs-tailwind-frontend_20260108.06_p0 delete_studio_artifactnow accepts optionalnotebook_idfor mind map fallback
[0.1.5] - 2026-01-09
Fixed
- Improved LLM guidance for authentication errors
[0.1.4] - 2026-01-09
Added
source_get_contenttool for raw text extraction from sources
[0.1.3] - 2026-01-08
Fixed
- Chrome detection on Linux distros
[0.1.2] - 2026-01-07
Fixed
- YouTube URL handling - use correct array position
[0.1.1] - 2026-01-06
Changed
- Improved research tool descriptions for better AI selection
[0.1.0] - 2026-01-05
Added
- Initial release
- Full NotebookLM API client with 31 MCP tools
- Authentication via Chrome DevTools or manual cookie extraction
- Notebook, source, query, and studio management
- Research (web/Drive) with source import
- Audio/Video overview generation
- Report, flashcard, quiz, infographic, slide deck creation
- Mind map generation