
Notebooklm Management
- 13 installs
- 7 repo stars
- Updated August 2, 2026
- practicalswan/agent-skills
notebooklm-management is a Claude Code skill for productivity & planning.
About
notebooklm-management is a Claude Code skill for productivity & planning. It helps solo builders move faster with AI-assisted development.
- notebooklm-management
- Productivity & Planning
- AI-coding skill
Notebooklm Management by the numbers
- 13 all-time installs (skills.sh)
- Ranked #2,148 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/practicalswan/agent-skills --skill notebooklm-managementAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 13 |
|---|---|
| repo stars | ★ 7 |
| Last updated | August 2, 2026 |
| Repository | practicalswan/agent-skills ↗ |
How do I helps with productivity & planning tasks.?
Helps with productivity & planning tasks.
Who is it for?
Best when you're working on productivity & planning and need structured help with notebooklm management.
Skip if: Teams with no productivity & planning needs, or anyone wanting a generic chat assistant without this specific workflow.
When should I use this skill?
When you need to helps with productivity & planning tasks., or when notebooklm-management is a claude code skill for productivity & planning.
What you get
Structured output aligned to notebooklm-management: notebooklm-management, Productivity & Planning.
Files
NotebookLM MCP Management
Tech Stack Target / Version: NotebookLM current web release, Markdown session capture, and URL-tracked research workflows.
Use this skill when research should be grounded in NotebookLM notebooks instead of a generic web search.
- Leverage native parallel subagent dispatch and 200k+ context windows where available.
Current MCP Reality
This repository already targets a real NotebookLM MCP workflow. The concrete tool surface available in this environment includes:
get_healthlist_notebooks,search_notebooks,select_notebookask_questionadd_notebook,update_notebook,remove_notebooklist_sessions,reset_session,close_sessionsetup_auth,re_auth,cleanup_data
Activation Conditions
Use symptom -> action triggers: when one matches, apply this skill and verify with the protocol below.
- Querying a specific NotebookLM notebook
- Adding a notebook from a share URL
- Managing a notebook library or switching active notebooks
- Recovering authentication or cleaning NotebookLM state
- Continuing a multi-turn research session
Recommended Workflow
1. Call get_health first to confirm authentication and server readiness. 2. Reuse an existing session when the task is the same. 3. Prefer search_notebooks or list_notebooks before asking the user to restate what is already in the library. 4. Use ask_question iteratively in the same session for deep work. 5. Use setup_auth or re_auth only when health indicates auth problems.
Library Management Rules
- Do not add or remove notebooks without explicit user confirmation.
- When adding a notebook, collect URL, description, topics, and use cases first.
- Update metadata instead of creating duplicates when the notebook already exists.
Troubleshooting
- Auth broken:
get_health->re_auth - Stale browser state:
cleanup_data(preserve_library=true)after closing browsers - Wrong context:
reset_sessionor switch notebooks - Ambiguous notebook choice: search the library before creating a new one
Anti-Patterns
- Treating source content as already clean: Formatting automation will happily preserve broken or inconsistent input.
- Skipping an open-file verification pass: Documents and spreadsheets often fail in the destination app, not in the script output.
- Automating irreversible edits without checkpoints: A small mapping mistake can affect an entire workbook or document.
Verification Protocol
Before claiming "skill applied successfully":
1. Pass/fail: The Notebooklm Management workflow names the agent boundary, delegated scope, and expected return artifact. 2. Pass/fail: Context passed to helpers is minimal, task-local, and free of hidden expected answers. 3. Pass/fail: Results are integrated only after evidence, diffs, or citations are checked by the controller. 4. Pressure-test scenario: Run the workflow on two similar tasks that must not share assumptions or leaked context. 5. Success metric: Zero context leakage; every delegated output is independently reviewable.
References & Resources
Documentation
- MCP Tool Reference - Current NotebookLM MCP operations and parameters
- Troubleshooting Guide - Auth recovery, cleanup, and session issues
- Workflows - Library, query, and maintenance workflows
Scripts
- NotebookLM Helper - Local helper for library exports and reporting when MCP access is unavailable
- Scripts README - Quick commands for the helper script
Examples
- simple-query.py - Basic query pattern
- multi-turn-conversation.py - Session reuse pattern
- library-management.py - Library search and organization
<!-- PORTABILITY:START -->
Cross-Client Portability
This skill is written to stay usable across GitHub Copilot, Claude Code, Codex, and Gemini CLI.
- GitHub Copilot: keep the folder in a Copilot-visible skill or plugin path, or wrap the workflow as project instructions if the host does not support portable skill folders directly.
- Claude Code: keep the folder in a local skills directory or a compatible plugin or marketplace source.
- Codex: install or sync the folder into
$CODEX_HOME/skills/<skill-name>and restart Codex after major changes. - Gemini CLI: this repository generates a project command named
/skills:notebooklm-managementfrom this skill. Rebuild commands withpython scripts/export-gemini-skill.py notebooklm-managementand then run/commands reloadinside Gemini CLI.
<!-- PORTABILITY:END -->
<!-- MCP:START -->
MCP Availability And Fallback
Preferred MCP Server: NotebookLM MCP
- Fallback prompt: "Use the NotebookLM MCP Management skill without MCP. Rely on the local
SKILL.md, bundled references or scripts, and manual verification. Show the exact commands, evidence, and final checks you used before concluding." - Use the NotebookLM web UI directly, capture answers in Markdown, and store session notes locally when the MCP server is unavailable.
- Preserve notebook URLs, prompt history, and manual research notes so the workflow remains reproducible.
<!-- MCP:END -->
Related Skills
- documentation-authoring: Use it when the workflow also needs drafting structured technical or product documents.
- notion-docs: Use it when the workflow also needs Notion page and database publishing workflows.
- pdf: Use it when the workflow also needs PDF extraction, generation, and layout-aware review.
- word-document: Use it when the workflow also needs Word document authoring and formatting workflows.
Changelog
[2026-04-25] - Version 1.2 Verification Protocol Refresh
Added
- Added a
Verification Protocolsection with skill-specific pass/fail checks, one pressure-test scenario, and a measurable success metric. - Added guidance to leverage native parallel subagent dispatch and 200k+ context windows where available.
Changed
- Updated
SKILL.mdfrontmatter toversion: "1.2"andlast_updated: 2026-04-25. - Reframed activation guidance toward symptom -> action triggers and standardized two-stage review wording where applicable.
[2026-04-24] - Version 1.1 Refresh
Changed
- Updated the SKILL frontmatter version to
1.1for the 2026-04-24 catalog refresh.
All notable changes to this skill will be documented in this file.
[2026-04-24] - Skill Refresh
Changed
- Standardized the SKILL frontmatter with version metadata, last-updated date, tags, and a concise catalog description.
- Reformatted the portability and MCP guidance with a preferred server line, a copy-paste fallback prompt, and consistent bullet lists.
- Added a catalog-standard Anti-Patterns section and refreshed the Related Skills links at the end of the skill.
- Added a Tech Stack Target / Version note so NotebookLM workflows are anchored to the current web tooling surface.
[2026-04-04] - Cross-Client Portability Refresh
Changed
- Added a standard portability note covering GitHub Copilot, Claude Code, Codex, and Gemini CLI.
- Documented the preferred MCP server surface for this skill and a local no-MCP fallback workflow.
Tested
- Validated
SKILL.mdfrontmatter, portability sections, and Gemini export readiness withpython scripts/validate-skills.py.
[2026-03-09] - Workspace Modernization
Changed
- Rewrote the skill around the real NotebookLM MCP tool surface available in this environment
Added
scripts/README.mddocumenting local helper usage when MCP access is unavailable
[2026-02-28] — Description Rewrite & Cross-References
Changed
- Rewrote skill description to ~200 characters with clear, specific activation keywords
- Improved keyword specificity to reduce overlap with related skills
Added
## Related Skillscross-reference table with 2-4 related skills and "Use When" guidance
"""
Example: Adding a New Notebook to Library
This example shows how to add a notebook from a Google share link
with proper metadata.
"""
# Example 1: Add documentation notebook
add_notebook(
url="https://notebooklm.google/share/example-docs",
name="Product Documentation",
description="Complete API documentation and usage examples",
topics=["API", "Documentation", "Reference"],
content_types=["documentation", "examples"],
use_cases=["API integration", "Troubleshooting", "Feature lookup"],
tags=["official", "v2.0"]
)
# Example 2: Add research notebook
add_notebook(
url="https://notebooklm.google/share/research-notes",
name="ML Research Papers",
description="Collection of key machine learning papers and summaries",
topics=["Machine Learning", "Research", "Papers"],
use_cases=["Literature review", "Model selection", "State-of-art"],
tags=["academic", "research", "ml"]
)
# Example 3: Add tutorial notebook
add_notebook(
url="https://notebooklm.google/share/tutorial-guide",
name="React Tutorial Series",
description="Step-by-step React development tutorials from beginner to advanced",
topics=["React", "JavaScript", "Frontend"],
content_types=["tutorials", "examples"],
use_cases=["Learning React", "Best practices", "Quick reference"],
tags=["tutorial", "react", "javascript"]
)
"""
Example: Ad-Hoc Notebook Queries
This example demonstrates querying notebooks without adding
them to your library using notebook_url parameter.
"""
# Example 1: Query a shared notebook directly
# Useful for one-time queries without adding to library
response = ask_question(
question="What are the main architecture principles discussed?",
notebook_url="https://notebooklm.google/share/some-shared-notebook"
)
# Example 2: Compare two notebooks
# Query notebook 1
response1 = ask_question(
question="What is the approach to error handling?",
notebook_url="https://notebooklm.google/share/notebook-1"
)
# Query notebook 2
response2 = ask_question(
question="What is the approach to error handling?",
notebook_url="https://notebooklm.google/share/notebook-2"
)
# Compare results and provide analysis
# Example 3: Quick question about public resource
def quick_fact_check(question, notebook_url):
"""
Quickly check a fact or get information from a public notebook
without adding it to your library.
Useful for:
- One-time lookups
- Evaluating if notebook is worth adding
- Quick fact verification
"""
response = ask_question(
question=question,
notebook_url=notebook_url
)
return response
# Usage: Check if a notebook is relevant
test_response = quick_fact_check(
question="Does this notebook cover Node.js development?",
notebook_url="https://notebooklm.google/share/some-public-docs"
)
# If relevant, then add to library
if "Node.js" in test_response.answer:
add_notebook(
url="https://notebooklm.google/share/some-public-docs",
name="Node.js Development Guide",
description="Complete Node.js development documentation",
topics=["Node.js", "Backend", "JavaScript"]
)
# Example 4: Evaluate notebook before adding
def evaluate_notebook(notebook_url):
"""
Ask multiple questions to evaluate if a notebook is worth
adding to your library.
"""
questions = [
"What topics does this notebook cover?",
"What is the target audience?",
"What level of detail is provided?",
"What are the main use cases?"
]
evaluation = {}
for q in questions:
response = ask_question(question=q, notebook_url=notebook_url)
evaluation[q] = response.answer
return evaluation
# Evaluate before adding
evaluation_result = evaluate_notebook(
"https://notebooklm.google/share/candidate-notebook"
)
# Review and decide based on evaluation
"""
Example: Notebook Library Management
This example shows common library management operations.
"""
# Example 1: List all notebooks
notebooks = list_notebooks()
for notebook in notebooks:
print(f"{notebook.name}")
print(f" Topics: {', '.join(notebook.topics)}")
print(f" Description: {notebook.description}")
print()
# Example 2: Search for specific notebooks
# Find all React-related notebooks
react_notebooks = search_notebooks(query="react")
# Find notebooks about authentication
auth_notebooks = search_notebooks(query="authentication")
# Find notebooks with specific content type
tutorial_notebooks = search_notebooks(query="tutorial")
# Example 3: Update notebook metadata
# Rename a notebook
update_notebook(
id="notebook-old-id",
name="Updated: React Best Practices"
)
# Add more topics to a notebook
update_notebook(
id="notebook-xyz",
topics=["React", "Hooks", "Performance", "Optimization"]
)
# Update description and use cases
update_notebook(
id="notebook-abc",
description="Comprehensive guide to React hooks with real-world examples",
use_cases=["Learning hooks", "Optimizing performance", "Best practices"],
tags=["react", "hooks", "tutorial"]
)
# Example 4: Organize library workflow
def organize_library():
"""Find and update outdated notebook metadata"""
# List all notebooks
notebooks = list_notebooks()
for notebook in notebooks:
# Check for outdated descriptions (example logic)
if "FIXME" in notebook.description or len(notebook.description) < 20:
print(f"Needs update: {notebook.name}")
# You would update with new metadata here
# update_notebook(...)
# Search for duplicates or similar notebooks
docs_results = search_notebooks(query="documentation")
print(f"Found {len(docs_results)} documentation notebooks")
# Example 5: Library audit
def audit_library():
"""Audit notebook library for quality"""
notebooks = list_notebooks()
missing_topics = []
short_descriptions = []
incomplete_metadata = []
for nb in notebooks:
if not nb.topics or len(nb.topics) < 2:
missing_topics.append(nb.id)
if len(nb.description) < 30:
short_descriptions.append(nb.id)
if not nb.use_cases:
incomplete_metadata.append(nb.id)
print(f"Notebooks missing topics: {len(missing_topics)}")
print(f"Notebooks with short descriptions: {len(short_descriptions)}")
print(f"Notebooks with incomplete metadata: {len(incomplete_metadata)}")
return {
"missing_topics": missing_topics,
"short_descriptions": short_descriptions,
"incomplete_metadata": incomplete_metadata
}
"""
Example: Multi-Turn Conversation with NotebookLM
This example demonstrates how to maintain conversation context
across multiple queries using session_id.
"""
import uuid
# Start a new conversation about a topic
def explore_topic(notebook_id, topic):
"""Explore a topic through iterative questioning"""
# Initial question
response1 = ask_question(
question=f"What is {topic}?",
notebook_id=notebook_id
)
session_id = response1.session_id
print(f"Session ID: {session_id}")
# Drill down based on response
response2 = ask_question(
question="What are the key components?",
notebook_id=notebook_id,
session_id=session_id
)
# Explore relationships
response3 = ask_question(
question="How do these components work together?",
notebook_id=notebook_id,
session_id=session_id
)
# Ask about use cases
response4 = ask_question(
question="What are common use cases?",
notebook_id=notebook_id,
session_id=session_id
)
return session_id
# Example usage for exploring React concept
react_session = explore_topic(
notebook_id="react-docs-123",
topic="React Context API"
)
# Example usage for troubleshooting
def troubleshoot_issue(notebook_id, issue):
"""Troubleshoot an issue through iterative questioning"""
response1 = ask_question(
question=f"I'm experiencing: {issue}. What could be the causes?",
notebook_id=notebook_id
)
session_id = response1.session_id
response2 = ask_question(
question="How do I diagnose which cause it is?",
notebook_id=notebook_id,
session_id=session_id
)
response3 = ask_question(
question="What are the solutions for each cause?",
notebook_id=notebook_id,
session_id=session_id
)
return session_id
# Example: Troubleshoot API rate limit
troubleshoot_session = troubleshoot_issue(
notebook_id="api-docs-456",
issue="Getting rate limit errors on API calls"
)
"""
Example: Simple Query to NotebookLM
This example demonstrates how to query a specific notebook
with a straightforward question.
"""
# Example 1: Query a specific notebook by ID
result = ask_question(
question="What are the main features of the product?",
notebook_id="notebook-abc-123"
)
# Example 2: Query without notebook ID (uses active session)
result = ask_question(
question="Explain the authentication flow"
)
# Example 3: Query with follow-up using session_id
# First query
initial_response = ask_question(
question="What are the API endpoints?",
notebook_id="notebook-abc-123"
)
session_id = initial_response.session_id
# Follow-up query in same conversation
follow_up = ask_question(
question="How do I authenticate to these endpoints?",
notebook_id="notebook-abc-123",
session_id=session_id
)
MIT License
Copyright (c) 2026 Sithu Win San
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
NotebookLM MCP Tool Reference
Complete reference for all NotebookLM MCP server tools.
add_notebook
Adds a notebook to your library from a Google share link.
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
url | string | NotebookLM share URL | https://notebooklm.google/share/xyz |
name | string | Display name for notebook | React Documentation |
description | string | What knowledge/content is in this notebook | Complete API docs and examples |
topics | array | Topics covered (3-5 recommended) | ["React", "API", "Frontend"] |
Optional Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
content_types | array | Types of content | ["documentation", "examples"] |
use_cases | array | When to consult this notebook | ["API integration", "Debugging"] |
tags | array | Organizational tags | ["official", "v2.0", "core"] |
Best Practices for Metadata
Names:
- Descriptive and specific
- Use version numbers if applicable
- Example: "React Documentation` or "n8n v2.0"
Descriptions:
- 1-2 sentences max
- Focus on content purpose
- Example: "Complete API documentation with examples and troubleshooting guides"
Topics:
- 3-5 topics optimal
- Use searchable keywords
- Include both broad and specific terms
- Example:
["React", "Hooks", "State Management", "Performance"]
Use Cases:
- Describe when this notebook is helpful
- Be specific and actionable
- Example:
["Learning React hooks", "Solving state issues", "Performance optimization"]
Usage Example
add_notebook(
url="https://notebooklm.google/share/abc123",
name="React Hooks Guide",
description="Complete guide to React hooks with examples",
topics=["React", "Hooks", "State Management"],
content_types=["documentation", "examples"],
use_cases=["Learning hooks", "Troubleshooting", "Best practices"],
tags=["react", "hooks", "tutorial"]
)ask_question
Query NotebookLM with a natural language question.
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
question | string | Natural language question | How do I use useEffect? |
Optional Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
notebook_id | string | Specific notebook to query | notebook-abc-123 |
notebook_url | string | Ad-hoc query URL (overrides notebook_id) | https://notebooklm.google/share/xyz |
session_id | string | Continue existing conversation | session-xyz-789 |
show_browser | boolean | Display browser for debugging | true |
browser_options | object | Advanced browser control | See below |
Browser Options
| Option | Type | Description | Default |
|---|---|---|---|
headless | boolean | Run browser in headless mode | false |
timeout | integer | Timeout in milliseconds | 30000 |
viewport_width | integer | Browser viewport width | 1280 |
viewport_height | integer | Browser viewport height | 720 |
Query Strategy
Good Questions:
- Specific: "How do I handle state cleanup in useEffect?"
- Contextual: "What are the best practices for error handling?"
- Focused: "Compare React Context vs Redux"
Poor Questions:
- Too vague: "Tell me about React"
- Multiple topics: "How do I use React, Vue, and Angular together?"
- No context: "Fix my code"
Response Format
{
"answer": "The main features are...",
"sources": ["Source 1", "Source 2"],
"session_id": "session-abc-123",
"confidence": 0.95
}Usage Examples
Simple Query:
response = ask_question(
question="What are the core benefits of using hooks?",
notebook_id="react-hooks-123"
)Multi-Turn Conversation:
# First query
r1 = ask_question(
question="What is React Context?",
notebook_id="react-docs-123"
)
session_id = r1.session_id
# Follow-up
r2 = ask_question(
question="How does it differ from Redux?",
notebook_id="react-docs-123",
session_id=session_id
)Ad-Hoc Query:
response = ask_question(
question="Summarize the key concepts",
notebook_url="https://notebooklm.google/share/public-notebook"
)list_notebooks
Shows all library notebooks with metadata.
Parameters
None required.
Response Format
[
{
"id": "notebook-abc-123",
"name": "React Documentation",
"description": "Complete API documentation",
"topics": ["React", "API", "Frontend"],
"url": "https://notebooklm.google/share/abc",
"created_at": "2026-02-16T10:00:00Z"
}
]Usage Example
notebooks = list_notebooks()
for notebook in notebooks:
print(f"{notebook.name}")
print(f" Topics: {notebook.topics}")
print(f" Description: {notebook.description}")search_notebooks
Search library by query (name, description, topics, tags).
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
query | string | Search term | "react" |
Search Strategy
Queries search across:
- Notebook names
- Descriptions
- Topics
- Tags
Good Search Queries:
- Specific technology:
"react" - Concept:
"authentication" - Content type:
"tutorial" - Combined:
"react hooks"
Response Format
Same as list_notebooks but filtered results.
Usage Examples
# Find React notebooks
react_notebooks = search_notebooks(query="react")
# Find authentication docs
auth_docs = search_notebooks(query="authentication")
# Find tutorials
tutorials = search_notebooks(query="tutorial")update_notebook
Update notebook metadata.
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
id | string | Notebook ID to update | notebook-abc-123 |
Optional Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
name | string | New name | Updated React Docs |
description | string | New description | Enhanced documentation |
topics | array | Updated topics | ["React", "Hooks"] |
content_types | array | Updated content types | ["docs", "examples"] |
use_cases | array | Updated use cases | ["Learning", "Debugging"] |
tags | array | Updated tags | ["official", "v2.5"] |
url | string | Updated URL | New share link |
When to Update
- Add new topics discovered
- Update description to be more accurate
- Add use cases based on experience
- Update version in tags
- Fix typos or clarify names
Usage Example
update_notebook(
id="react-docs-123",
name="React Hooks Deep Dive",
description="Comprehensive guide to React hooks",
topics=["React", "Hooks", "Performance", "Best Practices"],
use_cases=["Learning hooks", "Optimizing performance", "Solving issues"],
tags=["react", "hooks", "tutorial", "advanced"]
)reset_session
Reset session chat history (keeps same session ID).
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
session_id | string | Session to reset | session-xyz-789 |
When to Reset
- Starting a completely new topic
- Session context is confusing
- Want fresh conversation context
- Too much history in session
What Reset Does
- Clears chat history
- Keeps same session_id
- Maintains notebook context
- Allows new conversation flow
Usage Example
# After many questions on topic A
# Reset before moving to topic B
reset_session(session_id="session-abc-123")
# Now ask questions about topic B in same notebook
new_response = ask_question(
question="Tell me about component lifecycle",
notebook_id="react-docs-123",
session_id="session-abc-123"
)Tool Selection Guide
| Task | Tool | Key Parameters |
|---|---|---|
| Add new notebook | add_notebook | url, name, description, topics |
| Ask a question | ask_question | question, optional notebook_id or notebook_url |
| Continue conversation | ask_question | question, notebook_id, session_id |
| Browse library | list_notebooks | None |
| Find specific notebook | search_notebooks | query |
| Update metadata | update_notebook | id, fields to update |
| Fresh conversation | reset_session | session_id |
Error Handling
Common Errors
| Error | Cause | Solution |
|---|---|---|
| Authentication required | Not logged in | Run authentication flow |
| Notebook not found | Invalid notebook_id | Verify ID exists in library |
| Session expired | Old session_id | Use reset_session or create new |
| Rate limit exceeded | Too many queries | Wait or upgrade account |
| Invalid URL | Bad notebook share link | Verify share URL is valid |
Best Practices
1. Always check authentication before operations 2. Store session_ids for multi-turn conversations 3. Handle rate limits gracefully 4. Validate notebook IDs before queries 5. Use descriptive metadata from the start
NotebookLM Troubleshooting Guide
Complete guide for diagnosing and resolving common NotebookLM MCP issues.
Authentication Issues
Problem: "Authentication Required" or "Login Required"
Symptoms:
- Error messages about requiring login
- unable to access notebooks
- Queries fail with auth errors
Diagnosis Steps: 1. Check if this is first-time use → see Initial Setup 2. Check if session recently expired → see Session Recovery 3. Check if Google account changed → see Account Switch
Initial Setup
First time using NotebookLM MCP:
# Run authentication setup
notebooklm.auth-setup()
# This will:
# 1. Open browser for OAuth flow
# 2. Request Google account login
# 3. Request NotebookLM permissions
# 4. Save session credentials locally
# After setup, verify with health check
get_health()Expected Behavior:
- Browser opens to Google login
- Request for NotebookLM access permissions
- Session saved automatically
- Health check returns success
If Still Fails: 1. Check browser is allowing popups 2. Verify Google account has NotebookLM access 3. Check network connectivity 4. Try incognito/private browser mode
Session Recovery
Previously authenticated but now getting auth errors:
# Clear old session data
notebooklm.auth-repair()
# Re-authenticate
notebooklm.auth-setup()
# Verify
get_health()When to Use:
- Seeing authentication required for first time in a while
- Just upgraded MCP server version
- Changed Google account
- Session corrupted
Account Switch
Using different Google account than initial setup:
# Clear existing session
notebooklm.auth-repair()
# Start fresh
notebooklm.auth-setup()
# Login with desired accountProblem: Authentication Stuck in Browser
Symptoms:
- OAuth window opens but doesn't complete
- Infinite loading during authentication
- Window closes without success
Solutions:
# Clear all session data and retry
notebooklm.auth-repair()
notebooklm.auth-setup()
# If still stuck, check:
# 1. Browser extensions blocking OAuth
# 2. Pop-up blocker enabled
# 3. Network/firewall issues
# 4. Google service outageBrowser-Specific Fixes:
Chrome: 1. Disable ad blockers temporarily 2. Check chrome://settings/cookies for blocked cookies 3. Try in incognito mode
Firefox: 1. Check privacy settings 2. Allow cookies for accounts.google.com 3. Try in private window
Query Issues
Problem: Query Returns Wrong Information
Symptoms:
- Answer doesn't match question
- Information from different notebook
- Completely unrelated response
Diagnosis:
# 1. Verify you're querying correct notebook
notebooks = list_notebooks()
print([nb.name for nb in notebooks])
# 2. Check if using the right notebook_id
response = ask_question(
question="test query",
notebook_id="your-notebook-id"
)
# 3. If using session_id, check if context is preserved
# Old session_id might have wrong contextSolutions:
# Solution 1: Explicitly specify notebook_id
response = ask_question(
question="Your specific question",
notebook_id="correct-notebook-id"
)
# Solution 2: Reset session if context confused
reset_session(session_id="old-session-id")
# Solution 3: Start new conversation without session_id
response = ask_question(
question="Your specific question",
notebook_id="correct-notebook-id"
# No session_id = new context
)Problem: Query Timeout or Slow Response
Symptoms:
- Query takes 30+ seconds
- Response never comes
- Timeout errors
Diagnosis:
# Try with browser visibility to debug
response = ask_question(
question="test query",
notebook_id="your-notebook-id",
show_browser=True
)Solutions:
# Solution 1: Optimize query
# Too broad → narrow down
response = ask_question(
question="Specific focused question", # Better than "tell me about X"
notebook_id="your-notebook-id"
)
# Solution 2: Increase timeout via browser_options
response =ask_question(
question="Your question",
notebook_id="your-notebook-id",
browser_options={
"timeout": 60000 # 60 seconds
}
)
# Solution 3: Break into smaller queries
# Instead of one complex question, ask multiple simple onesProblem: Query Returns Empty or Minimal Response
Symptoms:
- Response is very short
- "I don't know" type answers
- No sources cited
Diagnosis:
# 1. Check if notebook has relevant content
list_notebooks() # Verify notebook exists
# 2. Test with simple question
response = ask_question(
question="What topics are covered?",
notebook_id="your-notebook-id"
)
# 3. Check if notebook was properly added
# Verify it's not empty or corruptedSolutions:
# Solution 1: Re-add notebook if corrupted
add_notebook(
url="original-share-url",
name="Notebook Name",
description="Description",
topics=["Topic 1", "Topic 2"]
)
# Solution 2: Reformulate question
# Be more specific
response = ask_question(
question="Specific question about specific topic",
notebook_id="your-notebook-id"
)
# Solution 3: Query different notebook
search_notebooks(query="relevant-topic")Notebook Management Issues
Problem: Notebook Not Found in Library
Symptoms:
list_notebooks()doesn't show expected notebook- Search returns no results
- Query fails with "notebook not found"
Diagnosis:
# Check all notebooks
all_notebooks = list_notebooks()
for nb in all_notebooks:
print(f"{nb.id}: {nb.name}")
# Search by partial name
results = search_notebooks(query="partial-name")Solutions:
# Solution 1: Re-add notebook
add_notebook(
url="share-url",
name="Notebook Name",
description="Description",
topics=["Topic"]
)
# Solution 2: Check different terms in search
search_notebooks(query="different-keyword")
search_notebooks(query="tag-name")
# Solution 3: Verify notebook ID from previous interactions
# If you have session_id, check contextProblem: Can't Update Notebook Metadata
Symptoms:
update_notebook()fails- Changes not reflected
- Invalid field errors
Diagnosis:
# Verify notebook exists and get correct ID
notebooks = list_notebooks()
for nb in notebooks:
if nb.name == "Target Name":
correct_id = nb.id
print(f"Correct ID: {correct_id}")Solutions:
# Solution 1: Use correct notebook_id
update_notebook(
id="correct-id-from-list", # Must match exactly
name="New Name"
)
# Solution 2: Update one field at a time
update_notebook(
id="notebook-id",
name="New Name" # Just name
)
update_notebook(
id="notebook-id",
description="New Description" # Then description
)
# Solution 3: Check for valid enum values
# content_types, tags should be strings
# topics should be list of stringsSession Management Issues
Problem: Session Context Confusing or Incorrect
Symptoms:
- Follow-up questions don't make sense
- Context from previous queries affects new ones
- Contradictory answers
Diagnosis:
# Check if using old session_id
# Old sessions maintain context from previous questionsSolutions:
# Solution 1: Reset session for fresh context
reset_session(session_id="old-session-id")
# Now start fresh context in same notebook
response = ask_question(
question="Completely different topic",
notebook_id="notebook-id",
session_id="reset-session-id" # Same ID, fresh context
)
# Solution 2: Start completely new session
# Don't provide session_id at all
response = ask_question(
question="New topic",
notebook_id="notebook-id"
# No session_id = automatically new
)Problem: Lost Session ID
Symptoms:
- Can't continue multi-turn conversation
- Don't have session_id from previous query
Solutions:
# Solution 1: Start fresh conversation
response = ask_question(
question="Your question",
notebook_id="notebook-id"
# New session_id will be in response
)
new_session_id = response.session_id
# Solution 2: Re-ask initial question
# If you remember what the first question was
response = ask_question(
question="Initial question from before",
notebook_id="notebook-id"
)
# Get session_id and continue
# Solution 3: Check if session_id is needed
# For simple one-off questions, don't use session_id
response = ask_question(
question="Independent question",
notebook_id="notebook-id"
)Rate Limit Issues
Problem: "Too Many Queries" or Rate Limit Errors
Symptoms:
- Rate limit error messages
- Queries suddenly start failing
- Error after many successful queries
Diagnosis:
# Check NotebookLM account tier
# Free tier: 50 daily queries
# Paid tiers: Higher limits
# Monitor query count
# Keep track of how many queries you've madeSolutions:
# Solution 1: Wait for cooldown
# Free tier resets daily
# Wait until next day for more queries
# Solution 2: Upgrade account tier
# Visit NotebookLM to upgrade for higher limits
# Solution 3: Optimize query strategy
# Batch related questions in multi-turn conversations
# Instead of 10 separate queries, use 1 with follow-ups
response1 = ask_question(
question="Overview of topic",
notebook_id="notebook-id"
)
session_id = response1.session_id
# Follow-ups count differently or use less quota
response2 = ask_question(
question="Detail point A",
notebook_id="notebook-id",
session_id=session_id
)Problem: Frequent Rate Limiting
Symptoms:
- Always hitting limits
- Can't work efficiently
Long-Term Solutions:
# Solution 1: Cache results locally
# Store common answers to avoid re-querying
cache = {}
def cached_query(question, notebook_id):
key = f"{notebook_id}:{question}"
if key in cache:
return cache[key]
response = ask_question(question=question, notebook_id=notebook_id)
cache[key] = response
return response
# Solution 2: Use notebooks with comprehensive content
# Better notebooks = fewer queries needed
# Add comprehensive documentation notebooks instead of many small ones
# Solution 3: Batch questions intelligently
# Use multi-turn conversations for related topicsNetwork and Connectivity Issues
Problem: Connection Errors
Symptoms:
- Network timeout errors
- Connection refused
- Unable to reach NotebookLM
Diagnosis:
# Check network connectivity
# Can you reach other MCP servers?
# Test in browser: notebooklm.googleSolutions:
# Solution 1: Check internet connection
# Verify you can access notebooklm.google in browser
# Solution 2: Check firewall/proxy settings
# Ensure NotebookLM domains not blocked
# Solution 3: Try with browser to debug
response = ask_question(
question="test",
notebook_id="notebook-id",
show_browser=True,
browser_options={
"timeout": 60000
}
)Getting Help
When to Seek Additional Help
- Issues persist after trying all solutions
- Error messages not covered in this guide
- Unexpected behavior not documented
Information to Gather
Before seeking help, collect:
# 1. MCP server version
# From MCP server configuration
# 2. Error messages (exact text)
# Copy full error stack trace
# 3. Steps to reproduce
# What you did, in what order
# 4. Expected vs actual behavior
# What you expected to happen vs what did
# 5. Environment info
# OS, browser, Node.js version (if applicable)Where to Get Help
NotebookLM Detailed Workflows
Comprehensive step-by-step workflows for all NotebookLM operations.
Workflow 1: Adding a New Notebook
Complete process for adding a notebook from a share link to your library.
Phase 1: Information Gathering
Step 1.1: Acquire the NotebookLM Share URL
# Ask user for the share link
user_url = input("Enter NotebookLM share URL: ")
# Example: https://notebooklm.google/share/abc123def456Step 1.2: Gather Notebook Content Information
# Ask: What knowledge is inside this notebook?
description = input("What content/knowledge is in this notebook? (1-2 sentences): ")
# Example: "Complete API documentation for React hooks with examples and best practices"Step 1.3: Identify Topics
# Ask: Which topics does it cover?
topics_input = input("List 3-5 topics covered (comma-separated): ")
# Example: "React, Hooks, State Management, Performance, Documentation"
topics = [t.strip() for t in topics_input.split(",")]Step 1.4: Define Use Cases
# Ask: When should we consult this notebook?
use_cases_input = input("List use cases (comma-separated): ")
# Example: "Learning hooks, Troubleshooting state issues, Performance optimization"
use_cases = [uc.strip() for uc in use_cases_input.split(",")]Step 1.5: Capture Additional Metadata (Optional)
# Ask for content types if relevant
content_types_input = input("Content types (documentation, tutorial, examples, etc.): ") or None
# Example: ["documentation", "examples"]
# Ask for tags for organization
tags_input = input("Organizational tags (optional, comma-separated): ") or None
# Example: ["official", "v2.0", "core"]Phase 2: Propose and Confirm
Step 2.1: Generate Metadata Summary
summary = f"""
Notebook Addition Summary:
URL: {user_url}
Name: [Proposed Name]
Description: {description}
Topics: {', '.join(topics)}
Use Cases: {', '.join(use_cases)}
"""
print(summary)Step 2.2: Propose Name Based on Topics
# Suggest a concise, descriptive name
primary_topic = topics[0]
suggested_name = f"{primary_topic} Documentation"
# Or combine top 2 topics
suggested_name = f"{topics[0]} {topics[1]} Guide"
print(f"Suggested name: {suggested_name}")Step 2.3: Confirm with User
confirmation = input("Add this notebook to your library? (yes/no): ").lower()
if confirmation == "yes":
add_notebook(
url=user_url,
name=suggested_name,
description=description,
topics=topics,
content_types=content_types,
use_cases=use_cases,
tags=tags
)
print("Notebook added successfully!")
else:
print("Notebook not added.")Full Example
def add_notebook_workflow():
"""Complete workflow for adding a notebook"""
print("=== Add New Notebook to Library ===\n")
# Phase 1: Gather information
url = input("Enter NotebookLM share URL: ")
description = input(
"What content/knowledge is in this notebook? (1-2 sentences): "
)
topics_input = input("List 3-5 topics covered (comma-separated): ")
topics = [t.strip() for t in topics_input.split(",")]
use_cases_input = input("List use cases (comma-separated): ")
use_cases = [uc.strip() for uc in use_cases_input.split(",")]
content_types_input = input(
"Content types (optional, comma-separated): "
) or ""
content_types = [ct.strip() for ct in content_types_input.split(",")] if content_types_input else []
tags_input = input("Organizational tags (optional, comma-separated): ") or ""
tags = [t.strip() for t in tags_input.split(",")] if tags_input else []
# Phase 2: Propose and confirm
suggested_name = f"{topics[0]} Documentation"
print(f"\n=== Notebook Summary ===")
print(f"URL: {url}")
print(f"Name: {suggested_name}")
print(f"Description: {description}")
print(f"Topics: {', '.join(topics)}")
print(f"Use Cases: {', '.join(use_cases)}")
if content_types:
print(f"Content Types: {', '.join(content_types)}")
if tags:
print(f"Tags: {', '.join(tags)}")
confirmation = input("\nAdd this notebook to your library? (yes/no): ").lower()
if confirmation == "yes":
add_notebook(
url=url,
name=suggested_name,
description=description,
topics=topics,
content_types=content_types,
use_cases=use_cases,
tags=tags
)
print("\n✓ Notebook added successfully!")
return True
else:
print("\n✗ Notebook not added.")
return FalseWorkflow 2: Querying Notebooks
Complete process for asking questions and getting answers from notebooks.
Phase 1: Notebook Selection
Step 2.1: Check for Active Session
# If continuing a conversation
existing_session_id = check_existing_session()
if existing_session_id:
print(f"Continuing session: {existing_session_id}")
use_session = TrueStep 2.2: Select Notebook if No Active Session
if not use_session:
# List available notebooks
notebooks = list_notebooks()
print("\nAvailable Notebooks:")
for i, nb in enumerate(notebooks, 1):
print(f"{i}. {nb.name}")
print(f" Topics: {', '.join(nb.topics)}")
print(f" Description: {nb.description}\n")
# User selects
selection = input("Enter notebook number: ")
selected_notebook = notebooks[int(selection) - 1]Phase 2: Formulate Question
Step 2.3: Guide User to Ask Good Question
print("\n=== Formulate Your Question ===")
print("Tips for good questions:")
print("• Be specific and focused")
print("• Include context if needed")
print("• Ask about one topic at a time")
print("• Reference notebook content specifically if possible")
question = input("\nEnter your question: ")Step 2.4: Validate Question
# Check if question is too vague
vague_indicators = ["tell me about", "explain", "what is", "give me"]
if any(question.lower().startswith(indicator) for indicator in vague_indicators):
print("\n⚠ Your question might be too general.")
print("Try to be more specific:")
print(f" Instead of: '{question}'")
print(f" Consider: 'How does [specific aspect] work in [context]?'")
refine = input("Refine your question? (yes/no): ").lower()
if refine == "yes":
question = input("Enter refined question: ")Phase 3: Execute Query
Step 2.5: Query with Appropriate Parameters
if use_session:
# Continue existing conversation
response = ask_question(
question=question,
notebook_id=selected_notebook.id,
session_id=existing_session_id
)
else:
# New query
response = ask_question(
question=question,
notebook_id=selected_notebook.id
)
# Save session_id for follow-ups
session_id = response.session_id if response.session_id else NonePhase 4: Present Results
Step 2.6: Display Answer with Context
print(f"\n=== Answer ===")
print(f"{response.answer}")
if hasattr(response, 'sources') and response.sources:
print(f"\n=== Sources ===")
for i, source in enumerate(response.sources, 1):
print(f"{i}. {source}")
if hasattr(response, 'confidence'):
confidence_pct = response.confidence * 100
print(f"\nConfidence: {confidence_pct:.1f}%")Step 2.7: Offer Follow-up Questions
print(f"\n=== Continue Conversation? ===")
print(f"Session ID: {session_id}")
continue_conv = input("Ask another question? (yes/no): ").lower()
if continue_conv == "yes" and session_id:
# Continue in workflow from Phase 2
# with existing session_id
...Full Example
def query_notebook_workflow():
"""Complete workflow for querying a notebook"""
print("=== Query Notebook ===\n")
# Phase 1: Notebook selection
session_id = None
# Check for existing session
existing_id = input("Continue existing session? (yes/no): ").lower()
if existing_id == "yes":
session_id = input("Enter session ID: ")
notebook_id = input("Enter notebook ID: ")
else:
# Select notebook
notebooks = list_notebooks()
print("\nAvailable Notebooks:")
for i, nb in enumerate(notebooks, 1):
print(f"{i}. {nb.name}")
print(f" {', '.join(nb.topics)}")
selection = int(input("\nSelect notebook number: "))
selected_notebook = notebooks[selection - 1]
notebook_id = selected_notebook.id
# Phase 2: Formulate question
print("\nFormulate your question:")
print("• Be specific and focused")
print("• Include context if needed")
question = input("\nYour question: ")
# Phase 3: Execute
response = ask_question(
question=question,
notebook_id=notebook_id,
session_id=session_id
)
if not session_id:
session_id = response.session_id
# Phase 4: Present results
print(f"\n=== Answer ===")
print(f"{response.answer}")
if hasattr(response, 'sources'):
print(f"\n=== Sources ===")
for source in response.sources:
print(f"• {source}")
print(f"\nSession ID: {session_id}")
# Offer follow-up
while True:
continue_query = input("\nAsk another? (yes/no): ").lower()
if continue_query != "yes":
break
question = input("\nYour question: ")
response = ask_question(
question=question,
notebook_id=notebook_id,
session_id=session_id
)
print(f"\n{response.answer}")
return session_idWorkflow 3: Managing Notebook Library
Complete processes for organizing and maintaining notebook library.
Phase 1: Library Audit
Step 3.1: List All Notebooks
notebooks = list_notebooks()
print(f"\n=== Notebook Library Audit ===")
print(f"Total notebooks: {len(notebooks)}\n")
for i, nb in enumerate(notebooks, 1):
print(f"{i}. {nb.name}")
print(f" ID: {nb.id}")
print(f" Topics: {', '.join(nb.topics)}")
print(f" Description: {nb.description}")
if hasattr(nb, 'tags') and nb.tags:
print(f" Tags: {', '.join(nb.tags)}")
if hasattr(nb, 'use_cases') and nb.use_cases:
print(f" Use Cases: {', '.join(nb.use_cases)}")
print()Step 3.2: Identify Issues
issues = {
"short_descriptions": [],
"missing_topics": [],
"no_use_cases": [],
"duplicate_names": {}
}
for nb in notebooks:
# Check description length
if len(nb.description) < 30:
issues["short_descriptions"].append(nb.id)
# Check topic count
if len(nb.topics) < 2:
issues["missing_topics"].append(nb.id)
# Check use cases
if not nb.use_cases or len(nb.use_cases) == 0:
issues["no_use_cases"].append(nb.id)
# Check for duplicates
if nb.name in issues["duplicate_names"]:
issues["duplicate_names"][nb.name].append(nb.id)
else:
issues["duplicate_names"][nb.name] = [nb.id]
# Report issues
print("\n=== Issues Found ===")
for issue_type, affected in issues.items():
if affected:
print(f"\n{issue_type.replace('_', ' ').title()}: {len(affected)}")
for item in affected:
print(f" - {item}")Phase 2: Organization
Step 3.3: Search for Related Notebooks
print("\n=== Search and Group ===")
# Find notebooks by topic
search_query = input("Enter topic to search for: ")
matching_notebooks = search_notebooks(query=search_query)
print(f"\nNotebooks matching '{search_query}':")
for nb in matching_notebooks:
print(f"• {nb.name} ({', '.join(nb.topics)})")Step 3.4: Update Metadata
print("\n=== Update Metadata ===")
notebook_id = input("Enter notebook ID to update: ")
# Get current notebook
notebook = next(nb for nb in notebooks if nb.id == notebook_id)
print(f"\nCurrent Name: {notebook.name}")
print(f"Current Description: {notebook.description}")
print(f"Current Topics: {', '.join(notebook.topics)}")
# Ask what to update
print("\nWhat to update?")
print("1. Name")
print("2. Description")
print("3. Topics")
print("4. All")
choice = input("Enter choice (1-4): ")
if choice == "1":
new_name = input(f"New name for {notebook.name}: ")
update_notebook(id=notebook_id, name=new_name)
elif choice == "2":
new_desc = input(f"New description: ")
update_notebook(id=notebook_id, description=new_desc)
elif choice == "3":
new_topics = input("New topics (comma-separated): ")
topics = [t.strip() for t in new_topics.split(",")]
update_notebook(id=notebook_id, topics=topics)
elif choice == "4":
new_name = input("New name: ")
new_desc = input("New description: ")
new_topics = input("New topics (comma-separated): ")
topics = [t.strip() for t in new_topics.split(",")]
update_notebook(id=notebook_id, name=new_name, description=new_desc, topics=topics)
print("✓ Updated successfully!")Full Example
def manage_library_workflow():
"""Complete library management workflow"""
while True:
print("\n=== Notebook Library Management ===")
print("1. List all notebooks")
print("2. Search notebooks")
print("3. Update metadata")
print("4. Run audit")
print("5. Exit")
choice = input("\nSelect option (1-5): ")
if choice == "1":
notebooks = list_notebooks()
for nb in notebooks:
print(f"\n{nb.name}")
print(f" Topics: {', '.join(nb.topics)}")
print(f" Description: {nb.description}")
elif choice == "2":
query = input("\nSearch term: ")
results = search_notebooks(query=query)
if results:
for nb in results:
print(f"\n{nb.name}")
print(f" {', '.join(nb.topics)}")
else:
print("No matching notebooks found.")
elif choice == "3":
notebooks = list_notebooks()
print("\nSelect notebook:")
for i, nb in enumerate(notebooks, 1):
print(f"{i}. {nb.name}")
selection = int(input("\nEnter number: "))
notebook = notebooks[selection - 1]
field = input(f"\nUpdate field for '{notebook.name}' (name/description/topics): ")
if field == "name":
new_value = input("New name: ")
update_notebook(id=notebook.id, name=new_value)
elif field == "description":
new_value = input("New description: ")
update_notebook(id=notebook.id, description=new_value)
elif field == "topics":
new_value = input("New topics (comma-separated): ")
topics = [t.strip() for t in new_value.split(",")]
update_notebook(id=notebook.id, topics=topics)
print("✓ Updated!")
elif choice == "4":
notebooks = list_notebooks()
issues = 0
for nb in notebooks:
if len(nb.description) < 30:
print(f"⚠ Short description: {nb.name}")
issues += 1
if len(nb.topics) < 2:
print(f"⚠ Few topics: {nb.name}")
issues += 1
if issues == 0:
print("✓ No issues found!")
elif choice == "5":
breakWorkflow 4: Troubleshooting Authentication
Complete process for resolving authentication issues.
Scenario 1: First-Time Setup
def initial_authentication_setup():
"""Complete first-time authentication setup"""
print("=== NotebookLM Authentication Setup ===")
print("This will open a browser window for Google OAuth.")
print("\nRequirements:")
print("• Google account with NotebookLM access")
print("• Browser window permission")
print("• Internet connection\n")
proceed = input("Proceed? (yes/no): ").lower()
if proceed != "yes":
print("Setup cancelled.")
return False
print("\nOpening browser for authentication...")
notebooklm.auth-setup()
print("\n✓ Authentication complete!")
print("\nVerifying health...")
health_status = get_health()
if health_status.get("status") == "authenticated":
print("✓ Successfully authenticated!")
return True
else:
print("✗ Authentication may have failed.")
print("Please run authentication again or check troubleshoot guide.")
return FalseScenario 2: Session Recovery
def recover_expired_session():
"""Recover from expired session"""
print("=== Session Recovery ===")
print("Your session may have expired.")
print("Common causes:")
print("• Long period of inactivity")
print("• MCP server upgrade")
print("• Account changes\n")
action = input("Recover session? (yes/no): ").lower()
if action != "yes":
print("Recovery cancelled.")
return False
print("\nClearing old session data...")
notebooklm.auth-repair()
print("Opening browser for re-authentication...")
notebooklm.auth-setup()
print("\n✓ Session recovered!")
return TrueScenario 3: Account Switch
def switch_google_account():
"""Switch to different Google account"""
print("=== Switch Google Account ===")
print("This will clear your current session.")
print("You'll need to authenticate with the new account.\n")
confirm = input("Switch account? (yes/no): ").lower()
if confirm != "yes":
print("Cancelled.")
return False
print("\nClearing current session...")
notebooklm.auth-repair()
print("Opening browser for new account authentication...")
notebooklm.auth-setup()
print("\n✓ Account switched!")
return TrueWorkflow 5: Multi-Turn Conversations
Advanced workflow for maintaining context across multiple questions.
Complete Conversation Pattern
def multi_turn_conversation(notebook_id):
"""Structured multi-turn conversation"""
print("=== Multi-Turn Conversation ===")
print("Topic exploration mode. Enter 'exit' to finish.\n")
# Initial question
question = input("Starting question: ")
response = ask_question(
question=question,
notebook_id=notebook_id
)
session_id = response.session_id
print(f"\n{response.answer}")
turn_count = 1
while True:
turn_count += 1
print(f"\n--- Turn {turn_count} ---")
# Provide context hints
print(f"Session: {session_id}")
print("Context preserved from previous turns.")
question = input("\nYour follow-up question (or 'exit'): ")
if question.lower() == "exit":
print("\n=== Conversation Summary ===")
print(f"Total turns: {turn_count}")
print(f"Session ID: {session_id}")
break
# Ask follow-up question
response = ask_question(
question=question,
notebook_id=notebook_id,
session_id=session_id
)
print(f"\n{response.answer}")
# Show sources if available
if hasattr(response, 'sources') and response.sources:
print(f"\nSources:")
for source in response.sources:
print(f" • {source}")
return session_idTopic Exploration Pattern
def explore_topic_depth(notebook_id, topic):
"""Explore a topic progressively deeper"""
print(f"\n=== Exploring: {topic} ===\n")
# Level 1: Overview
print("Level 1: Overview")
response = ask_question(
question=f"What is {topic} at a high level?",
notebook_id=notebook_id
)
print(f"{response.answer}\n")
session_id = response.session_id
# Level 2: Components
print("Level 2: Components")
response = ask_question(
question="What are the main components or aspects?",
notebook_id=notebook_id,
session_id=session_id
)
print(f"{response.answer}\n")
# Level 3: Deep dive
print("Level 3: Deep Dive")
component = input("\nWhich component to explore deeper? ")
response = ask_question(
question=f"Tell me more about {component}",
notebook_id=notebook_id,
session_id=session_id
)
print(f"{response.answer}\n")
# Level 4: Use cases
print("Level 4: Practical Application")
response = ask_question(
question="What are practical use cases or applications?",
notebook_id=notebook_id,
session_id=session_id
)
print(f"{response.answer}\n")
return session_id#!/usr/bin/env python3
"""
NotebookLM MCP Helper Script
Utility script for common NotebookLM MCP operations.
Provides helper functions for library management, queries, and maintenance.
"""
import json
import sys
from datetime import datetime
from typing import List, Dict, Optional
class NotebookLMHelper:
"""Helper class for NotebookLM MCP operations"""
def __init__(self):
"""Initialize helper"""
self.cached_notebooks = None
self.cache_timestamp = None
self.cache_ttl = 300 # 5 minutes
def list_notebooks_with_details(self) -> List[Dict]:
"""
List all notebooks with enhanced details.
Returns:
List of notebook dictionaries with full metadata
"""
from mcp import list_notebooks
# Check cache
if (self.cached_notebooks and
self.cache_timestamp and
(datetime.now() - self.cache_timestamp).seconds < self.cache_ttl):
print("Using cached notebook list")
return self.cached_notebooks
notebooks = list_notebooks()
self.cached_notebooks = notebooks
self.cache_timestamp = datetime.now()
return notebooks
def find_notebook_by_name(self, name: str) -> Optional[Dict]:
"""
Find a notebook by exact name match.
Args:
name: Exact notebook name to search for
Returns:
Notebook dictionary or None if not found
"""
notebooks = self.list_notebooks_with_details()
for notebook in notebooks:
if notebook.name.lower() == name.lower():
return notebook
return None
def find_notebooks_by_topic(self, topic: str) -> List[Dict]:
"""
Find all notebooks containing a specific topic.
Args:
topic: Topic to search for
Returns:
List of matching notebooks
"""
notebooks = self.list_notebooks_with_details()
matching = []
topic_lower = topic.lower()
for notebook in notebooks:
if any(t.lower() == topic_lower for t in notebook.topics):
matching.append(notebook)
return matching
def search_notebooks_fuzzy(self, query: str) -> List[Dict]:
"""
Fuzzy search across name, description, and topics.
Args:
query: Search query string
Returns:
List of matching notebooks with match score
"""
from mcp import search_notebooks
# Use MCP search
notebooks = search_notebooks(query=query)
# Score matches based on name, description, topic overlap
scored = []
query_lower = query.lower()
query_parts = query_lower.split()
for notebook in notebooks:
score = 0
# Name match (highest weight)
if query_lower in notebook.name.lower():
score += 50
# Topic matches
topic_matches = sum(
1 for t in notebook.topics
if any(part in t.lower() for part in query_parts)
)
if topic_matches > 0:
score += 30 * topic_matches
# Description matches
desc_matches = sum(
1 for part in query_parts
if part in notebook.description.lower()
)
if desc_matches > 0:
score += 20 * desc_matches
if score > 0:
scored.append({
'notebook': notebook,
'score': score
})
# Sort by score (descending)
scored.sort(key=lambda x: x['score'], reverse=True)
return [item['notebook'] for item in scored]
def analyze_library_quality(self) -> Dict[str, List]:
"""
Analyze notebook library for quality issues.
Returns:
Dictionary with lists of notebook IDs by issue type
"""
notebooks = self.list_notebooks_with_details()
issues = {
'short_descriptions': [],
'missing_topics': [],
'few_topics': [],
'no_use_cases': [],
'missing_tags': [],
'duplicate_names': {}
}
name_to_ids = {}
for notebook in notebooks:
# Check description length
if len(notebook.description) < 30:
issues['short_descriptions'].append({
'id': notebook.id,
'name': notebook.name,
'length': len(notebook.description)
})
# Check for missing topics
if not notebook.topics or len(notebook.topics) == 0:
issues['missing_topics'].append({
'id': notebook.id,
'name': notebook.name
})
# Check for few topics
elif len(notebook.topics) < 3:
issues['few_topics'].append({
'id': notebook.id,
'name': notebook.name,
'topic_count': len(notebook.topics)
})
# Check use cases
if not hasattr(notebook, 'use_cases') or not notebook.use_cases:
issues['no_use_cases'].append({
'id': notebook.id,
'name': notebook.name
})
# Check tags
if not hasattr(notebook, 'tags') or not notebook.tags:
issues['missing_tags'].append({
'id': notebook.id,
'name': notebook.name
})
# Track duplicate names
if notebook.name in name_to_ids:
name_to_ids[notebook.name].append(notebook.id)
else:
name_to_ids[notebook.name] = [notebook.id]
# Filter duplicates with more than one ID
for name, ids in name_to_ids.items():
if len(ids) > 1:
issues['duplicate_names'][name] = ids
return issues
def generate_library_report(self) -> str:
"""
Generate a comprehensive library report.
Returns:
Formatted report string
"""
issues = self.analyze_library_quality()
notebooks = self.list_notebooks_with_details()
report = ["=" * 60]
report.append("NotebookLM Library Report")
report.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
report.append(f"Total Notebooks: {len(notebooks)}")
report.append("=" * 60)
# Summary
total_issues = sum(len(v) if isinstance(v, list) else len(v)
for v in issues.values())
report.append(f"\n📊 Summary")
report.append(f" Total Issues Found: {total_issues}")
# Detailed issues
if any(issues.values()):
report.append("\n🔍 Issues Found\n")
for issue_type, affected in issues.items():
if not affected:
continue
if not isinstance(affected, list):
# Dictionary (duplicates)
for name, ids in affected.items():
report.append(f" ⚠ Duplicate Name: '{name}'")
for nb_id in ids:
report.append(f" - {nb_id}")
else:
# List
type_name = issue_type.replace('_', ' ').title()
report.append(f" ⚠ {type_name}: {len(affected)} notebook(s)")
for item in affected[:5]: # Show first 5
if isinstance(item, dict):
report.append(f" - {item.get('name', item.get('id'))}")
if len(affected) > 5:
report.append(f" ... and {len(affected) - 5} more")
else:
report.append("\n✓ No issues found!")
# Statistics
report.append("\n📈 Statistics")
report.append(f" Avg Description Length: {sum(len(nb.description) for nb in notebooks) / len(notebooks):.1f} chars")
report.append(f" Avg Topics per Notebook: {sum(len(nb.topics) for nb in notebooks) / len(notebooks):.1f}")
with_tags = [nb for nb in notebooks if hasattr(nb, 'tags') and nb.tags]
report.append(f" Notebooks with Tags: {len(with_tags) / len(notebooks) * 100:.1f}%")
with_use_cases = [nb for nb in notebooks if hasattr(nb, 'use_cases') and nb.use_cases]
report.append(f" Notebooks with Use Cases: {len(with_use_cases) / len(notebooks) * 100:.1f}%")
report.append("\n" + "=" * 60)
return "\n".join(report)
def suggest_notebook_updates(self, notebook_id: str) -> List[str]:
"""
Suggest updates for a specific notebook.
Args:
notebook_id: ID of notebook to analyze
Returns:
List of update suggestions
"""
notebooks = self.list_notebooks_with_details()
notebook = next((nb for nb in notebooks if nb.id == notebook_id), None)
if not notebook:
raise ValueError(f"Notebook not found: {notebook_id}")
suggestions = []
# Description suggestions
if len(notebook.description) < 30:
suggestions.append(
"Consider expanding description to 30+ characters "
"for better discoverability"
)
# Topic suggestions
if len(notebook.topics) < 3:
suggestions.append(
"Add more topics (aim for 3-5) to improve searchability"
)
# Use cases
if not hasattr(notebook, 'use_cases') or not notebook.use_cases:
suggestions.append(
"Add use cases to describe when this notebook is helpful"
)
# Tags
if not hasattr(notebook, 'tags') or not notebook.tags:
suggestions.append(
"Add organizational tags for better library management"
)
return suggestions
def export_library(self, filename: str = "notebook-library-export.json"):
"""
Export library to JSON file.
Args:
filename: Output filename
"""
notebooks = self.list_notebooks_with_details()
export_data = {
'exported_at': datetime.now().isoformat(),
'total_notebooks': len(notebooks),
'notebooks': []
}
for notebook in notebooks:
nb_data = {
'id': notebook.id,
'name': notebook.name,
'description': notebook.description,
'topics': notebook.topics,
'url': notebook.url
}
if hasattr(notebook, 'tags') and notebook.tags:
nb_data['tags'] = notebook.tags
if hasattr(notebook, 'use_cases') and notebook.use_cases:
nb_data['use_cases'] = notebook.use_cases
if hasattr(notebook, 'content_types') and notebook.content_types:
nb_data['content_types'] = notebook.content_types
export_data['notebooks'].append(nb_data)
with open(filename, 'w', encoding='utf-8') as f:
json.dump(export_data, f, indent=2, ensure_ascii=False)
print(f"✓ Library exported to {filename}")
print(f" Total notebooks: {len(notebooks)}")
return filename
def main():
"""Main entry point for CLI usage"""
helper = NotebookLMHelper()
import argparse
parser = argparse.ArgumentParser(
description="NotebookLM MCP Helper Utility"
)
parser.add_argument(
'action',
choices=['list', 'search', 'report', 'export', 'analyze'],
help="Action to perform"
)
parser.add_argument(
'--query', '-q',
help="Search query"
)
parser.add_argument(
'--output', '-o',
help="Output filename (for export)"
)
parser.add_argument(
'--notebook-id', '-n',
help="Notebook ID (for specific actions)"
)
args = parser.parse_args()
try:
if args.action == 'list':
notebooks = helper.list_notebooks_with_details()
print(f"\nTotal Notebooks: {len(notebooks)}\n")
for nb in notebooks:
print(f"📚 {nb.name}")
print(f" Topics: {', '.join(nb.topics)}")
print(f" ID: {nb.id}")
print()
elif args.action == 'search':
if not args.query:
print("Error: --query required for search")
sys.exit(1)
results = helper.search_notebooks_fuzzy(args.query)
print(f"\nSearch Results for '{args.query}':\n")
if results:
for i, nb in enumerate(results, 1):
print(f"{i}. {nb.name}")
print(f" {', '.join(nb.topics)}")
print(f" {nb.description}")
print(f" ID: {nb.id}")
print()
else:
print("No matching notebooks found.")
elif args.action == 'report':
report = helper.generate_library_report()
print(report)
elif args.action == 'export':
filename = args.output or "notebook-library-export.json"
helper.export_library(filename)
elif args.action == 'analyze':
if not args.notebook_id:
print("Error: --notebook-id required for analyze")
sys.exit(1)
suggestions = helper.suggest_notebook_updates(args.notebook_id)
print(f"\nSuggestions for notebook {args.notebook_id}:\n")
if suggestions:
for i, suggestion in enumerate(suggestions, 1):
print(f"{i}. {suggestion}")
else:
print("✓ No suggestions - notebook looks great!")
except Exception as e:
print(f"\n❌ Error: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
NotebookLM Helper Script
notebooklm-helper.py is a local utility for reviewing exported NotebookLM library metadata when the MCP server is unavailable in the current client.
Examples
python notebooklm-helper.py list
python notebooklm-helper.py search --query "react"
python notebooklm-helper.py report
python notebooklm-helper.py export --output backup.jsonRelated skills
FAQ
What does notebooklm-management do?
notebooklm-management is a Claude Code skill for productivity & planning.
When should I use notebooklm-management?
When you need to helps with productivity & planning tasks., or when notebooklm-management is a claude code skill for productivity & planning.
What are the main capabilities?
notebooklm-management; Productivity & Planning; AI-coding skill.