Skip to main content

Managing the Notebook Library

Complete guide to the multi-notebook library system


📚 Overview

The NotebookLM MCP HTTP Server integrates a library system that allows you to manage multiple NotebookLM notebooks and easily switch between them.

Key features:

  • ✅ Add multiple notebooks with automatic validation
  • ✅ Switch between notebooks in a single request
  • ✅ Live validation (verifies that the notebook actually exists)
  • ✅ Duplicate protection
  • ✅ Usage statistics per notebook
  • ✅ Library search

🗂️ Library Structure

library.json File

Location: %LOCALAPPDATA%\notebooklm-mcp\Data\library.json

{
"notebooks": [
{
"id": "parents-numerique",
"url": "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000101",
"name": "Parents et Numérique",
"description": "Conseils pour parents à l'ère du numérique",
"topics": ["parentalité", "numérique", "éducation"],
"content_types": ["documentation", "examples"],
"use_cases": [
"Conseils éducatifs à l'ère du numérique",
"Questions sur la parentalité et les écrans"
],
"added_at": "2025-11-22T08:49:16.735Z",
"last_used": "2025-11-22T09:30:45.123Z",
"use_count": 15,
"tags": ["psychology", "french"]
},
{
"id": "shakespeare",
"url": "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000102",
"name": "Shakespeare",
"description": "William Shakespeare - L'intégrale des pièces",
"topics": ["littérature", "théâtre", "Shakespeare"],
"content_types": ["documentation", "examples"],
"use_cases": ["Recherche sur les œuvres de Shakespeare", "Analyse littéraire et citations"],
"added_at": "2025-11-22T08:54:33.592Z",
"last_used": "2025-11-22T08:54:39.064Z",
"use_count": 3,
"tags": ["psychology"]
}
],
"active_notebook_id": "parents-numerique",
"last_modified": "2025-11-22T09:36:04.837Z",
"version": "1.0.0"
}

NotebookEntry Fields

FieldTypeDescription
idstringUnique ID (slug generated from name)
urlstringNotebookLM URL (validated)
namestringNotebook name (unique)
descriptionstringComplete description
topicsstring[]List of covered topics
content_typesstring[]Content types (docs, examples, etc.)
use_casesstring[]Recommended use cases
added_atISO dateDate added
last_usedISO dateLast used
use_countnumberNumber of requests
tagsstring[]Custom tags

🚀 Getting Started Guide

1. Automatic Initialization

On first startup, the library is empty:

{
"notebooks": [],
"active_notebook_id": null,
"last_modified": "2025-11-22T08:00:00.000Z",
"version": "1.0.0"
}

2. Add Your First Notebook

Step 1: Get the NotebookLM URL

  1. Open https://notebooklm.google.com
  2. Open your notebook
  3. Copy the URL from the address bar

Expected format: https://notebooklm.google.com/notebook/[id]

Step 2: Add the notebook

curl -X POST http://localhost:3000/notebooks \
-H "Content-Type: application/json" \
-d '{
"url": "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000101",
"name": "Parents et Numérique",
"description": "Conseils pour parents à l'ère du numérique",
"topics": ["parentalité", "numérique", "éducation"]
}'

PowerShell:

$body = @{
url = "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000101"
name = "Parents et Numérique"
description = "Conseils pour parents à l'ère du numérique"
topics = @("parentalité", "numérique", "éducation")
} | ConvertTo-Json

Invoke-RestMethod -Uri "http://localhost:3000/notebooks" `
-Method Post `
-Body $body `
-ContentType "application/json"

⏱️ Warning: Adding takes 15-30 seconds because the server validates that the notebook actually exists.

3. Add Other Notebooks

Repeat the operation for each notebook:

# Shakespeare Notebook
$body = @{
url = "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000102"
name = "Shakespeare"
description = "William Shakespeare - L'intégrale des pièces"
topics = @("littérature", "théâtre", "Shakespeare")
tags = @("literature", "theater")
} | ConvertTo-Json

Invoke-RestMethod -Uri "http://localhost:3000/notebooks" `
-Method Post `
-Body $body `
-ContentType "application/json"

4. List Your Notebooks

curl http://localhost:3000/notebooks

PowerShell:

Invoke-RestMethod -Uri "http://localhost:3000/notebooks"

🎯 Usage

Using the Active Notebook

If a notebook is marked as active (active_notebook_id), no need to specify the ID:

curl -X POST http://localhost:3000/ask \
-H "Content-Type: application/json" \
-d '{
"question": "Qu'\''est-ce que l'\''empathie?"
}'

The server will automatically use the active notebook.

Using a Specific Notebook

To use a specific notebook, use notebook_id:

curl -X POST http://localhost:3000/ask \
-H "Content-Type: application/json" \
-d '{
"question": "Quelles sont les principales pièces de Shakespeare?",
"notebook_id": "shakespeare"
}'

Change the Active Notebook

curl -X PUT http://localhost:3000/notebooks/shakespeare/activate

PowerShell:

Invoke-RestMethod -Uri "http://localhost:3000/notebooks/shakespeare/activate" -Method Put

