Skip to main content
Glama
juanQNav

mcp-notebooklm

by juanQNav

mcp-notebooklm

MCP server that exposes Google NotebookLM notebooks as tools for AI assistants (opencode).

Thin wrapper over notebooklm-py using FastMCP.

What it implements

A stdio MCP server with four tools:

Tool

Purpose

list_notebooks()

List every notebook with id, title, source_count.

find_notebook(title)

Case-insensitive partial match over notebook titles.

ask_notebook(notebook_id, question)

Ask a question; returns the grounded answer from NotebookLM.

generate_quiz(notebook_id, num_questions, ...)

Generate quiz JSON with multiple_choice / true_false questions in batches.

The service (src/mcp_notebooklm/service.py) wraps the async NotebookLMClient and applies two safety rails so the host LLM never hangs:

  • Concurrency limit — one in-flight query at a time (asyncio.Semaphore(1)), with a 10s queue timeout. If another query is running, the tool returns [RETRY_NEEDED] NotebookLM is busy... call again in ~60 seconds.

  • Execution timeout — 60s hard cap on the underlying chat.ask(). Timeouts and transport failures surface as [RETRY_NEEDED] / [ERROR] prefixes so the LLM can react instead of looping.

Authentication state is persisted to data/auth.json and reloaded on every request via NotebookLMClient.from_storage().

Related MCP server: notebooklm-mcp-server

Prerequisites

  • Python ≥ 3.12

  • uv (recommended) or pipx

  • A Google account with NotebookLM access

1. Install

From the project root:

uv sync

This installs the project (including the notebooklm-py[browser] extra, which pulls Playwright) and exposes the mcp-notebooklm console script.

2. Install Playwright browser (one-time)

notebooklm-py[browser] installs the Playwright Python package, but the Chromium browser binary must be downloaded separately.

uv run playwright install chromium

This is a one-time step (~170 MB) and must be done before the first login.

3. Authenticate with NotebookLM

The first run downloads Chromium (~170 MB) and opens a Google sign-in window. Auth state is written to data/auth.json and reused on subsequent calls.

# one-time login (interactive — finishes in the browser)
uv run notebooklm login --storage-path ./data/auth.json

The login command is provided by the upstream notebooklm-py CLI; see its README for browser options (--browser msedge, --browser-cookies chrome, multi-account --profile, etc.).

data/auth.json is git-ignored. Back it up somewhere safe — it is the only thing standing between you and a fresh login.

To refresh cookies silently (cron / launchd / systemd):

notebooklm auth refresh --quiet

4. Register with opencode

Add the server to ~/.config/opencode/opencode.json:

{
  "mcp": {
    "notebooklm": {
      "command": [
        "uv",
        "run",
        "--project",
        "<your-path>/mcp-notebooklm",
        "mcp-notebooklm",
      ],
      "timeout": 120000,
      "type": "local",
    },
  },
}

Restart opencode. The four tools (list_notebooks, find_notebook, ask_notebook, generate_quiz) appear as notebooklm__* and are available immediately.

The timeout (120s) covers the worst-case ask path: 10s queue + 60s ask + overhead. Raise it if you see transport resets on slow networks.

5. Use it

From inside opencode (or any MCP host):

list all my NotebookLM notebooks
find the notebook about <topic>
ask notebook <notebook_id>: <question grounded in that notebook's sources>

Typical flow the LLM will follow:

  1. list_notebooks() → choose the right notebook_id.

  2. ask_notebook(id, question) → get a cited answer.

  3. If the response starts with [RETRY_NEEDED], call the tool again.

Quiz generation

Generate structured quizzes that bypass NotebookLM's ~20 question limit by batching requests:

generate_quiz(
    notebook_id = "abc123",
    num_questions = 50,
    topic = "sorting algorithms",
    difficulty = "mixed",
    output_path = "~/quizzes/algorithms.json",
    cumulative = true,
    language = "es"
)

Parameters:

Param

Required

Default

Description

notebook_id

yes

Notebook to query

num_questions

yes

Total questions to generate

topic

no

"all sources"

Specific topic or full notebook

difficulty

no

"mixed"

easy / medium / hard / mixed

output_path

no

Save JSON to this path (creates directories if needed)

cumulative

no

false

If true and file exists, merge new questions with existing ones

language

no

"es"

Language for questions, options, and explanations

How batching works:

