Skip to main content
Glama
chuanmingliu

MCP Web Research Server

by chuanmingliu

search_google

Perform web research by searching Google for specific queries to find relevant information, extract webpage content, and capture screenshots for analysis.

Instructions

Search Google for a query

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query

Implementation Reference

  • The implementation of the search_google tool handler. It uses Playwright to navigate to Google, input the query, submit the search, extract top results (title, url, snippet), stores them in the research session, and returns JSON of the 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');
                await dismissGoogleConsent(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');
                    });
    
                    // 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
                    await searchInput.click({ clickCount: 3 });  // Select all existing text
                    await searchInput.press('Backspace');        // Clear selected text
                    await searchInput.type(query);               // Type new query
                }, 3, 2000);  // Allow 3 retries with 2s delay
    
                // Step 4: Submit search and wait for results
                await withRetry(async () => {
                    await Promise.all([
                        page.keyboard.press('Enter'),
                        page.waitForLoadState('networkidle', { timeout: 15000 }),
                    ]);
                });
    
                // Step 5: Extract search results
                const searchResults = await withRetry(async () => {
                    const results = await page.evaluate(() => {
                        // Find all search result containers
                        const elements = document.querySelectorAll('div.g');
                        if (!elements || elements.length === 0) {
                            throw new Error('No search results found');
                        }
    
                        // Extract data from each result
                        return Array.from(elements).map((el) => {
                            // Find required elements within result container
                            const titleEl = el.querySelector('h3');            // Title element
                            const linkEl = el.querySelector('a');              // Link element
                            const snippetEl = el.querySelector('div.VwiC3b');  // Snippet element
    
                            // Skip results missing required elements
                            if (!titleEl || !linkEl || !snippetEl) {
                                return null;
                            }
    
                            // Return structured result data
                            return {
                                title: titleEl.textContent || '',        // Result title
                                url: linkEl.getAttribute('href') || '',  // Result URL
                                snippet: snippetEl.textContent || '',    // Result description
                            };
                        }).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
            };
        }
    }
  • The schema definition for the search_google tool, including name, description, and inputSchema requiring a 'query' parameter.
    {
        name: "search_google",
        description: "Search Google for a query",
        inputSchema: {
            type: "object",
            properties: {
                query: { type: "string", description: "Search query" },
            },
            required: ["query"],
        },
    },
  • index.ts:580-582 (registration)
    Registration of the tool list handler which returns the TOOLS array containing the search_google tool definition.
    server.setRequestHandler(ListToolsRequestSchema, async () => ({
        tools: TOOLS  // Return list of available research tools
    }));
  • Helper text in the agentic-research prompt that describes and instructs on using the search_google tool.
    You can use these tools:
    - search_google: Search for information
    - visit_page: Visit and extract content from web pages
    
    Do *NOT* use the following tools:
    - Anything related to knowledge graphs or memory, unless explicitly instructed to do so by the user.`
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/chuanmingliu/mcp-webresearch'

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