NotebookLMPyPIMCPPythonOpen SourceIndie Dev

From zero to PyPI: making NotebookLM programmable

··4 min read

Updated September 21, 2026: Google Cloud provides enterprise notebook-management APIs with enterprise setup and licensing. kof-notebooklm-mcp is an unofficial web-automation integration; the earlier blanket statement that NotebookLM cannot be controlled programmatically has been corrected.

What problem was I trying to solve?

The goal was straightforward. I wanted to create a NotebookLM notebook from a development environment such as Cursor, import technical documents or meeting notes, ask questions, and receive answers with source citations.

If those actions could be triggered by code, NotebookLM could become a knowledge-service node inside a larger workflow instead of remaining a standalone product.

Where did the tool come from?

This project did not begin as an independent package. kof-notebooklm-mcp was originally an internal tool inside keeponfirst-local-brain. The central idea was simple: use a local Git repository as the single source of truth, let documents and development notes evolve with the codebase, and let AI tools keep reading, analyzing, and responding to that material.

In that architecture, the Git repository is the formal source and documentation changes with the project. NotebookLM is a research and analysis node, not a separate app.

The main implementation problems

The first problem was authentication. Google sign-in includes multi-factor authentication and risk detection, so fully automating it is not practical. The current approach asks the user to sign in manually on the first run, saves the browser session, and reuses it later.

The second problem was a highly dynamic interface. NotebookLM changes frequently, so browser automation can break easily. To improve stability, the implementation prioritizes accessibility attributes and visible text instead of binding itself to the DOM structure, and it checks state before important actions.

Why split it into a standalone package?

Keeping the tool in a monorepo was convenient for development but awkward for users to install. The tradeoff was clear: the monorepo preserved development convenience, while a standalone package required cleanup but lowered the barrier to trying the tool.

I eventually extracted kof-notebooklm-mcp so a user could begin with one command: pip install kof-notebooklm-mcp.

Publishing to PyPI with Trusted Publisher

The release process uses PyPI Trusted Publisher. It avoids a long-lived API token by binding publishing permission to the GitHub repository, and GitHub Actions authenticates through OIDC. The setup is small and better suited to long-term maintenance.

The point of the project

The point was to make a useful tool participate in a real workflow. When software cannot be controlled programmatically, the limitation affects more than efficiency; it also narrows what the surrounding system can do.

GitHub: https://github.com/keeponfirst/kof-notebooklm-mcp | PyPI: pip install kof-notebooklm-mcp

Installation is only the first step

The package documents three setup steps: install it, install Playwright Chromium, and initialize authentication. Use a virtual environment to isolate dependencies; the package requires Python 3.10 or newer. These instructions were checked against the published setup documentation, not an authenticated Google session in this revision.

bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install kof-notebooklm-mcp
python -m playwright install chromium
kof-notebooklm-init

Complete sign-in yourself in the opened browser. Keep passwords, verification codes, and browser profiles out of the repository. The documented default profile directory is ~/.kof-notebooklm/profile. Treat its reusable authentication state as account credentials when backing up or moving it.

Point the MCP client at the same environment

An IDE’s MCP process may not inherit the terminal’s virtual environment. If the command is missing after installation, run command -v kof-notebooklm-mcp with the environment active and use the returned absolute path as the client command. Configuration locations differ by client; this illustrates the relevant fields, not a universal IDE configuration file.

json
{
  "mcpServers": {
    "notebooklm": {
      "command": "/absolute/path/to/.venv/bin/kof-notebooklm-mcp",
      "args": []
    }
  }
}

Check read-only operations before creating a test notebook

Call health_check, then compare list_notebooks with the notebooks visible in the browser. Once those work, create a dedicated test notebook with a short known source. Verify both the answer and its citation against that source. Nonempty output alone does not establish correctness.

An empty list could mean no notebooks, an expired session, an unfinished page load, or a broken selector. If a source was added but cannot be used, check whether its processing finished. Classifying the failed stage is more useful than reinstalling everything.

Next: check stale replies, partial streams, and UI contamination

Sources

Read the author’s original publication