Questions are generated in batches of 15. For 50 questions, the tool makes 4 calls to NotebookLM (15 + 15 + 15 + 5), parses each response, and merges them into a single JSON. If a batch fails (timeout, parse error), it's skipped and failed_batches in metadata tells you how many were lost.

Output format:

{
  "metadata": {
    "notebook_id": "abc123",
    "notebook_title": "Algorithms",
    "generated_at": "2026-06-24T10:30:00Z",
    "topic": "sorting algorithms",
    "difficulty": "mixed",
    "total_questions": 50,
    "failed_batches": 0
  },
  "questions": [
    {
      "id": 1,
      "type": "multiple_choice",
      "question": "What is the average time complexity of quicksort?",
      "options": [
        {
          "text": "O(n)",
          "rationale": "Incorrect. Linear time only applies to specific cases like searching in unsorted arrays."
        },
        {
          "text": "O(n log n)",
          "rationale": "Correct. Quicksort averages O(n log n) with good pivot selection and balanced partitions."
        },
        {
          "text": "O(n²)",
          "rationale": "Incorrect. This is the worst-case complexity when the pivot selection is poor (e.g., already sorted array with first/last element as pivot)."
        },
        {
          "text": "O(log n)",
          "rationale": "Incorrect. Logarithmic time applies to operations like binary search, not full sorting algorithms."
        }
      ],
      "correct_answer": 1
    },
    {
      "id": 2,
      "type": "true_false",
      "question": "Mergesort is a stable sorting algorithm.",
      "correct_answer": true,
      "explanation": "Mergesort preserves the relative order of equal elements, making it stable."
    }
  ]
}

Cumulative mode:

When cumulative = true and output_path exists, new questions are appended to the existing array and IDs are renumbered sequentially. This lets you build up a question bank over multiple calls.

Project layout

src/mcp_notebooklm/
├── __init__.py
├── main.py        # entry point → server.main()
├── server.py      # FastMCP tool definitions (list, find, ask, generate_quiz)
└── service.py     # NotebookLMClient wrapper + concurrency / timeout guards + quiz generation
data/
└── auth.json      # notebooklm-py session storage (git-ignored)
pyproject.toml     # deps, entry point: mcp-notebooklm

Development

uv run ruff check src/        # lint
uv run flake8 src/           # style

Notes & limits

  • The upstream library uses undocumented Google APIs — endpoints can break without notice.

  • Heavy usage is rate-limited; the 1-concurrent semaphore is intentional, not a bug. Quiz generation with many questions will take time due to sequential batches.

  • chat.ask is the only endpoint used. Source management, artifact generation, etc. are not wired into the MCP surface.

  • The server is stdio-only. For HTTP, look at the upstream notebooklm-py REST server.

Available Tools

4 tools
ask_notebookA
Ask a question to a specific NotebookLM notebook and get an AI answer
based on its sources.

Args:
    notebook_id: The ID of the notebook to query
    (use list_notebooks to find IDs).
    question: The question to ask the notebook.
ParametersJSON Schema
NameRequiredDescriptionDefault
questionYes
notebook_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description fully bears the transparency burden. It describes the tool as a read operation (get answer), non-destructive. However, it lacks details on authentication, rate limits, or the exact format of the answer. The output schema may compensate, but the description itself is minimal.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Extremely concise and well-structured: one sentence for purpose followed by a numbered list for parameters. No unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (2 required params, no enums, output schema present), the description is complete. It explains what the tool does, the parameters needed, and how to get the notebook ID. The output schema likely covers return value details.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds valuable context beyond the schema by specifying that notebook_id is obtained via list_notebooks. The question parameter is simply restated. Schema coverage is 0%, so this addition is significant.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Ask a question' and the resource 'specific NotebookLM notebook', with a clear output 'get an AI answer based on its sources'. It distinguishes from siblings like list_notebooks, find_notebook, and generate_quiz by focusing on querying a notebook for answers.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implicitly guides usage by telling the user to use list_notebooks to find notebook IDs, but does not explicitly state when to use this tool vs alternatives or provide exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_notebookA
Find NotebookLM notebooks by title (partial match, case-insensitive).

Args:
    title: The title or partial title to search for.
