NotebookLM MCP Server
Connects MCP-compatible AI clients to Google NotebookLM for notebook/source management, grounded chat/RAG, artifact generation, research, sharing, and diagnostics.
List, create, describe, rename, and delete notebooks.
Add, list, read, rename, delete, and wait on sources from URLs, YouTube, text, files, Google Drive, and Google Play Books.
Ask grounded questions with citations, continue conversations, poll/cancel background chat tasks, configure chat behavior, and suggest prompts/follow-ups.
Generate and manage Studio artifacts such as audio/video overviews, slide decks, quizzes, flashcards, infographics, data tables, mind maps, and reports; poll status, download, retry, rename, and delete them.
Start, check, cancel, and import fast or deep research results.
Save and update research notes.
Manage notebook sharing status, link access, and user permissions.
Check server/auth health, reconnect/login, inspect account/quota info, and await uploaded files.
Connects AI agents directly to Google NotebookLM via its internal high-performance RPC calls, enabling fast grounded RAG queries with citations, full notebook management (create, list, rename, delete), source ingestion, chat configuration, note saving, automated Deep Research, and generation/download of Studio artifacts such as Audio Overviews (podcasts) and reports.
Allows adding files directly from Google Drive as indexed sources in a NotebookLM notebook.
Allows ingesting YouTube video links as sources that can be indexed and queried within a NotebookLM notebook.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@NotebookLM MCP Server create a notebook from this YouTube video and generate an audio overview"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
📓 NotebookLM MCP Server (Python & FastMCP)
Servidor Model Context Protocol (MCP) profissional em Python construído com FastMCP para conectar assistentes e agentes de IA (Antigravity IDE, Claude Desktop, Cursor, Claude Code, Windsurf) diretamente ao Google NotebookLM.
Diferente de soluções lentas baseadas em automação visual contínua (DOM/UI scraping), este servidor opera diretamente sobre as chamadas RPC internas de alta performance do NotebookLM, permitindo:
Consultas RAG rápidas fundamentadas com citações.
Gerenciamento completo de cadernos e ingestão de fontes (URLs, YouTube, documentos e textos).
Disparo e download assíncrono de Audio Overviews (Podcasts / Deep Dives) e relatórios.
Pesquisa aprofundada automatizada (Deep Research).
Gerenciamento de sessão persistente com keep-alive e renovação de cookies.
⚡ Quickstart
# 1. Clone o repositório
git clone https://github.com/dougrn/MCP-notebookLM.git
cd MCP-notebookLM
# 2. Crie e ative o ambiente virtual
uv venv .venv
.venv\Scripts\activate # No Windows (ou 'source .venv/bin/activate' no Linux/macOS)
# 3. Instale as dependências
uv pip install -r requirements.txt "notebooklm-py[cookies]"
playwright install chromium
# 4. Faça o login único com sua conta Google
python login.py
# 5. Inicie o servidor MCP em modo stdio
python server.pyRelated MCP server: notebooklm-mcp
🏗️ Arquitetura
┌────────────────────────────────────────────────────────┐
│ Clientes MCP (Claude Desktop, Cursor, Antigravity) │
└──────────────────────────┬─────────────────────────────┘
│ JSON-RPC (stdio / http)
▼
┌────────────────────────────────────────────────────────┐
│ NotebookLM FastMCP Server (server.py) │
│ - 40 Ferramentas Registradas │
│ - Health Checking & Auth Status │
│ - Prompt Templates & Resources │
└──────────────────────────┬─────────────────────────────┘
│ FastMCP Lifespan & RPC Client
▼
┌────────────────────────────────────────────────────────┐
│ Google NotebookLM Backend Engine │
│ - Gemini 2.5 Grounded Session RAG │
│ - Source Ingestion & Parser (URLs / YouTube / Text) │
│ - Studio Artifact Generation (Audio Overviews / .m4a) │
└────────────────────────────────────────────────────────┘📦 Estrutura do Repositório
MCP-notebookLM/
├── server.py # Ponto de entrada do servidor FastMCP
├── login.py # Script CLI amigável para login e verificação de sessão
├── requirements.txt # Dependências com versões exatas travadas
├── pyproject.toml # Manifesto de configuração do pacote Python
├── .env.example # Modelo de configuração de ambiente
├── .gitignore # Regras de exclusão de artefatos
├── LICENSE # Licença MIT
└── README.md # Documentação oficial🔑 Autenticação
O Google NotebookLM utiliza autenticação vinculada à sua conta Google. Para evitar que a sessão expire e o servidor MCP desconecte com frequência, o projeto utiliza Master Token persistente.
Login Único e Persistente (Recomendado)
Execute o utilitário interativo:
python login.pyUma janela do navegador será iniciada para você fazer o login com sua conta Google.
O Google Master Token será gerado e salvo em
~/.notebooklm/profiles/default/master_token.json.Sessão durável: Sempre que os cookies expirarem, a biblioteca renova as credenciais automaticamente em background via OAuth, sem você precisar fazer login de novo e sem que a IA perca o acesso.
Checagem de Saúde da Sessão
Para verificar a qualquer momento se a sessão continua ativa e se o Master Token está presente:
python login.py --checkTestar Renovação de Sessão
Para testar a re-emissão de novos cookies a partir do Master Token:
python login.py --refresh🔌 Configuração nos Clientes MCP
1. Antigravity IDE
Edite ~/.gemini/antigravity-ide/mcp_config.json ou ~/.gemini/config/mcp_config.json:
{
"mcpServers": {
"notebooklm-python": {
"command": "c:\\Users\\dougl\\Desktop\\Serviços\\_Pessoais\\MCP-notebookLM\\.venv\\Scripts\\python.exe",
"args": [
"c:\\Users\\dougl\\Desktop\\Serviços\\_Pessoais\\MCP-notebookLM\\server.py"
]
}
}
}2. Claude Desktop
Adicione ao seu %APPDATA%\Claude\claude_desktop_config.json (Windows) ou ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"notebooklm": {
"command": "c:\\Users\\dougl\\Desktop\\Serviços\\_Pessoais\\MCP-notebookLM\\.venv\\Scripts\\python.exe",
"args": [
"c:\\Users\\dougl\\Desktop\\Serviços\\_Pessoais\\MCP-notebookLM\\server.py"
]
}
}
}3. Cursor
No Cursor, configure em .cursor/mcp.json ou nas configurações de MCP:
{
"mcpServers": {
"notebooklm": {
"command": "c:\\Users\\dougl\\Desktop\\Serviços\\_Pessoais\\MCP-notebookLM\\.venv\\Scripts\\python.exe",
"args": [
"c:\\Users\\dougl\\Desktop\\Serviços\\_Pessoais\\MCP-notebookLM\\server.py"
]
}
}
}4. Claude Code (CLI)
claude mcp add notebooklm -- c:/Users/dougl/Desktop/Serviços/_Pessoais/MCP-notebookLM/.venv/Scripts/python.exe c:/Users/dougl/Desktop/Serviços/_Pessoais/MCP-notebookLM/server.py🧰 Catálogo de Ferramentas Disponíveis
Categoria | Ferramenta | Descrição |
Diagnóstico & Auth |
| Verifica status de conexão e presença do Master Token durável |
| Força renovação silenciosa de cookies via Master Token em background | |
| Dispara a janela de login na tela do usuário a partir do harness | |
| Detalhes do servidor, versão do runtime e perfil ativo | |
Cadernos |
| Lista todos os cadernos com ID, título, contagem de fontes e datas |
| Cria um novo caderno no NotebookLM | |
| Detalhes aprofundados e metadados de um caderno | |
| Resumo instantâneo das fontes e perguntas sugeridas | |
| Renomeia um caderno existente | |
| Exclui um caderno com confirmação | |
Fontes |
| Lista todas as fontes indexadas no caderno |
| Retorna o texto extraído de uma fonte | |
| Ingestão de URL web, link do YouTube ou texto bruto | |
| Adiciona arquivo direto do Google Drive | |
| Remove uma fonte do caderno | |
| Aguarda a conclusão da indexação assíncrona da fonte | |
Chat & RAG |
| Faz perguntas ao caderno com fundamentação e citações |
| Inicia uma nova conversa persistente no caderno | |
| Configura o tom e diretrizes de resposta do chat | |
| Gera ideias de perguntas com base nas fontes | |
Studio & Áudio |
| Dispara geração de Audio Overview (podcast), vídeo ou quiz |
| Consulta o status de processamento da geração | |
| Faz o download do arquivo de áudio ( | |
| Lista todos os artefatos de estúdio gerados | |
Notas & Pesquisa |
| Salva notas de pesquisa diretamente no caderno |
| Inicia uma rotina de Deep Research sobre um tema | |
| Importa os achados da pesquisa para o caderno |
🧪 Teste Interativo com FastMCP Inspector
Para testar e interagir visualmente com as ferramentas pelo navegador:
fastmcp dev server.py📄 Licença
Este projeto está sob a licença MIT.
Available Tools
38 toolsawait_uploadAwait UploadARead-only
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 ~timeouts; 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. Checksource_listbefore requesting a new link to avoid adding the same file twice.{"status":"expired_or_invalid",...}— the link failed; mint a fresh one viasource_add(source_type="file").
Inputs: upload_link (required), timeout. Returns: object
chat_askChat 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.
Inputs: notebook (required), history, question, references, +3 more. Returns: object
chat_cancelChat 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.
Inputs: notebook (required), task_id, conversation_id. Returns: object
chat_configureChat ConfigureA
Configure a notebook's chat behavior. Accepts a notebook name or ID.
Two mutually-exclusive ways to configure:
chat_modeis a preset — one ofdefault/learning-guide/concise/detailed. It replaces the whole block, so it can't be combined withgoal/response_length(that's rejected).goal(custom persona; selects the CUSTOM goal) andresponse_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.
Inputs: notebook (required), goal, chat_mode, response_length. Returns: object
chat_startChat 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": ...}— callchat_statuswith thistask_idin ~20–30s; re-invoke whilepending.{"status": "already_running", "task_id": ...}— an identical ask is still in flight; poll thattask_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.
Inputs: notebook (required), question (required), references, source_ids, +1 more. Returns: object
chat_statusChat StatusARead-only
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:queuedwaiting for a generation slot, orgenerating) — re-invoke; polling never restarts a generation.completed— the fullchat_ask-shaped payload, plusqueued_s/generation_stimings.failed—error: {code, message, retriable, ...}; a retriable code is worth onechat_startretry (which re-runs the generation).unknown— no such task, or its result expired;chat_startagain.
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.
Inputs: task_id, notebook, conversation_id. Returns: object
notebook_createNotebook CreateC
Create a new notebook with the given title.
Inputs: title (required). Returns: object
notebook_deleteNotebook DeleteADestructive
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.
Inputs: notebook (required), confirm. Returns: object
notebook_describeNotebook DescribeARead-only
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.
Inputs: notebook (required), include_metadata. Returns: object
notebook_listNotebook ListARead-only
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.
Inputs: limit, offset. Returns: object
notebook_renameNotebook RenameC
Rename a notebook. Accepts a notebook name or ID.
Inputs: notebook (required), new_title (required). Returns: object
note_saveNote SaveA
Create a note, or update an existing one (upsert). Accepts a notebook name or ID.
Mode is chosen SOLELY by note:
noteomitted → create a new note;titleANDcontentare both required. Returnsstatus="created".notegiven (a note name or id) → update that note; supplytitleand/orcontent(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. Returnsstatus="updated".
Inputs: notebook (required), note, title, content. Returns: object
research_cancelResearch 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.
Inputs: notebook (required), run_id, poll_task_id. Returns: object
research_importResearch 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.
Inputs: notebook (required), task_id, cited_only, max_sources, +2 more. Returns: object
research_startResearch 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).
Inputs: query (required), notebook (required), mode, source. Returns: object
research_statusResearch StatusARead-only
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).
Inputs: notebook (required), task_id, poll_task_id, source_limit, +3 more. Returns: object
server_infoServer InfoARead-only
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.
Inputs: include_account. Returns: object
source_addSource 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— requireurl(youtube→ a YouTube link).text— requirestext;titleoptional.file— over stdio, requirespath(a local path on the server host insideNOTEBOOKLM_MCP_ALLOWED_ROOTS; host-path file-add is off until that env is set — not$HOMEand not~/.notebooklm). Over the remote (http) connector the host filesystem is unreachable, so it returnsupload_requiredwith two actor paths:human_upload(open the signed URL in a browser) andagent_upload(an agent POSTs the bytes as the raw body);agent_instructionsgives the rule (tryagent_upload, elsehuman_upload.url). Alternatively passbytes_base64to add a SMALL file in-channel (any transport, no signed URL): standard base64 (not URL-safe) ≤ 10,000 chars (≈ 7 KB);filenameseeds the title/extension. A bigger file must take the signed URL (≤ 200 MiB).drive— requiresdocument_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.
Inputs: notebook (required), url, path, text, +13 more.
source_add_drive_fileSource 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")).
Inputs: notebook (required), document_id (required), wait, title. Returns: object
source_add_play_bookSource 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.
Inputs: notebook (required), content_id (required), wait. Returns: object
source_deleteSource DeleteADestructive
Delete sources. source XOR sources. Preview: omit both.
Confirm with the preview's canonical notebook_id and source id(s).
Inputs: notebook (required), source, confirm, sources. Returns: object
source_listSource ListARead-only
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.
Inputs: notebook (required), label, limit, detail, +2 more. Returns: object
source_list_play_booksSource List Play BooksARead-only
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.
Inputs: limit, offset. Returns: object
source_readSource ReadARead-only
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 extractedcontent, the fullchar_count, and atruncatedflag.contentis ALWAYS bounded: omittingmax_charscaps it at the first 10,000 chars; raisemax_charsand/or page withoffset(slice[offset : offset+max_chars]).char_countstays the FULL length.contentisnull(char_count0) 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.
Inputs: source (required), notebook (required), detail, offset, +2 more.
source_renameSource RenameC
Rename a source. Accepts a notebook/source name or ID.
Inputs: source (required), notebook (required), new_title (required). Returns: object
source_waitSource WaitARead-only
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).
Inputs: notebook (required), source, sources, timeout, +1 more.
studio_deleteStudio DeleteADestructive
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.
Inputs: notebook (required), item, items, confirm. Returns: object
studio_downloadStudio 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 otherartifact_*tools take; resolves to its type + id.artifact_type— a registry-advertised type, optionally withartifact_id(full or unique-prefix) for a specific one; omitartifact_idto 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.
Inputs: notebook (required), path, artifact, artifact_id, +2 more.
studio_generateStudio 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 — requiresstyle=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.
Inputs: notebook (required), artifact_type (required), style, detail, +14 more. Returns: object
studio_listStudio ListARead-only
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.
detailladder (NOTE bodies only; read a report/data-table body viastudio_download):summary(default) gives each note a boundedcontent_preview+char_count. Artifacts addcreated_at,generation_prompt,duration_seconds,slide_count,source_count(unknown metadata/counts arenull).full= wholecontent;compact= aid/title/type/status_label/created_atroster.kindfilters to onetype.item(name or id) fetches just that item as a 1-element list with the note's FULLcontentor the artifact's summary metadata; no match is NOT_FOUND.limit/offset/detailare ignored withitem;kindscopes resolution.
Inputs: notebook (required), item, kind, limit, +2 more. Returns: object
studio_renameStudio 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.
Inputs: item (required), notebook (required), new_title (required). Returns: object
studio_retryStudio 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.
Inputs: artifact (required), notebook (required). Returns: object
studio_statusStudio StatusARead-only
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.
Inputs: task_id (required), notebook (required). Returns: object
suggest_promptsSuggest PromptsARead-only
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.
Inputs: notebook (required), query, surface, source_ids. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 38 tools
Most tools target clearly distinct resources (notebook_*, source_*, studio_*, chat_*, research_*, share_*). A few boundaries blur: source_add overlaps with source_add_drive_file and source_add_play_book, and chat_ask vs chat_start differ only by blocking vs detached execution. Descriptions do explicitly disambiguate these overlaps, so misselection is largely avoidable.
The set follows a strong resource_verb convention (notebook_rename, source_add, studio_generate, chat_ask, research_start, share_set_user). A few tools break the pattern (note_save, suggest_prompts, server_info, await_upload), but these are minor deviations that stay readable.
38 tools is heavy and pushes past the comfortable range. The domain (notebooks, sources, studio artifacts, chat, research, sharing) is genuinely broad so many tools earn their place, but the several source_add* variants and chat ask/start/status family suggest consolidation was possible.
Coverage spans the full lifecycle: notebooks (create/list/rename/delete/describe), sources (add/list/read/delete/rename/wait), studio artifacts (generate/status/download/rename/retry/delete/list), chat (ask/start/status/cancel/configure), research, sharing, and server health. No obvious dead ends in the domain.
Maintenance
Related MCP Connectors
Durable memory, headless browser and research for agents. Pay per call: x402 USDC on Base or credits
YouTube transcripts, search, channel/playlist listings and upload tracking for AI agents.
Cited deep research for agents: run research, search graded sources. OAuth or API key sign-in.
AI research library. Save, organise and reuse notes and webpages as clean markdown context.
Related MCP Servers
- AlicenseAqualityNot gradedmaintenanceEnables interaction with Google's NotebookLM through natural language, allowing users to create and manage notebooks, add sources from URLs/YouTube/Google Drive, query AI for insights, generate audio podcasts and other studio content, and perform AI-powered research and analysis.323MIT
- AlicenseBqualityAmaintenanceEnables AI assistants to programmatically interact with Google NotebookLM, allowing them to create and manage notebooks, add sources, query content, generate audio/video, and perform research tasks through natural language commands.5514,897 PyPI6,500MIT
- AlicenseAqualityDmaintenanceEnables AI assistants to programmatically access and control Google NotebookLM, supporting operations like notebook management, source addition, audio generation, and more via natural language.39MIT
- AlicenseAqualityDmaintenanceEnables AI agents to interact with Google NotebookLM, including listing and managing notebooks and sources, asking grounded questions with citations, and generating audio overviews, briefings, quizzes, and mind maps.13MIT