Skip to main content
Glama
furkancakmakcreative

NotebookLM Curator

notebooklm-curator

An MCP server that audits and prunes Gemini Notebook (formerly NotebookLM) libraries.

Not an official Google or Anthropic integration. This drives NotebookLM through your own signed-in Chrome profile — it is not affiliated with, endorsed by, or connected to Google in any way. Consider using a separate Google account rather than your primary one; the account parameter supports multiple profiles. See Known limitations for the full picture before pointing it at anything you care about.

Off-the-shelf NotebookLM MCPs give you add_source and ask_question. None of them give you these three:

Tool

What it does

In other NotebookLM MCPs

nlm_list_sources

Lists the sources in a notebook

✗ missing

nlm_remove_source

Deletes a source

✗ missing

nlm_audit

Flags stale sources by shelf life

✗ missing

Also included: nlm_auth, nlm_list_notebooks, nlm_create_notebook, nlm_rename_notebook, nlm_add_source, nlm_ask.

nlm_audit output inside Claude Desktop

(Titles above are representative examples; the counts reflect a real run against a 56-source notebook.)


Why browser automation

NotebookLM has no public API on the consumer side. Source lists, publish dates, and deletion are not reachable over HTTP. The Gemini Notebook Enterprise API on Google Cloud is a separate product that needs an enterprise account.

So the only way in is a persistent Chrome profile. Every selector lives in one file, src/notebooklm.js — when Google ships a UI change, that's the only file that needs an update.

Selectors were verified live against notebooklm.google.com on 2026-07-29.


Related MCP server: OneClickLM

Requirements

  • Node.js 20+

  • Google Chrome installed (Windows or macOS — the standard desktop app from google.com/chrome). This tool automates your real Chrome install on purpose, not a downloaded Chromium build: patchright's anti-detection patches are far more effective against NotebookLM's bot checks when running inside an actual Chrome, so we don't trade that away for a "works anywhere" default. If Chrome isn't found, nlm_auth/any tool call fails immediately with a clear message instead of a cryptic browser-launch error. Because real Chrome is used by default, npm install does not download a separate Chromium build — nothing extra to fetch, nothing extra on disk. (If you deliberately opt into NLM_BROWSER_CHANNEL=chromium, run npx patchright install chromium once yourself first.)

  • Tested on Windows and macOS. Linux is not a current target.

Setup

git clone https://github.com/furkancakmakcreative/notebooklm-curator.git
cd notebooklm-curator
npm install

Copy .env.example to .env if you want nlm_audit's YouTube date resolution:

YOUTUBE_API_KEY=your_own_key

The key stays on your machine. The server only sends it to googleapis.com and never logs or forwards it elsewhere.

Connecting to Claude Desktop / Claude Code

%APPDATA%\Claude\claude_desktop_config.json (Windows) or the equivalent config on macOS/Linux:

{
  "mcpServers": {
    "notebooklm-curator": {
      "command": "node",
      "args": ["/full/path/to/notebooklm-curator/src/index.js"],
      "env": { "YOUTUBE_API_KEY": "your_own_key" }
    }
  }
}

Fully restart Claude Desktop. On first use, call nlm_auth: a visible Chrome window opens, you sign in with your Google account once, and the session is saved to a persistent local profile. Every run after that is headless.


Getting a YouTube API key

Google Cloud Console → APIs & Services

  1. Library → search "YouTube Data API v3" → Enable

  2. CredentialsCreate credentialsAPI key

  3. Click the key → API restrictionsRestrict key → select only YouTube Data API v3 → Save

Don't skip step 3. If a restricted key ever leaks, it can only read public YouTube data — it can't touch your account or spend money.

Quota — this matters

The free daily quota is 10,000 units:

  • videos.list1 unit per call (up to 50 videos)

  • search.list100 units per call (one title)

NotebookLM never exposes a source's URL, so the first audit has to search by title: 83 sources ≈ 8,300 units, most of the daily quota. But that search returns a videoId. Save it and pass it back to nlm_audit as knownIds — every later audit then uses the cheap videos.list path, ~2 units total.

The searchBudget parameter caps this cost (default 60).


Shelf-life policy

A single global "40 days" threshold gets the wrong answer both ways: a model announcement is dead in three weeks; a typography video is still useful in three years. Shelf life is therefore a function of category:

Category

Days

What lands here

news

30

announcements, release notes, weekly roundups

tactics

45

rate limits, model ranking/picking advice tied to a moving target

tool

60

tool usage, workflow tied to a specific release

official

150

Anthropic/Claude official product-feature videos

tutorial

120

courses, walkthroughs, technical deep-dives

