Pythonic wrapper for NotebookLM via notebooklm-mcp-cli MCP server
Project description
NotebookLM Wrapper
Pythonic wrapper for Google NotebookLM via the MCP (Model Context Protocol). Connects to the notebooklm-mcp server and provides a clean, typed interface to all NotebookLM functionality.
Features
- Clean Python API - No subprocess or CLI calls
- Full type safety - Pydantic models for all data
- Sync + Async - Use either programming style
- 28 operations - Notebooks, sources, chat, research, studio, sharing, and more
- Auth handled by server - Run
nlm loginonce, then use the wrapper
Requirements
- Python 3.11+
- notebooklm-mcp-cli (installed automatically)
Installation
From PyPI (once published):
pip install notebooklm-wrapper
From source (development or unreleased):
pip install git+https://github.com/ai-chitect/notebooklm-wrapper.git
# or, from a local clone:
pip install -e .
Publishing to PyPI: Run ./scripts/publish.sh (runs tests, builds, then publishes). Use ./scripts/publish.sh --test for TestPyPI. Requires hatch and PyPI credentials.
Prerequisites: Authenticate with NotebookLM (one-time setup):
pip install notebooklm-mcp-cli
nlm login # Opens browser for authentication
Quick Start
from notebooklm_wrapper import NotebookLMClient
# Initialize client (uses default profile from nlm login)
client = NotebookLMClient()
# List notebooks
notebooks = client.notebook.list()
for nb in notebooks:
print(f"{nb.title} ({nb.id})")
# Create notebook
notebook = client.notebook.create(title="My Research")
# Add sources
client.source.add(
notebook.id,
"url",
url="https://example.com/article",
)
# Ask questions
response = client.chat.ask(notebook.id, "What are the main points?")
print(response.answer)
for citation in response.citations:
print(f" - {citation.source_title}")
Async Usage
import asyncio
from notebooklm_wrapper import AsyncNotebookLMClient
async def main():
client = AsyncNotebookLMClient()
notebooks = await client.notebook.list()
print(f"Found {len(notebooks)} notebooks")
# Create and query
notebook = await client.notebook.create(title="Async Research")
response = await client.chat.ask(notebook.id, "Summarize the key findings")
print(response.answer)
asyncio.run(main())
Multi-Profile
# Use specific profile (set via NOTEBOOKLM_MCP_PROFILE when spawning server)
client = NotebookLMClient(profile="work")
notebooks = client.notebook.list()
# Async with profile
async_client = AsyncNotebookLMClient(profile="personal")
Multi-User / Web App
For multi-tenant apps (e.g. on Google Cloud) where each user has their own NotebookLM credentials stored in your DB (encrypted) and obtained via OAuth, use config_dir to isolate credentials per user. The wrapper spawns one MCP server process per client; with a unique config_dir per user, that process uses a dedicated credential store under config_dir/.notebooklm-mcp-cli.
- Store credentials: After OAuth (or user-provided cookies), encrypt and store the cookie string in your DB keyed by user id.
- Per request/session: Create a user-specific directory (or use a persistent path per user), decrypt credentials from your DB, then create a client and inject tokens:
import os
from notebooklm_wrapper import AsyncNotebookLMClient
async def notebooklm_client_for_user(user_id: str, decrypted_cookies: str):
# Use a dedicated dir per user so the MCP server stores credentials there
config_dir = f"/app/data/users/{user_id}"
os.makedirs(config_dir, exist_ok=True)
client = AsyncNotebookLMClient(
profile=user_id,
config_dir=config_dir,
)
# Inject credentials so the server can use them (first time or refresh)
await client.auth.save_tokens(cookies=decrypted_cookies)
return client
# Then use the client as usual
async def handle_request(user_id: str, ...):
cookies = get_encrypted_cookies_from_db(user_id)
decrypted = decrypt(cookies)
client = await notebooklm_client_for_user(user_id, decrypted)
try:
notebooks = await client.notebook.list()
# ...
finally:
await client.disconnect()
See docs/multi-user-credentials-design.md for how credential isolation works and design details.
API Reference
| Resource | Methods |
|---|---|
client.notebook |
list(), get(id), describe(id), create(title), rename(id, title), delete(id, confirm=True) |
client.source |
add(notebook_id, type, url=...), list_drive(notebook_id), sync_drive(ids, confirm=True), delete(id, confirm=True), describe(id), get_content(id) |
client.chat |
ask(notebook_id, query), configure(notebook_id, goal=..., response_length=...) |
client.research |
start(query, source="web", mode="fast"), status(notebook_id), import_sources(notebook_id, task_id) |
client.studio |
create(notebook_id, type, confirm=True), status(notebook_id), delete(notebook_id, artifact_id, confirm=True) |
client.share |
status(notebook_id), set_public(notebook_id, is_public), invite(notebook_id, email, role="viewer") |
client.download |
artifact(notebook_id, type, output_path) |
client.note |
create(notebook_id, content, title=...), list(notebook_id), update(notebook_id, note_id, ...), delete(notebook_id, note_id, confirm=True) |
client.auth |
refresh(), save_tokens(cookies, ...) |
client.export |
to_docs(notebook_id, artifact_id), to_sheets(notebook_id, artifact_id) |
Error Handling
All operations raise NotebookLMError subclasses on failure:
from notebooklm_wrapper import (
NotebookLMClient,
AuthenticationError,
NotFoundError,
ValidationError,
RateLimitError,
GenerationError,
)
client = NotebookLMClient()
try:
notebooks = client.notebook.list()
except AuthenticationError:
print("Run 'nlm login' to authenticate")
except NotFoundError as e:
print(f"Not found: {e}")
except RateLimitError as e:
print(f"Rate limited. Retry after: {e.retry_after}s")
Error messages include the tool name for easier debugging (e.g. [notebook_list] Please login first).
Development
# Clone the repository
git clone https://github.com/ai-chitect/notebooklm-wrapper.git
cd notebooklm-wrapper
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # Linux/macOS
# .venv\Scripts\activate # Windows
# Install in editable mode with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run tests with coverage
pytest --cov=notebooklm_wrapper --cov-report=term-missing
# Lint
ruff check src/ tests/
# Format
black src/ tests/
isort src/ tests/
# Type check
mypy src/
# Publish to PyPI (after tests pass)
./scripts/publish.sh
# Test OAuth + list notebooks (integration-style; opens browser for login)
python scripts/test_oauth_list_notebooks.py
# Reuse credentials in a directory (skip login next time):
python scripts/test_oauth_list_notebooks.py --config-dir ./tmp_oauth_test
python scripts/test_oauth_list_notebooks.py --config-dir ./tmp_oauth_test --skip-login
# Test paste-cookie flow (use a file for long cookie strings):
echo "SID=...; __Secure-1PSID=...; ..." > cookies.txt # paste from browser
python scripts/test_cookie_list_notebooks.py --cookie-file cookies.txt
# Or prompt for short cookie, or stdin:
python scripts/test_cookie_list_notebooks.py
cat cookies.txt | python scripts/test_cookie_list_notebooks.py --stdin
Acknowledgments
This wrapper connects to the notebooklm-mcp-cli MCP server by Jacob Ben-David, which provides the underlying NotebookLM integration. That project is MIT-licensed and compatible with this wrapper.
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file notebooklm_wrapper-0.1.3.tar.gz.
File metadata
- Download URL: notebooklm_wrapper-0.1.3.tar.gz
- Upload date:
- Size: 149.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: Hatch/1.16.3 cpython/3.13.5 HTTPX/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5de19177c3deb0c59afbab7f968630a9b788aecb2c3863ddeaab41d2bdd37638
|
|
| MD5 |
9a41eb359c06430049c5a9536b4f50fe
|
|
| BLAKE2b-256 |
6c1f355a4dd43c363c5bc4cc74f9231b437cb65bd0c383ad22b96ca927fc347c
|
File details
Details for the file notebooklm_wrapper-0.1.3-py3-none-any.whl.
File metadata
- Download URL: notebooklm_wrapper-0.1.3-py3-none-any.whl
- Upload date:
- Size: 25.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: Hatch/1.16.3 cpython/3.13.5 HTTPX/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1d9a825ca65d5bd90fb0402154eebffdb1f87d8872feb70a5709f12e2ca1a91
|
|
| MD5 |
9e257b28db533e4b5df176a9d245ea10
|
|
| BLAKE2b-256 |
501bd3e7a57720fe5b77ac2c2ec1e2f12a06f63eee8d6a712d66ae1292cf5058
|