Skip to main content
Glama
PhialsBasement

MCP Web Research Server

search_google

Search the web using Google to find current information, news, websites, and general knowledge. Returns structured results with titles, URLs, and snippets.

Instructions

Performs a web search using Google, ideal for finding current information, news, websites, and general knowledge. Use this tool when you need to research topics, find recent information, or gather data from the web. Returns structured search results with titles, URLs, and snippets.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query

Implementation Reference

  • index.ts:144-154 (registration)
    Tool registration/schema for 'search_google' - defines the tool name, description, and input schema expecting a 'query' string parameter.
    {
        name: "search_google",
        description: "Performs a web search using Google, ideal for finding current information, news, websites, and general knowledge. Use this tool when you need to research topics, find recent information, or gather data from the web. Returns structured search results with titles, URLs, and snippets.",
        inputSchema: {
            type: "object",
            properties: {
                query: { type: "string", description: "Search query" },
            },
            required: ["query"],
        },
    },
  • Input schema for search_google tool - defines the 'query' string property as required.
    {
        name: "search_google",
        description: "Performs a web search using Google, ideal for finding current information, news, websites, and general knowledge. Use this tool when you need to research topics, find recent information, or gather data from the web. Returns structured search results with titles, URLs, and snippets.",
        inputSchema: {
            type: "object",
            properties: {
                query: { type: "string", description: "Search query" },
            },
            required: ["query"],
        },
    },
  • Handler implementation for search_google - navigates to Google, fills search query, extracts result titles/URLs/snippets, and returns JSON results.
    case "search_google": {
        // Extract search query from request parameters
        const { query } = request.params.arguments as { query: string };
    
        try {
            // Execute search with retry mechanism
            const results = await withRetry(async () => {
                // Step 1: Navigate to Google search page
                await safePageNavigation(page, 'https://www.google.com');
    
                // Simulate human behavior
                await randomDelay(800, 1500);
                await simulateHumanBehavior(page);
    
                // Step 2: Find and interact with search input
                await withRetry(async () => {
                    // Wait for any search input element to appear
                    await Promise.race([
                        // Try multiple possible selectors for search input
                        page.waitForSelector('input[name="q"]', { timeout: 5000 }),
                                       page.waitForSelector('textarea[name="q"]', { timeout: 5000 }),
                                       page.waitForSelector('input[type="text"]', { timeout: 5000 })
                    ]).catch(() => {
                        throw new Error('Search input not found - no matching selectors');
                    });
    
                    // Random delay before interacting
                    await randomDelay(300, 700);
    
                    // Find the actual search input element
                    const searchInput = await page.$('input[name="q"]') ||
                    await page.$('textarea[name="q"]') ||
                    await page.$('input[type="text"]');
    
                    // Verify search input was found
                    if (!searchInput) {
                        throw new Error('Search input element not found after waiting');
                    }
    
                    // Step 3: Enter search query with human-like typing
                    await searchInput.click();
                    await randomDelay(100, 300);
                    await searchInput.click({ clickCount: 3 });  // Select all existing text
                    await randomDelay(50, 150);
                    await searchInput.press('Backspace');        // Clear selected text
                    await randomDelay(200, 400);
    
                    // Type query with random delays between characters
                    for (const char of query) {
                        await searchInput.type(char);
                        await randomDelay(50, 150);
                    }
                }, 3, 2000);  // Allow 3 retries with 2s delay
    
                // Random delay before submitting
                await randomDelay(400, 900);
    
                // Step 4: Submit search and wait for results
                await withRetry(async () => {
                    await Promise.all([
                        page.keyboard.press('Enter'),
                                      page.waitForLoadState('networkidle', { timeout: 15000 }),
                    ]);
                });
    
                // Simulate human behavior after results load
                await randomDelay(500, 1000);
                await simulateHumanBehavior(page);
    
                // Step 5: Check for bot detection before extracting results
                const pageCheck = await page.evaluate(() => {
                    // Check for results using multiple selectors
                    const hasResults = document.querySelectorAll('div.g').length > 0 ||
                                      document.querySelectorAll('div[data-hveid]').length > 0 ||
                                      document.querySelectorAll('.MjjYud').length > 0 ||
                                      document.querySelectorAll('div.Gx5Zad').length > 0;
    
                    return {
                        title: document.title,
                        hasCaptcha: !!document.querySelector('#captcha-form') ||
                                   !!document.querySelector('iframe[src*="recaptcha"]') ||
                                   document.body.innerText.includes('unusual traffic'),
                        hasResults: hasResults,
                        bodyText: document.body.innerText.substring(0, 500)
                    };
                });
    
                if (pageCheck.hasCaptcha) {
                    throw new Error('Bot detection triggered - CAPTCHA detected');
                }
    
                if (!pageCheck.hasResults) {
                    throw new Error(`No search results found. Page title: "${pageCheck.title}". Body preview: ${pageCheck.bodyText}`);
                }
    
                // Step 6: Extract search results
                const searchResults = await withRetry(async () => {
                    const results = await page.evaluate(() => {
                        // Try multiple selectors for search result containers (Google changes these frequently)
                        const possibleSelectors = [
                            'div.g',              // Classic selector
                            'div[data-hveid]',    // Modern selector with tracking ID
                            'div.Gx5Zad',         // Alternative container
                            '.MjjYud',            // Another common container
                        ];
    
                        let elements: NodeListOf<Element> | null = null;
                        for (const selector of possibleSelectors) {
                            elements = document.querySelectorAll(selector);
                            if (elements && elements.length > 0) {
                                break;
                            }
                        }
    
                        if (!elements || elements.length === 0) {
                            throw new Error('No search results found with any known selector');
                        }
    
                        // Extract data from each result
                        return Array.from(elements).map((el) => {
                            // Find title - try multiple selectors
                            const titleEl = el.querySelector('h3') ||
                                           el.querySelector('h2') ||
                                           el.querySelector('[role="heading"]');
    
                            // Find link - look for main link
                            const linkEl = el.querySelector('a[href]');
    
                            // Find snippet - try multiple selectors
                            const snippetEl = el.querySelector('div.VwiC3b') ||
                                             el.querySelector('.IsZvec') ||
                                             el.querySelector('[data-content-feature]') ||
                                             el.querySelector('div[style*="line-clamp"]');
    
                            // Skip results missing required elements
                            if (!titleEl || !linkEl) {
                                return null;
                            }
    
                            const url = linkEl.getAttribute('href') || '';
    
                            // Skip non-http URLs (like javascript:, data:, etc.)
                            if (!url.startsWith('http')) {
                                return null;
                            }
    
                            // Return structured result data
                            return {
                                title: titleEl.textContent?.trim() || '',
                                url: url,
                                snippet: snippetEl?.textContent?.trim() || '',
                            };
                        }).filter(result => result !== null);  // Remove invalid results
                    });
    
                    // Verify we found valid results
                    if (!results || results.length === 0) {
                        throw new Error('No valid search results found');
                    }
    
                    // Return compiled list of results
                    return results;
                });
    
                // Step 6: Store results in session
                searchResults.forEach((result) => {
                    addResult({
                        url: result.url,
                        title: result.title,
                        content: result.snippet,
                        timestamp: new Date().toISOString(),
                    });
                });
    
                // Return compiled list of results
                return searchResults;
            });
    
            // Step 7: Return formatted results
            return {
                content: [{
                    type: "text",
                    text: JSON.stringify(results, null, 2)  // Pretty-print JSON results
                }]
            };
        } catch (error) {
            // Handle and format search errors
            return {
                content: [{
                    type: "text",
                    text: `Failed to perform search: ${(error as Error).message}`
                }],
                isError: true
            };
        }
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description must cover behavioral aspects. States return format (titles, URLs, snippets) but omits details like rate limits, query length limits, pagination, or error handling. Basic transparency but with notable gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, no unnecessary words, front-loaded with purpose. Every sentence adds value: what it does, when to use, what it returns.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a simple tool with one parameter and no output schema, the description covers primary purpose, use cases, and return format. Lacks details like result count limits or error scenarios, but adequate for basic usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter (query) with 100% schema description coverage (minimal: 'Search query'). The tool description adds no further parameter-specific meaning, only repeating use cases. Baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states 'Performs a web search using Google' with specific use cases (current information, news, websites, general knowledge). Distinguishes from sibling tools like search_scholar (academic) and visit_page (browsing).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear guidance on when to use: 'research topics, find recent information, or gather data from the web.' Does not explicitly mention when not to use or alternatives, but context implies a general web search tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/PhialsBasement/mcp-webresearch-stealthified'

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