✅ Automatic Validations

1. URL Format

The server verifies that the URL is in NotebookLM format:

Valid:

https://notebooklm.google.com/notebook/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Invalid:

https://example.com/notebook
https://notebooklm.google.com/
https://notebooklm.google.com/notebook/

2. Live Validation (Existence)

When adding, the server:

  1. Creates a temporary session
  2. Opens the notebook in headless Chrome
  3. Verifies that the chat interface loads
  4. Closes the temporary session

Detected errors:

  • Non-existent notebook
  • Notebook without access (permissions)
  • Incorrect URL
  • Invalid notebook ID

Error example:

{
"success": false,
"error": "Invalid or inaccessible notebook.\n\nURL: https://notebooklm.google.com/notebook/invalid-id\n\nThe notebook page loaded but the chat interface was not found.\nThis usually means:\n- The notebook doesn't exist\n- You don't have access to this notebook\n- The notebook ID in the URL is incorrect\n\nPlease verify the URL by:\n1. Go to https://notebooklm.google.com\n2. Open the notebook manually\n3. Copy the exact URL from the address bar"
}

3. Duplicate Detection

The server blocks adding notebooks with the same name (case-insensitive):

# First add: OK
POST /notebooks {"name": "Parents et Numérique", ...} # ✅

# Second add with same name: ERROR
POST /notebooks {"name": "parents et numérique", ...} # ❌ (case-insensitive)

Returned error:

{
"success": false,
"error": "A notebook with the name 'Parents et Numérique' already exists.\n\nExisting notebook ID: parents-numerique\nURL: https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000101\n\nPlease use a different name, or update the existing notebook instead.\nTo update: PUT /notebooks/parents-numerique with new data\nTo delete: DELETE /notebooks/parents-numerique"
}

📊 Usage Statistics

Automatic Counters

Each request to a notebook automatically increments:

  • use_count - Total number of requests
  • last_used - Last used timestamp

Get Statistics

curl http://localhost:3000/notebooks

The response includes metadata for each notebook:

{
"success": true,
"data": {
"notebooks": [
{
"id": "parents-numerique",
"name": "Parents et Numérique",
"use_count": 42,
"last_used": "2025-11-22T10:30:45.123Z",
...
}
]
}
}

Most Used Notebook

The notebook with the most use_count appears in the health check:

curl http://localhost:3000/health
{
"success": true,
"data": {
"library_notebooks": 2,
"most_used": "parents-numerique"
}
}

🗑️ Notebook Management

Delete a Notebook

curl -X DELETE http://localhost:3000/notebooks/parents-numerique

Behavior:

  • Removes the notebook from library.json
  • If it was the active notebook, automatically selects the first remaining notebook
  • Open sessions on this notebook remain active

Notebook Details

curl http://localhost:3000/notebooks/parents-numerique

Returns all metadata:

{
"success": true,
"data": {
"notebook": {
"id": "parents-numerique",
"url": "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000101",
"name": "Parents et Numérique",
"description": "Conseils pour parents à l'ère du numérique",
"topics": ["parentalité", "numérique", "éducation"],
"content_types": ["documentation", "examples"],
"use_cases": ["Conseils éducatifs", "Parentalité numérique", ...],
"added_at": "2025-11-22T08:49:16.735Z",
"last_used": "2025-11-22T09:30:45.123Z",
"use_count": 42,
"tags": ["psychology", "french"]
}
}
}

Search by Name, Description, Topics

Search is not yet exposed via the HTTP API, but it exists in the code:

// In src/library/notebook-library.ts:441
searchNotebooks(query: string): NotebookEntry[]

Searches in:

  • Notebook name
  • Description
  • Topics
  • Tags

Coming in a future version: GET /notebooks/search?q=empathie


💡 Use Cases

1. Multi-Project Workspace

You work on multiple projects with different notebooks:

{
"notebooks": [
{"id": "projet-a", "name": "Projet A - API Documentation", ...},
{"id": "projet-b", "name": "Projet B - User Research", ...},
{"id": "projet-c", "name": "Projet C - Technical Specs", ...}
]
}

Switch easily according to context:

# Work on Project A
curl -X PUT http://localhost:3000/notebooks/projet-a/activate

# Ask questions (will use Project A)
curl -X POST http://localhost:3000/ask -d '{"question": "..."}'

# Switch to Project B
curl -X PUT http://localhost:3000/notebooks/projet-b/activate

2. Multi-Language Documentation

Notebooks for different languages:

{
"notebooks": [
{"id": "docs-fr", "name": "Documentation Française", ...},
{"id": "docs-en", "name": "English Documentation", ...},
{"id": "docs-es", "name": "Documentación Española", ...}
]
}

3. Knowledge Domains

Notebooks by area of expertise:

{
"notebooks": [
{
"id": "psychology",
"name": "Psychology Resources",
"topics": ["mindfulness", "therapy", "CBT"]
},
{ "id": "tech", "name": "Tech Documentation", "topics": ["React", "Node", "TypeScript"] },
{ "id": "business", "name": "Business Knowledge", "topics": ["marketing", "sales"] }
]
}