ParametersJSON Schema
NameRequiredDescriptionDefault
titleYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description bears full burden. It reveals partial match and case-insensitivity but omits behaviors like what happens on no match, multiple results, or error handling, leaving gaps for an agent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no wasted words. Purpose is stated first, then parameter documented. Efficient and front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple search with one parameter and an existing output schema, the description is adequate but lacks details on return format, pagination, or edge cases (e.g., no results). Sibling differentiation is implicit only.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% (parameter has no description), so the description must add meaning. The line 'title: The title or partial title to search for.' clarifies the parameter's role beyond the type, which is helpful compensation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb (find) and resource (NotebookLM notebooks) and clarifies partial match and case-insensitive search, distinguishing it from siblings like list_notebooks (lists all) or ask_notebook (Q&A).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage when you have a title or partial title but does not explicitly state when to use this tool versus alternatives, nor provide exclusions or prerequisites.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

generate_quizA
Generate a quiz (JSON) from a NotebookLM notebook's sources.

Generates questions in batches to bypass NotebookLM's ~20 question
limit. Supports multiple_choice and true_false question types.

Args:
    notebook_id: The notebook to generate questions from.
    num_questions: Total number of questions to generate.
    topic: Specific topic or "all sources" for everything.
    difficulty: easy, medium, hard, or mixed.
    output_path: Optional file path to save the JSON quiz.
    cumulative: If true and output_path exists, merge with existing.
    language: Language for questions (default: "es").
ParametersJSON Schema
NameRequiredDescriptionDefault
topicNoall sources
languageNoes
cumulativeNo
difficultyNomixed
notebook_idYes
output_pathNo
num_questionsYes

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description bears full responsibility for behavioral disclosure. It explains batching to bypass limits and support for question types, but does not mention side effects, authentication requirements, or whether the tool is read-only. This leaves some uncertainty, warranting a 3.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is moderately sized and well-structured: a one-line summary, a behavioral note, and a bulleted Args list. It front-loads the main purpose. Slightly verbose due to the Args repetitions, but overall efficient. A 4 reflects good but not perfect conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers key aspects: parameters, batching, question types, and cumulative merging. However, it lacks details about the output JSON format (keys, structure), which would be helpful given no output schema. The language default ('es') is mentioned without explanation. Overall adequate but with notable gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 0% description coverage, so the description must compensate. It does so comprehensively by listing all 7 parameters with clear explanations, defaults, and permissible values (e.g., topic: 'all sources', difficulty: easy/medium/hard/mixed). This adds full meaning beyond the schema's bare types.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: generating a JSON quiz from a NotebookLM notebook's sources. It specifies the output format (JSON) and resource (notebook's sources). The verb 'generate' is specific, and the tool is distinct from sibling tools (ask, find, list). No ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not explicitly state when to use this tool versus alternatives. It mentions supporting multiple_choice and true_false question types, which provides some guidance, but no explicit context on when to choose this over siblings like ask_notebook. A 3 reflects the lack of direct usage instructions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_notebooksA

List all available NotebookLM notebooks with their IDs, titles, and source counts.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It only describes the action and output, lacking details on side effects, permissions, or limits. However, as a read-only list operation, the description is minimally adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single concise sentence that front-loads the verb 'List' and clearly conveys the action and output. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given zero parameters and the existence of an output schema, the description sufficiently explains the tool's purpose and result. It could mention that it returns all accessible notebooks, but overall it is complete for a simple listing tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero parameters, so the schema coverage is 100% trivially. Per guidelines, baseline is 4. The description adds no parameter info but none is needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it lists all available notebooks and specifies the returned fields (IDs, titles, source counts). This distinguishes it from sibling tools like ask_notebook, find_notebook, and generate_quiz.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies use for getting an overview of notebooks but does not explicitly state when to use this tool versus alternatives or when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv0.1.0
    • First observedask_notebook
    • First observedfind_notebook
    • First observedgenerate_quiz
    • First observedlist_notebooks

TDQS

A4.1/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a distinct, non-overlapping purpose: listing notebooks, finding by title, asking questions, and generating quizzes. No ambiguity.

Naming Consistency5/5

All tools follow a consistent verb_noun snake_case pattern (list_notebooks, find_notebook, ask_notebook, generate_quiz), making predictions easy.

Tool Count5/5

With 4 tools, the server is well-scoped for interacting with NotebookLM notebooks—covering essential operations without excess.

Completeness4/5

Covers listing, searching, asking, and quiz generation. Minor gaps like notebook creation/deletion or source retrieval, but these are outside the server's apparent focus.

Maintenance

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers