Skip to main content
Glama

ask_question

Query NotebookLM to get answers based on your uploaded documents, providing synthesized responses with source citations.

Instructions

Conversational Research Partner (NotebookLM • Gemini 2.5 • Session RAG)

No Active Notebook

  • Visit https://notebooklm.google to create a notebook and get a share link

  • Use add_notebook to add it to your library (explains how to get the link)

  • Use list_notebooks to show available sources

  • Use select_notebook to set one active

Auth tip: If login is required, use the prompt 'notebooklm.auth-setup' and then verify with the 'get_health' tool. If authentication later fails (e.g., expired cookies), use the prompt 'notebooklm.auth-repair'.

Tip: Tell the user you can manage NotebookLM library and ask which notebook to use for the current task.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
questionYesThe question to ask NotebookLM
session_idNoOptional session ID for contextual conversations. If omitted, a new session is created.
notebook_idNoOptional notebook ID from your library. If omitted, uses the active notebook. Use list_notebooks to see available notebooks.
notebook_urlNoOptional notebook URL (overrides notebook_id). Use this for ad-hoc queries to notebooks not in your library.
show_browserNoShow browser window for debugging (simple version). For advanced control (typing speed, stealth, etc.), use browser_options instead.
browser_optionsNoOptional browser behavior settings. Claude can control everything: visibility, typing speed, stealth mode, timeouts. Useful for debugging or fine-tuning.