4. Environments (Dev/Staging/Prod)

Different notebooks for different environments:

{
"notebooks": [
{"id": "dev-kb", "name": "Dev Knowledge Base", ...},
{"id": "staging-kb", "name": "Staging Knowledge Base", ...},
{"id": "prod-kb", "name": "Production Knowledge Base", ...}
]
}

🔧 Advanced Configuration

Manually Edit library.json

Location: %LOCALAPPDATA%\notebooklm-mcp\Data\library.json

# Open in an editor
code "$env:LOCALAPPDATA\notebooklm-mcp\Data\library.json"

# Or notepad
notepad "$env:LOCALAPPDATA\notebooklm-mcp\Data\library.json"

⚠️ Warning:

  • Respect the JSON format (validate with a linter)
  • Restart the server after manual modification
  • Manual modifications do not go through validations

Export/Import the Library

Export:

Copy-Item "$env:LOCALAPPDATA\notebooklm-mcp\Data\library.json" `
-Destination "D:\backup\library-backup.json"

Import:

Copy-Item "D:\backup\library-backup.json" `
-Destination "$env:LOCALAPPDATA\notebooklm-mcp\Data\library.json"

Reset the Library

# Backup first
Copy-Item "$env:LOCALAPPDATA\notebooklm-mcp\Data\library.json" `
-Destination "$env:LOCALAPPDATA\notebooklm-mcp\Data\library-backup.json"

# Delete
Remove-Item "$env:LOCALAPPDATA\notebooklm-mcp\Data\library.json"

# Restart the server (will create an empty library)

🐛 Troubleshooting

Problem: "Notebook not found in library"

Cause: No notebook configured or incorrect ID

Solution:

# List available notebooks
curl http://localhost:3000/notebooks

# Verify the exact ID
# Use notebook_url directly if needed
curl -X POST http://localhost:3000/ask \
-d '{
"question": "...",
"notebook_url": "https://notebooklm.google.com/notebook/xxx"
}'

Problem: Validation fails during addition

Cause: Inaccessible notebook or invalid URL

Solution:

  1. Verify that you are authenticated: npm run setup-auth
  2. Test the URL manually in Chrome
  3. Check notebook permissions (shared with your account?)
  4. Copy the URL directly from the address bar

Problem: "A notebook with the name 'X' already exists"

Cause: Duplicate name

Solutions:

# Option 1: Use a different name
curl -X POST http://localhost:3000/notebooks \
-d '{"name": "Parents et Numérique v2", ...}'

# Option 2: Delete the old one
curl -X DELETE http://localhost:3000/notebooks/parents-numerique

# Option 3: Update the existing one (coming soon)
# PUT /notebooks/my-notebook

Problem: Corrupted library.json

Symptoms: JSON errors at startup

Solution:

# Restore from backup if available
Copy-Item "$env:LOCALAPPDATA\notebooklm-mcp\Data\library-backup.json" `
-Destination "$env:LOCALAPPDATA\notebooklm-mcp\Data\library.json"

# Or delete and reset
Remove-Item "$env:LOCALAPPDATA\notebooklm-mcp\Data\library.json"
# Restart the server

📝 Complete Examples

PowerShell Script: Add Multiple Notebooks

#!/usr/bin/env pwsh

# Configuration
$baseUrl = "http://localhost:3000"

# List of notebooks to add
$notebooks = @(
@{
url = "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000101"
name = "Parents et Numérique"
description = "Conseils pour parents à l'ère du numérique"
topics = @("parentalité", "numérique", "éducation")
},
@{
url = "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000102"
name = "Shakespeare"
description = "William Shakespeare - L'intégrale des pièces"
topics = @("littérature", "théâtre", "Shakespeare")
}
)

# Add each notebook
foreach ($notebook in $notebooks) {
Write-Host "Adding notebook: $($notebook.name)..." -ForegroundColor Cyan

$body = $notebook | ConvertTo-Json

try {
$result = Invoke-RestMethod `
-Uri "$baseUrl/notebooks" `
-Method Post `
-Body $body `
-ContentType "application/json"

Write-Host "✅ Added: $($result.data.notebook.id)" -ForegroundColor Green
}
catch {
Write-Host "❌ Error: $_" -ForegroundColor Red
}
}

# List all notebooks
Write-Host "`nNotebooks in library:" -ForegroundColor Cyan
$list = Invoke-RestMethod -Uri "$baseUrl/notebooks"
$list.data.notebooks | Format-Table id, name, use_count, active

n8n Script: Workflow with Notebook Selection

{
"nodes": [
{
"name": "Select Notebook",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "PUT",
"url": "http://localhost:3000/notebooks/{{$json[\"notebook_id\"]}}/activate"
}
},
{
"name": "Ask Question",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "POST",
"url": "http://localhost:3000/ask",
"jsonParameters": true,
"bodyParametersJson": {
"question": "{{$json[\"question\"]}}"
}
}
}
]
}

Complete library guide!

For more information, see: