Managing the Notebook Library

April 18, 2026 · View on GitHub

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: