| notebook_listA | List all notebooks (id + title + metadata). Returns a bounded page: limit (default 50) items from offset (default
0), plus total / offset / has_more. Page forward by re-calling
with offset += limit while has_more is true. |
| notebook_createB | Create a new notebook with the given title. |
| notebook_describeA | Fetch a notebook's AI-generated description. Accepts a notebook name or ID. Returns the resolved notebook_id plus the AI description. Pass
include_metadata=True to additionally fetch the notebook's metadata
(details + source list) and surface it under a metadata key; the
default output (include_metadata omitted) is unchanged. |
| notebook_renameB | Rename a notebook. Accepts a notebook name or ID. |
| notebook_deleteA | Delete a notebook (irreversible). Accepts a notebook name or ID. Two-step confirmation: called with confirm=False (the default) it does
NOT delete — it returns a needs_confirmation preview of the resolved
notebook. Re-submit its canonical notebook_id with confirm=True. |
| source_listA | List a notebook's sources. Accepts a notebook name or ID. detail (default full): full gives each source's metadata plus string
kind / status_label / drive_status_label labels; compact returns
only id / title / kind / status_label / drive_status_label /
created_at — a low-token roster.
drive_status_label is a separate axis, null on non-Drive sources:
a Drive file that was deleted or unshared keeps reading
status_label="ready" (ingestion did finish) while this turns
deleted / inaccessible / syncing, so answers may be stale.
Pass status to list only sources whose status_label matches (error =
a broken import's ghost row). Pass label (name or ID) to restrict to that
label's members; composes with status. |
| source_readA | Read a source at one of two detail levels. Accepts a notebook/source name or ID. detail selects what you get back (two distinct shapes):
summary — a tiny AI digest for low-token triage:
{notebook_id, source_id, summary, keywords}. Cheap to fan out across
many sources before deciding which to pull in full.
full (DEFAULT) — the source metadata (incl. kind/status_label/
drive_status_label)
plus the extracted content, the full char_count, and a
truncated flag. content is ALWAYS bounded: omitting max_chars
caps it at the first 10,000 chars; raise max_chars and/or page with
offset (slice [offset : offset+max_chars]). char_count stays
the FULL length. content is null (char_count 0) when the
source isn't ready yet or has no extractable text.
output_format (text default / markdown, needs the server's
markdownify extra) and max_chars / offset apply only to
detail="full" (ignored for summary). Prefer chat_ask for
querying large sources rather than pulling the whole body.
|
| source_renameC | Rename a source. Accepts a notebook/source name or ID. |
| source_deleteA | Delete sources. source XOR sources. Preview: omit both.
Confirm with the preview's canonical notebook_id and source id(s). |
| source_waitA | Wait for sources to finish processing. Accepts a notebook name or ID. Waits for a subset when sources (list or comma/JSON string) is given, a
single source when source (name or ID) is given, else every source. All
three modes return the SAME structured aggregate, so an agent never has to
branch on the shape: {"notebook_id", "ok", "ready", "timed_out", "failed", "not_found"}
plus per-bucket *_count + total_count. ready holds sources that
reached READY (with kind / status_label labels); timed_out /
failed / not_found hold {"source_id", "error"} entries. ok is
true iff all error buckets empty. Subset
and all-sources modes report partial progress (a slow or failed source no
longer discards the ones that did become ready). A READY web-page entry may carry a non-blocking warning when its indexed
text is thin (likely dead link / soft-404 / paywall); advisory only
(still READY, still ok — verify with source_read (detail="full")). An unresolved ref in sources / source raises NOT_FOUND before the wait —
an input error, distinct from a resolved source the backend reports missing /
failed / slow (which lands in a bucket). |
| source_addA | Add sources by notebook name or ID: single, batch, or in-channel bytes. Choose ONE mode: Single mode — pass source_type; it selects the required input: url / youtube — require url (youtube → a YouTube link).
text — requires text; title optional.
file — over stdio, requires path (a local path on the
server host inside NOTEBOOKLM_MCP_ALLOWED_ROOTS; host-path file-add
is off until that env is set — not $HOME and not ~/.notebooklm).
Over the remote (http) connector the host filesystem is
unreachable, so it returns upload_required with two actor paths:
human_upload (open the signed URL in a browser) and agent_upload (an
agent POSTs the bytes as the raw body); agent_instructions gives the rule
(try agent_upload, else human_upload.url). Alternatively pass
bytes_base64 to add a SMALL file in-channel (any transport, no signed URL):
standard base64 (not URL-safe) ≤ 10,000 chars (≈ 7 KB); filename seeds the
title/extension. A bigger file must take the signed URL (≤ 200 MiB).
drive — requires document_id + mime_type (one of
google-doc|google-slides|google-sheets|pdf; required, no default — a wrong
default fails non-Doc imports, #1827).
The single-mode content inputs are mutually exclusive — supply only the one
your source_type requires (bytes_base64 is the file alternative to
path). An explicit title for url/youtube/drive is honored via a post-add
rename; a miss returns title_override_applied: false (#1960). Pass wait=true to block until the ONE added source finishes processing and
return the source_wait aggregate (buckets + per-bucket *_count +
total_count) with a top-level source_id (present even on timeout/failure);
timeout/interval tune the poll. wait is single-mode only and NOT for a
remote file signed-URL upload (add it, then source_wait). Without wait
the added source is echoed under source with string kind /
status_label labels; imports are ASYNCHRONOUS so the echo is usually still
processing/preparing — confirm with source_wait or
source_list(status="error"). A failed import is flagged inline
(status_label="error" + a warning); source_wait also flags a READY web
page with suspiciously thin text (dead link/soft-404/paywall). Single web URLs support fallback_fetch=True: eligible connection failures
become static text with fallback provenance (impersonate + markdown extras).
cleanup_on_failure=True additionally deletes the attributable failed stub
once its replacement is ready. Private fetch destinations are blocked. Batch mode — pass urls (http/https, including YouTube). Returns
notebook_id, added/failed counts and per-input results with
input, status (added/error), source fields or an error object. results[i] corresponds to urls[i] and includes commit_state
(confirmed/rejected/unknown/not_sent). Batch is URL-only; invalid entries are
not_sent errors. Escaping failures retain settled members as batch_outcome.
Single-mode inputs and wait are invalid with urls; allow_internal
applies to every entry.
|
| source_add_drive_fileA | Add a Google Drive file by downloading it server-side and uploading it (supports
epub/docx/pptx/txt/md/rtf/odt/csv/tsv/pdf). Probes the Drive file and routes: a downloadable type is fetched server-side and
uploaded; a Google-native Doc/Slides/Sheet isn't downloadable and returns a pointer
error → use source_add(source_type='drive', mime_type=…) for those (or for a
Drive PDF you'd rather add by reference). Use source_add(source_type='file') when
you hold the bytes locally. Accepts a notebook name or ID and a Drive file id or share URL (/d/<id>,
/file/d/<id>/…, ?id=<id>). The fetch runs server-side with the profile's
session, so it works on the remote (http) connector too — no upload_required
step. Processed ASYNCHRONOUSLY; pass wait=true to block until READY (else
confirm via source_wait / source_list(status="error")). |
| source_list_play_booksA | List Google Play Books eligible to be added as sources (Expert Intelligence). Returns the account's purchased ebooks NotebookLM can ingest (US only, 18+).
Each row has content_id (pass it to source_add_play_book), title,
authors, export_disabled and reason (a non-exportable title cannot
be added), plus cover_url / store_url. Empty for an account with no
Play Books library. Web backend only. |
| source_add_play_bookA | Add a Google Play Book as a source by its content id (Expert Intelligence). content_id is a volume id from source_list_play_books. The title must
be exportable — a publisher-blocked one is refused up front. Accepts a notebook
name or ID. Reads back as an expert_intelligence source. Processed
asynchronously; pass wait=true to block until READY. Web backend only.
|
| chat_askA | Ask a notebook's sources a question, and/or recall prior turns. Accepts a
notebook name or ID. Pass conversation_id to continue a specific conversation; omit it to
continue the notebook's most-recent conversation (or start a new one). source_ids (optional) scopes the question to specific sources by
id/prefix/title; omit it to query every source. It accepts a real list, a
JSON-array string, or a comma-separated string (the comma form cannot
carry a source title that itself contains a comma — use a JSON array or a
real list for those).
history (optional, default 0): the max number of prior Q&A pairs
(each a {question, answer}) to also return (oldest-first), from the
conversation as it stood before this question. There is no unbounded
"all" value — pass a generously large number (e.g. 100) for the whole
conversation. Omit question (leave it empty) with history > 0 to
recall prior pairs without asking anything new; a recall-only call also
echoes the conversation_id it read. Pass neither and the call is
rejected.
Returns the answer, turn_number, and citation references
(when a question is asked).
references controls citation detail: lite (default) returns
source_id / citation_number / cited_text; full adds
chunk-level char offsets and scores. suggest_followups (optional, default False): when True the
result also carries a suggested_prompts list of AI-suggested
follow-up questions (each a {title, prompt}), scoped to the same
source_ids and steered by question when one is given. It works on
its own too — pass it with no question (and history 0) to get
suggested questions without asking anything. When omitted/False the
result never contains a suggested_prompts key.
|
| chat_startA | Start a chat ask as a detached background task and return immediately. The watchdog-safe way to ask when generation may run long (large/shared
notebooks routinely take 1–3 minutes, and remote MCP transports cut a
call at ~60s of silence — which kills a blocking chat_ask
mid-generation). The ask runs server-side regardless of what happens to
this call; chat_status collects the answer. For questions expected
to answer quickly, chat_ask stays the one-call path. Parameters mirror chat_ask's ask path (history /
suggest_followups are chat_ask-only). Returns one of: {"status": "started", "task_id": ...} — call chat_status
with this task_id in ~20–30s; re-invoke while pending.
{"status": "already_running", "task_id": ...} — an identical ask
is still in flight; poll that task_id (no double generation).
A finished ask is never replayed: starting the same question again
re-asks and appends a new conversation turn, exactly like chat_ask
(so an answer can't go stale after source_add / chat_configure).
A finished payload stays pollable by its task_id for ~30 minutes,
then chat_status reports unknown. |
| chat_statusA | Poll detached asks, or inspect a notebook's live generation session. Detached-task mode: task_id accepts one id, a list, or a
comma-separated string — poll
a whole batch in ONE call and re-invoke every ~20–30s while anything
is pending. Per-task statuses: pending (state: queued waiting for a generation slot, or
generating) — re-invoke; polling never restarts a generation.
completed — the full chat_ask-shaped payload, plus
queued_s / generation_s timings.
failed — error: {code, message, retriable, ...}; a retriable
code is worth one chat_start retry (which re-runs the generation).
unknown — no such task, or its result expired; chat_start
again.
A single string id returns that task's status dict; a list (even of
one) returns {"tasks": [...]} in input order. At most 64 ids per
call. Live-session mode: pass notebook instead of task_id to inspect
Google's current chat session. conversation_id is optional and
defaults to that notebook's most-recent conversation. The result is
idle or generating and includes the generation token when Google
supplies one. The two modes are mutually exclusive. |
| chat_cancelA | Stop a notebook's active chat generation. conversation_id defaults to the notebook's most-recent session.
Pass the task_id returned by chat_start when cancelling a
detached ask: the MCP server abandons its local response stream first,
then cancels the associated Google session when one exists.
An unknown task ID or one belonging to another notebook is rejected.
|
| chat_configureA | Configure a notebook's chat behavior. Accepts a notebook name or ID. Two mutually-exclusive ways to configure: chat_mode is a preset — one of default / learning-guide /
concise / detailed. It replaces the whole block, so it can't be
combined with goal / response_length (that's rejected).
goal (custom persona; selects the CUSTOM goal) and
response_length (default / longer / shorter) set a custom
config. A partial call (just one) merges with the current settings — the
omitted field is preserved. Only a bare call (no preset, neither field)
is rejected, as it would reset every setting to its default.
|
| suggest_promptsA | Get AI-suggested, ready-to-send prompts for a studio surface. Accepts a
notebook name or ID. surface selects what the prompts are written for (default ask):
ask — chat questions to ask the notebook's content.
audio-deep-dive / audio-brief / audio-critique / audio-debate
— prompts to steer an Audio Overview in that format.
video-explainer / video-short — prompts to steer a Video Overview.
quiz / flashcards — prompts to steer quiz / flashcard generation.
Each result is a ready-to-send instruction you can pass to the matching
generator (chat_ask for ask; studio_generate's instructions for
the studio formats). source_ids (optional) scopes the suggestions to
specific sources; omit for all. query optionally steers the suggestions. Related: chat_ask(suggest_followups=true) returns ask-surface
suggestions inline with a question (ask + follow-ups in one call); this tool
is the standalone selector across every surface. |
| note_saveA | Create a note, or update an existing one (upsert). Accepts a notebook name or ID. Mode is chosen SOLELY by note: note omitted → create a new note; title AND content are
both required. Returns status="created".
note given (a note name or id) → update that note; supply title
and/or content (at least one — title-only renames, content-only
replaces the body). A ref that doesn't resolve is a not-found error, NEVER
a stray create. Returns status="updated".
|
| studio_listA | List a notebook's Studio panel — text notes AND generated artifacts. Accepts a notebook name or ID. Returns a merged items list; each item has
id / title / type (note or a hyphenated artifact kind); artifacts
also carry status_label / url. Bounded page of limit (default 50)
from offset, with total / offset / has_more. detail ladder (NOTE bodies only; read a report/data-table body via
studio_download): summary (default) gives each note a bounded
content_preview + char_count. Artifacts add created_at,
generation_prompt, duration_seconds, slide_count, source_count
(unknown metadata/counts are null). full = whole content; compact = a
id/title/type/status_label/created_at roster.
kind filters to one type.
item (name or id) fetches just that item as a 1-element list with the
note's FULL content or the artifact's summary metadata;
no match is NOT_FOUND. limit / offset / detail are ignored with
item; kind scopes resolution.
|
| studio_generateA | Start generating a studio artifact. Accepts a notebook name or ID. Non-blocking: returns immediately with a task_id; poll
studio_status(notebook, task_id) until is_complete is true.
Exception: mind-map renders synchronously (no task_id) — its node
tree is under mind_map (or null), the map's id under mind_map_id. artifact_type selects the artifact kind (each routes to its own
generator):
audio — podcast-style overview (audio_format:
deep-dive|brief|critique|debate, audio_length: short|default|long).
video — video overview (video_format:
explainer|brief|cinematic|short, style: auto|custom|classic|whiteboard|
kawaii|anime|watercolor|retro-print|heritage|paper-craft, style_prompt:
free-text custom-style prompt — requires style=custom).
cinematic-video — AI-generated documentary video.
slide-deck — slide deck (deck_format: detailed|presenter,
deck_length: default|short).
quiz / flashcards — study aids (quantity:
fewer|standard|more, difficulty: easy|medium|hard).
infographic — single-image infographic (orientation:
landscape|portrait|square, detail: concise|standard|detailed,
style: auto|sketch-note|professional|bento-grid|editorial|
instructional|bricks|clay|anime|kawaii|scientific).
data-table — extracted data table.
mind-map — mind map (map_kind: interactive|note-backed).
report — text report (report_format:
briefing-doc|study-guide|blog-post|custom).
Each per-kind option is valid ONLY for the kind(s) listed above; passing one
to a different artifact_type is a validation error, not a silent no-op.
Options default to the standard choice when omitted. source_ids (optional) scopes generation to specific sources; omit it
to use every source. It accepts a real list, a JSON-array string, or a
comma-separated string (a source title containing a comma needs the
JSON-array or list form).
instructions is free-text guidance for kinds that accept it
(including mind-map). language (optional) is a language code,
e.g. en/ja/zh_Hans.
|
| studio_statusA | Poll a generation task's status. Accepts a notebook name or ID. Stateless: pass the task_id from studio_generate. Returns status /
url / error / is_complete / media_ready; poll until done. A
pending url is provisional — trust it only if media_ready. |
| studio_downloadA | Download a generated artifact. Accepts a notebook name or ID. Target the artifact in ONE of two ways (exactly one): artifact — a name-or-id ref (title / id / unique-id-prefix), the form the
other artifact_* tools take; resolves to its type + id.
artifact_type — a registry-advertised type, optionally with
artifact_id (full or unique-prefix) for a specific one; omit
artifact_id to get the latest artifact of that type.
output_format overrides the default where the selected artifact type
supports it. The tool schema advertises the current type and format enums.
Over stdio the artifact is written to path (required). Over the
remote (http) connector the server filesystem is unreachable, so the tool
returns a clickable resource_link plus {"status": "download_ready", "url": …} — a short-lived signed URL; path is ignored. A text kind
(report/data-table) also returns the body inline (bounded content +
char_count + truncated) for link-incapable hosts. On the remote
connector an explicit artifact_id (and output_format) is validated up
front — an unknown/ambiguous id fails immediately, not as a 400 when opened. |
| studio_renameA | Rename a Studio item (title only) — a text note OR an artifact. Accepts a notebook name or ID plus an item name-or-id ref resolved over
the merged notes+artifacts list (mirroring studio_delete). Routing is by
resolved type: a note is renamed through the note system, preserving its
content via a get-then-update; every artifact type — audio, video,
slide-deck, quiz, flashcards, infographic, data-table, report, and BOTH
mind-map kinds — through the artifact rename RPC (note-backed mind maps route
back through the note system inside the shared core). Callers need not know
which backing an item has. Returns item_id / type plus the applied new_title and
is_mind_map. |
| studio_retryA | Retry a failed Studio artifact in place (the UI "Retry" action). Accepts a notebook/artifact name or ID. Non-blocking: on acceptance it
returns the kicked-off task_id (equal to the artifact id) and the new
status; poll studio_status(notebook, task_id) until complete. A
synchronous refusal (rate limit / quota / not-retryable) surfaces as an error. |
| studio_deleteA | Delete notes/artifacts irreversibly: item XOR items (1–100 refs). Names/IDs resolve over Studio. Preview first; confirm with canonical
notebook_id and item ID(s). Batch confirmation requires full IDs.
Text notes batch into one write; artifacts (including mind maps) route
individually by kind. Batch returns deleted / not_found arrays.
An absent single full ID is an idempotent success. |
| research_startA | Start a research session in a notebook. Accepts a notebook name or ID. Non-blocking. Carry the returned poll_task_id into
research_status / research_import / research_cancel — the
single id that drives polling (it resolves deep vs fast for you). Poll
research_status until completed, then research_import to add
the sources. source is web (default) or drive. mode is fast
(default) or deep (deep is web-only).
|
| research_statusA | Check a notebook's research status. Accepts a notebook name or ID. Returns status (no_research|in_progress|completed|failed|not_found),
poll_task_id, sources, and report metadata. Poll until
completed, then pass poll_task_id to research_import. termination_reason splits failed into no_results|cancelled|
unknown (else completed|in_progress); see hint.
report and per-source report_markdown are omitted unless
include_report=True (truncated to report_max_chars).
report_char_count is the full size; report_truncated flags an
omitted/truncated one. source_limit/source_offset page sources.
poll_task_id (optional) pins one of several in-flight tasks; omit
for a single task (ambiguous with two+). An unmatched pin reports
not_found. task_id is a deprecated alias (removed in v0.9.0).
|
| research_cancelA | Cancel an in-flight research run in a notebook. Accepts a notebook name or ID and the poll_task_id to cancel — the
value from research_start / research_status. run_id is a
deprecated alias (removed in v0.9.0). Sends the cancel unless the run is already TERMINAL (completed /
failed), which returns cancel_requested: false with the observed
status and no RPC. Otherwise returns cancel_requested: true with
run_status_before; a just-started run reading not_found /
no_research (replication lag) is cancelled too. Fire-and-forget; poll
research_status afterward to confirm. |
| research_importA | Import a completed research task's sources into the notebook. Accepts a notebook name or ID and the poll_task_id to import — the
value from research_start / research_status. task_id is a
deprecated alias (removed in v0.9.0). The id pins the task. Timeout-tolerant: a timed-out import reconciles
what committed. Idempotent: sources already present (by URL) are skipped
as already_present; allow_duplicate re-adds them. cited_only imports only report-cited sources (all, if none resolve).
max_sources caps the count.
|
| share_statusA | Get a notebook's sharing status. Accepts a notebook name or ID. Returns is_public, access (restricted | anyone_with_link),
the share_url, and the list of shared_users ({email, permission,
display_name, avatar_url}). permission / access are string labels. NOTE: view_level is intentionally NOT returned here — the read API does
not report it (it would always read "full"). Set it via
share_set_access, which echoes the value it just set. |
| share_set_accessA | Set a notebook's link-access settings. Accepts a notebook name or ID. Provide public (True = anyone-with-link, False = restricted)
and/or view_level (full or chat). Public widening
(public=True on a restricted notebook) returns a needs_confirmation
preview; confirm with its canonical notebook_id. Restricting and
view_level changes are not gated. Returns the updated status (or preview). view_level is echoed only when
set here (the read API can't report it); with both fields it is applied
before public so a partial failure fails closed. |
| share_set_userA | Upsert access: email + permission OR 1–100 grants [{email, permission}]. Preview lists every grant; confirm with its canonical notebook_id.
Batches allow mixed editor/viewer permissions in one write. notify
and message apply to all grantees. Returns updated sharing status. |
| share_remove_userA | Remove a user's access to a notebook. Accepts a notebook name or ID. Confirm-gated: called with confirm=False (default) it does NOT mutate —
it returns a preview. Re-submit its canonical notebook_id and verbatim
email with confirm=True. |
| server_infoA | Report the server version and local authentication health. Returns the package version, live chat_tasks gauges
({generating, queued, concurrency, cached_results} — check load
before submitting a chat_start batch), and an auth block (authenticated /
storage_exists / json_valid / cookies_present / sid_cookie /
profile). Use it to confirm the server is logged in before driving
notebook tools; if authenticated is false, run notebooklm login on
the server host. Set include_account=True to also fetch an account block: the
signed-in identity {email, authuser} (persisted first, then a live
WIZ_global_data probe when authenticated; None only when it can't be
discovered) plus quota fields {available, notebook_limit, source_limit, tier, output_language, output_language_is_default}
(output_language is the global account code, e.g. "en", or None
with output_language_is_default: true when using NotebookLM's default).
The quota fields need a live session, so the block is off by default — the
default call is a fast, network-free probe. When the session is missing or
stale the fields degrade to {available: False, reason: ...} (identity
still included) rather than failing the whole call. profile names the resolved storage profile the probe ran against
(e.g. "default"); the booleans are the actual health signals.
The absolute on-disk storage path is deliberately not returned: it
leaks the server-host OS username / filesystem layout to any (possibly
remote) caller, while telling the agent nothing it can act on. |
| await_uploadA | Wait for a file uploaded via a source_add(source_type="file") link to land. Pass the human_upload.url (or the bare token) that source_add returned.
Polls the server in-process until the browser/agent upload commits the source: {"status":"received","source_id",...,"file":{...}} — the upload landed.
{"status":"pending",...} — nothing yet after ~timeout s; re-invoke with
the same link (the wait resumes; a transport reset does not lose it).
{"status":"unconfirmed",...} — the upload may have landed, but its source
could not be confirmed. Check source_list before requesting a new link
to avoid adding the same file twice.
{"status":"expired_or_invalid",...} — the link failed; mint a fresh one via
source_add(source_type="file").
|
| pingA | Health check for this wrapper server. |