principle

1095

theory, strategy, timeless craft

nlm_audit guesses a category from the title heuristically; override any threshold with the categories parameter:

{ "notebookId": "...", "categories": { "news": 14, "tool": 45 } }

Status values: freshaging (75% of shelf life burned) → stale. Sources whose date can't be resolved are unknown — a date is never guessed.

By default the response only gives you counts for fresh/pinned sources, not their full per-item detail — you rarely need to see the sources that need no action. Pass includeFresh: true to get everything, e.g. for a full-library export.


Delete safety

nlm_remove_source is irreversible and refuses to run without confirm: true. nlm_audit never deletes anything — it only produces a report.

Intended flow: nlm_audit → show the list to the user → call nlm_remove_source one title at a time for what they approve. The model bulk-deleting on its own is blocked by design.


How nlm_ask actually detects "the answer is done"

This turned out to be the hardest part of the tool, worth documenting because the wrong approach looks like it works until it silently doesn't.

The first instinct is to poll document.querySelector('main').innerText until it stops changing. That's wrong: NotebookLM's chat panel renders outside <main> entirely. The text there never changes, so the polling loop reports "stable" almost instantly and returns whatever happens to be sitting in <main> at that moment — in one observed case, hidden emoji-picker markup that had nothing to do with the question asked.

The actual reliable signal is a .thinking-message element (it carries an is-changing class while streaming) detaching from the DOM once the model finishes. Even then, the query textarea's disabled attribute clears slightly after that detachment — firing the next question too early hits a still-disabled box and hangs. ask() in src/notebooklm.js waits for both, in order, before reading the last .chat-message-pair's answer text.

If you're extending this tool and NotebookLM's DOM changes again, that's the one thing worth re-verifying live before touching anything else. If a wait times out, nlm_ask sets incomplete: true on its response rather than silently returning stale or partial text as if it were final.

nlm_ask also enforces a minimum gap (default 4s, NLM_MIN_ASK_INTERVAL_MS) between question submissions. Firing questions back-to-back is a pattern real usage never produces, and it's the most plausible trigger for NotebookLM occasionally refusing to answer ("Şu anda yanıt vermekte zorlanıyorum") — this is cheap insurance against that, not a confirmed root cause.


Known limitations

  • Source URLs are not readable. NotebookLM never puts them in the DOM — no href, no data attribute, clicking a row doesn't reveal one either. Titles are used as the identifier instead, so two sources with an identical title can't be told apart (findDuplicates reports these separately).

  • The delete confirmation dialog may or may not appear depending on rollout; the code handles both and verifies the source count afterward. removeSource re-checks the target row's title immediately before acting on it, but a full guarantee against the list reordering mid-click isn't possible with index-based targeting alone.

  • UI text matching is English/Turkish only. Menu items, buttons, and the category-guessing heuristics in policy.js match against those two languages; a notebook in a third UI language may fail to categorize or to find the "remove" menu item.

  • Freshness dates only resolve for YouTube sources today. Web pages and PDFs always come back unknown — there's no per-page date extraction yet.

  • Fixed waitForTimeout calls are used in a few places instead of polling for a DOM signal; on a slow connection they can under-wait, on a fast one they add latency. ask() uses the more robust polling pattern — anything ported from removeSource/addSource should follow that model instead.

  • If Google changes the UI, src/notebooklm.js is the only file that needs updating.

  • renameNotebook and addSource report success once the DOM action is triggered, without re-reading the page to confirm it actually applied (unlike removeSource, which re-verifies). On a slow/flaky page a rename or add could silently no-op.

  • The Chrome profile directory is created with mode: 0o700, which is a no-op on Windows NTFS (no ACL is set) — on Windows the directory's permissions are whatever the OS default is for your user folder, not actually restricted to your account alone.

Roadmap

Ideas that didn't make v0.1, roughly in order of value:

  • Export an nlm_audit report to Markdown/CSV for offline review.

  • A batch-delete tool that takes a pre-approved list of {title, occurrence} pairs (still gated by an explicit human-approved list, not autonomous).

  • Cross-notebook source search/duplicate detection (findDuplicates already generalizes to this — it just isn't wired up across notebooks yet).

  • Date resolution for web sources via Last-Modified headers or article:published_time / JSON-LD datePublished metadata.

Contributions on any of these are welcome.

License

MIT

A
license - permissive license
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • MCP server for generating rough-draft project plans from natural-language prompts.

  • Augments MCP Server - A comprehensive framework documentation provider for Claude Code

  • MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/furkancakmakcreative/notebooklm-curator'

If you have feedback or need assistance with the MCP directory API, please join our Discord server