web_search
Perform web or news searches using Bing to find information, tutorials, or current events with time-based filtering options.
Instructions
Perform web or news search using Bing search engine. Supports both general web search and news search modes.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query, e.g., Node.js tutorial, tech news, political updates, etc. | |
| searchType | Yes | Search type: web (general web search), news (news search) - required | |
| maxResults | No | Maximum number of results | |
| timeFilter | No | Time filter (only valid for news search): past 1 hour, 24 hours, 7 days, 30 days | past_24_hours |
Implementation Reference
- src/mcp/server.js:173-211 (handler)Main MCP tool handler for web_search. Validates input parameters and delegates to searchService for Bing web or news search.async function handleWebSearch(args) { const { query, searchType, maxResults = 10, timeFilter = 'past_24_hours' } = args; if (!query || typeof query !== 'string') { throw new Error('Query parameter is required and must be a string'); } if (!searchType || !['web', 'news'].includes(searchType)) { throw new Error('searchType is required and must be either "web" or "news"'); } if (maxResults < 1 || maxResults > 20) { throw new Error('maxResults must be between 1 and 20'); } if (searchType === 'news' && !['past_hour', 'past_24_hours', 'past_7_days', 'past_30_days'].includes(timeFilter)) { throw new Error('timeFilter must be a valid time filter option'); } const searchService = (await import('../services/searchService.js')).default; let results; if (searchType === 'news') { results = await searchService.searchBingNews(query, maxResults, timeFilter); } else { results = await searchService.searchBing(query, maxResults); } return { tool: 'web_search', searchType, query, maxResults, timeFilter: searchType === 'news' ? timeFilter : undefined, results: results.results, totalResults: results.totalResults, timestamp: results.timestamp }; }
- src/mcp/server.js:9-38 (schema)Input schema definition for the web_search tool, including parameters query, searchType, maxResults, and timeFilter.name: 'web_search', description: 'Perform web or news search using Bing search engine. Supports both general web search and news search modes.', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query, e.g., Node.js tutorial, tech news, political updates, etc.' }, searchType: { type: 'string', enum: ['web', 'news'], description: 'Search type: web (general web search), news (news search) - required' }, maxResults: { type: 'number', description: 'Maximum number of results', default: 10, minimum: 1, maximum: 20 }, timeFilter: { type: 'string', enum: ['past_hour', 'past_24_hours', 'past_7_days', 'past_30_days'], description: 'Time filter (only valid for news search): past 1 hour, 24 hours, 7 days, 30 days', default: 'past_24_hours' } }, required: ['query', 'searchType'] }
- src/mcp/server.js:130-131 (registration)Switch case registration that maps tool call 'web_search' to the handleWebSearch function.case 'web_search': result = await handleWebSearch(args);
- Core implementation of Bing web search using Puppeteer browser automation to scrape search results.async searchBing(query, maxResults = 10) { try { const browser = await this.initBrowser(); const page = await browser.newPage(); await page.setUserAgent(this.getRandomUserAgent()); await page.setViewport({ width: 1920, height: 1080 }); const searchUrl = `https://www.bing.com/search?q=${encodeURIComponent(query)}&count=${maxResults}`; await page.goto(searchUrl, { waitUntil: 'networkidle2' }); await page.waitForSelector('#b_results', { timeout: 10000 }); const rawResults = await page.evaluate(() => { const searchResults = []; const resultElements = document.querySelectorAll('#b_results .b_algo'); resultElements.forEach((element, index) => { if (index >= 10) return; const titleElement = element.querySelector('h2 a'); const snippetElement = element.querySelector('.b_caption p'); if (titleElement) { searchResults.push({ title: titleElement.textContent.trim(), url: titleElement.href, snippet: snippetElement ? snippetElement.textContent.trim() : '', rank: index + 1 }); } }); return searchResults; }); // Clean URLs in Node.js const results = rawResults.map(item => ({ ...item, url: this.cleanUrl(item.url) })); await page.close(); logger.info(`Bing search completed for query: "${query}", found ${results.length} results`); return { engine: 'Bing', query, results, totalResults: results.length, timestamp: new Date().toISOString() }; } catch (error) { logger.error('Bing search error:', error); throw new Error(`Bing search failed: ${error.message}`); } }
- Core implementation of Bing news search with time filtering using Puppeteer to handle dynamic news results.async searchBingNews(query, maxResults = 10, timeFilter = 'past_24_hours') { try { const browser = await this.initBrowser(); const page = await browser.newPage(); await page.setUserAgent(this.getRandomUserAgent()); await page.setViewport({ width: 1920, height: 1080 }); // Build news search URL let searchUrl = `https://www.bing.com/news/search?q=${encodeURIComponent(query)}`; // Add time filter const timeParams = { 'past_hour': '&qft=interval%3d"1"', 'past_24_hours': '&qft=interval%3d"24"', 'past_7_days': '&qft=interval%3d"7"', 'past_30_days': '&qft=interval%3d"30"' }; if (timeParams[timeFilter]) { searchUrl += timeParams[timeFilter]; } logger.info(`Navigating to Bing News: ${searchUrl}`); await page.goto(searchUrl, { waitUntil: 'networkidle2', timeout: 15000 }); // Wait for news results to load await new Promise(resolve => setTimeout(resolve, 3000)); // Try to wait for page content try { await page.waitForSelector('body', { timeout: 5000 }); } catch (error) { logger.warn('Timeout waiting for page load, continuing'); } const rawResults = await page.evaluate((maxResults) => { const newsResults = []; // Try multiple selectors for news items const selectors = [ '.news-card', '.news-item', '.news-card-container', '[data-news-card]', '.news-content', '.news-title', '.news-item-container', '.news-list-item' ]; let newsElements = []; for (const selector of selectors) { newsElements = document.querySelectorAll(selector); if (newsElements.length > 0) { break; } } // Fallback: try links containing /news/ if (newsElements.length === 0) { const allLinks = document.querySelectorAll('a[href*="/news/"]'); newsElements = Array.from(allLinks).map(link => { const container = link.closest('div') || link.parentElement; return container || link; }); } // Fallback: just take some links if (newsElements.length === 0) { const allLinks = document.querySelectorAll('a[href]'); newsElements = Array.from(allLinks).slice(0, 20); } // Extract news info newsElements.forEach((element, index) => { if (index >= maxResults) return; let title = ''; let url = ''; let source = ''; let time = ''; // Title const titleSelectors = ['h2', 'h3', '.news-title', '.title', 'a']; for (const selector of titleSelectors) { const el = element.querySelector(selector); if (el && el.textContent.trim()) { title = el.textContent.trim(); if (el.href) { url = el.href; } break; } } // Link if (!url) { const linkEl = element.querySelector('a[href]'); if (linkEl && linkEl.href) { url = linkEl.href; } } // Source const sourceSelectors = ['.news-source', '.source', '.publisher', '.author']; for (const selector of sourceSelectors) { const el = element.querySelector(selector); if (el && el.textContent.trim()) { source = el.textContent.trim(); break; } } // Time const timeSelectors = ['.news-time', '.time', '.date', '.timestamp']; for (const selector of timeSelectors) { const el = element.querySelector(selector); if (el && el.textContent.trim()) { time = el.textContent.trim(); break; } } // Validate if (title && url) { const isValidNewsUrl = url.includes('/news/') || url.includes('news') || url.includes('bing.com') || url.includes('msn.com') || url.includes('baidu.com') || url.includes('baike.baidu.com'); if (isValidNewsUrl) { newsResults.push({ title, url, source, time, rank: index + 1 }); } } }); return newsResults; }, maxResults); // Clean URLs in Node.js const results = rawResults.map(item => ({ ...item, url: this.cleanUrl(item.url) })); await page.close(); logger.info(`Bing News search completed for query: "${query}", found ${results.length} results`); return { engine: 'Bing News', query, results, totalResults: results.length, timeFilter, timestamp: new Date().toISOString() }; } catch (error) { logger.error('Bing News search error:', error); throw new Error(`Bing News search failed: ${error.message}`); } }