Implementation Reference

  • Main handler function that executes the 'ask_question' tool. Manages browser sessions, resolves notebooks, interacts with NotebookLM via browser automation, handles errors and rate limits, and returns structured results including session information for follow-ups.
    async handleAskQuestion(
      args: {
        question: string;
        session_id?: string;
        notebook_id?: string;
        notebook_url?: string;
        show_browser?: boolean;
        browser_options?: BrowserOptions;
      },
      sendProgress?: ProgressCallback
    ): Promise<ToolResult<AskQuestionResult>> {
      const { question, session_id, notebook_id, notebook_url, show_browser, browser_options } = args;
    
      log.info(`🔧 [TOOL] ask_question called`);
      log.info(`  Question: "${question.substring(0, 100)}"...`);
      if (session_id) {
        log.info(`  Session ID: ${session_id}`);
      }
      if (notebook_id) {
        log.info(`  Notebook ID: ${notebook_id}`);
      }
      if (notebook_url) {
        log.info(`  Notebook URL: ${notebook_url}`);
      }
    
      try {
        // Resolve notebook URL
        let resolvedNotebookUrl = notebook_url;
    
        if (!resolvedNotebookUrl && notebook_id) {
          const notebook = this.library.incrementUseCount(notebook_id);
          if (!notebook) {
            throw new Error(`Notebook not found in library: ${notebook_id}`);
          }
    
          resolvedNotebookUrl = notebook.url;
          log.info(`  Resolved notebook: ${notebook.name}`);
        } else if (!resolvedNotebookUrl) {
          const active = this.library.getActiveNotebook();
          if (active) {
            const notebook = this.library.incrementUseCount(active.id);
            if (!notebook) {
              throw new Error(`Active notebook not found: ${active.id}`);
            }
            resolvedNotebookUrl = notebook.url;
            log.info(`  Using active notebook: ${notebook.name}`);
          }
        }
    
        // Progress: Getting or creating session
        await sendProgress?.("Getting or creating browser session...", 1, 5);
    
        // Apply browser options temporarily
        const originalConfig = { ...CONFIG };
        const effectiveConfig = applyBrowserOptions(browser_options, show_browser);
        Object.assign(CONFIG, effectiveConfig);
    
        // Calculate overrideHeadless parameter for session manager
        // show_browser takes precedence over browser_options.headless
        let overrideHeadless: boolean | undefined = undefined;
        if (show_browser !== undefined) {
          overrideHeadless = show_browser;
        } else if (browser_options?.show !== undefined) {
          overrideHeadless = browser_options.show;
        } else if (browser_options?.headless !== undefined) {
          overrideHeadless = !browser_options.headless;
        }
    
        try {
          // Get or create session (with headless override to handle mode changes)
          const session = await this.sessionManager.getOrCreateSession(
            session_id,
            resolvedNotebookUrl,
            overrideHeadless
          );
    
        // Progress: Asking question
        await sendProgress?.("Asking question to NotebookLM...", 2, 5);
    
        // Ask the question (pass progress callback)
        const rawAnswer = await session.ask(question, sendProgress);
        const answer = `${rawAnswer.trimEnd()}${FOLLOW_UP_REMINDER}`;
    
        // Get session info
        const sessionInfo = session.getInfo();
    
        const result: AskQuestionResult = {
          status: "success",
          question,
          answer,
          session_id: session.sessionId,
          notebook_url: session.notebookUrl,
          session_info: {
            age_seconds: sessionInfo.age_seconds,
            message_count: sessionInfo.message_count,
            last_activity: sessionInfo.last_activity,
          },
        };
    
          // Progress: Complete
          await sendProgress?.("Question answered successfully!", 5, 5);
    
          log.success(`✅ [TOOL] ask_question completed successfully`);
          return {
            success: true,
            data: result,
          };
        } finally {
          // Restore original CONFIG
          Object.assign(CONFIG, originalConfig);
        }
      } catch (error) {
        const errorMessage =
          error instanceof Error ? error.message : String(error);
    
        // Special handling for rate limit errors
        if (error instanceof RateLimitError || errorMessage.toLowerCase().includes("rate limit")) {
          log.error(`🚫 [TOOL] Rate limit detected`);
          return {
            success: false,
            error:
              "NotebookLM rate limit reached (50 queries/day for free accounts).\n\n" +
              "You can:\n" +
              "1. Use the 're_auth' tool to login with a different Google account\n" +
              "2. Wait until tomorrow for the quota to reset\n" +
              "3. Upgrade to Google AI Pro/Ultra for 5x higher limits\n\n" +
              `Original error: ${errorMessage}`,
          };
        }
    
        log.error(`❌ [TOOL] ask_question failed: ${errorMessage}`);
        return {
          success: false,
          error: errorMessage,
        };
      }
    }
  • Tool definition including input schema (JSON Schema) for the 'ask_question' tool, specifying parameters like question, session_id, notebook options, and browser controls.
    export const askQuestionTool: Tool = {
      name: "ask_question",
      // Description will be set dynamically using buildAskQuestionDescription
      description: "Dynamic description placeholder", 
      inputSchema: {
        type: "object",
        properties: {
          question: {
            type: "string",
            description: "The question to ask NotebookLM",
          },
          session_id: {
            type: "string",
            description:
              "Optional session ID for contextual conversations. If omitted, a new session is created.",
          },
          notebook_id: {
            type: "string",
            description:
              "Optional notebook ID from your library. If omitted, uses the active notebook. " +
              "Use list_notebooks to see available notebooks.",
          },
          notebook_url: {
            type: "string",
            description:
              "Optional notebook URL (overrides notebook_id). Use this for ad-hoc queries to notebooks not in your library.",
          },
          show_browser: {
            type: "boolean",
            description:
              "Show browser window for debugging (simple version). " +
              "For advanced control (typing speed, stealth, etc.), use browser_options instead.",
          },
          browser_options: {
            type: "object",
            description:
              "Optional browser behavior settings. Claude can control everything: " +
              "visibility, typing speed, stealth mode, timeouts. Useful for debugging or fine-tuning.",
            properties: {
              show: {
                type: "boolean",
                description: "Show browser window (default: from ENV or false)",
              },
              headless: {
                type: "boolean",
                description: "Run browser in headless mode (default: true)",
              },
              timeout_ms: {
                type: "number",
                description: "Browser operation timeout in milliseconds (default: 30000)",
              },
              stealth: {
                type: "object",
                description: "Human-like behavior settings to avoid detection",
                properties: {
                  enabled: {
                    type: "boolean",
                    description: "Master switch for all stealth features (default: true)",
                  },
                  random_delays: {
                    type: "boolean",
                    description: "Random delays between actions (default: true)",
                  },
                  human_typing: {
                    type: "boolean",
                    description: "Human-like typing patterns (default: true)",
                  },
                  mouse_movements: {
                    type: "boolean",
                    description: "Realistic mouse movements (default: true)",
                  },
                  typing_wpm_min: {
                    type: "number",
                    description: "Minimum typing speed in WPM (default: 160)",
                  },
                  typing_wpm_max: {
                    type: "number",
                    description: "Maximum typing speed in WPM (default: 240)",
                  },
                  delay_min_ms: {
                    type: "number",
                    description: "Minimum delay between actions in ms (default: 100)",
                  },
                  delay_max_ms: {
                    type: "number",
                    description: "Maximum delay between actions in ms (default: 400)",
                  },
                },
              },
              viewport: {
                type: "object",
                description: "Browser viewport size",
                properties: {
                  width: {
                    type: "number",
                    description: "Viewport width in pixels (default: 1920)",
                  },
                  height: {
                    type: "number",
                    description: "Viewport height in pixels (default: 1080)",
                  },
                },
              },
            },
          },
        },
        required: ["question"],
      },
    };
  • Function that builds and registers all tool definitions, dynamically setting the description for 'ask_question' based on the current notebook library state.
    export function buildToolDefinitions(library: NotebookLibrary): Tool[] {
      // Update the description for ask_question based on the library state
      const dynamicAskQuestionTool = {
        ...askQuestionTool,
        description: buildAskQuestionDescription(library),
      };
    
      return [
        dynamicAskQuestionTool,
        ...notebookManagementTools,
        ...sessionManagementTools,
        ...systemTools,
      ];
    }
  • src/index.ts:158-169 (registration)
    Dispatch/registration in the main MCP server handler: routes 'ask_question' tool calls to the handleAskQuestion method with progress support.
    case "ask_question":
      result = await this.toolHandlers.handleAskQuestion(
        args as {
          question: string;
          session_id?: string;
          notebook_id?: string;
          notebook_url?: string;
          show_browser?: boolean;
        },
        sendProgress
      );
      break;
  • TypeScript interface defining the structure of the result returned by the 'ask_question' tool.
    export interface AskQuestionResult {
      status: "success" | "error";
      question: string;
      answer?: string;
      error?: string;
      notebook_url: string;
      session_id?: string;
      session_info?: {
        age_seconds: number;
        message_count: number;
        last_activity: number;
      };
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/inventra/notebooklm-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server