Skip to main content
Glama

Web Search MCP Server

by williamvd4
index.ts4.3 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js'; import axios from 'axios'; import * as cheerio from 'cheerio'; interface SearchResult { title: string; url: string; description: string; } const isValidSearchArgs = (args: any): args is { query: string; limit?: number } => typeof args === 'object' && args !== null && typeof args.query === 'string' && (args.limit === undefined || typeof args.limit === 'number'); class WebSearchServer { private server: Server; constructor() { this.server = new Server( { name: 'web-search', version: '0.1.0', }, { capabilities: { tools: {}, }, } ); this.setupToolHandlers(); this.server.onerror = (error) => console.error('[MCP Error]', error); process.on('SIGINT', async () => { await this.server.close(); process.exit(0); }); } private setupToolHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'search', description: 'Search the web using Google (no API key required)', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query', }, limit: { type: 'number', description: 'Maximum number of results to return (default: 5)', minimum: 1, maximum: 10, }, }, required: ['query'], }, }, ], })); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { if (request.params.name !== 'search') { throw new McpError( ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}` ); } if (!isValidSearchArgs(request.params.arguments)) { throw new McpError( ErrorCode.InvalidParams, 'Invalid search arguments' ); } const query = request.params.arguments.query; const limit = Math.min(request.params.arguments.limit || 5, 10); try { const results = await this.performSearch(query, limit); return { content: [ { type: 'text', text: JSON.stringify(results, null, 2), }, ], }; } catch (error) { if (axios.isAxiosError(error)) { return { content: [ { type: 'text', text: `Search error: ${error.message}`, }, ], isError: true, }; } throw error; } }); } private async performSearch(query: string, limit: number): Promise<SearchResult[]> { const response = await axios.get('https://www.google.com/search', { params: { q: query }, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } }); const $ = cheerio.load(response.data); const results: SearchResult[] = []; $('div.g').each((i, element) => { if (i >= limit) return false; const titleElement = $(element).find('h3'); const linkElement = $(element).find('a'); const snippetElement = $(element).find('.VwiC3b'); if (titleElement.length && linkElement.length) { const url = linkElement.attr('href'); if (url && url.startsWith('http')) { results.push({ title: titleElement.text(), url: url, description: snippetElement.text() || '', }); } } }); return results; } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('Web Search MCP server running on stdio'); } } const server = new WebSearchServer(); server.run().catch(console.error);

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/williamvd4/web-search'

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