Skip to main content
Glama

Claude Web Search MCP Server

by Doriandarko
index.ts5.24 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, Tool, } from "@modelcontextprotocol/sdk/types.js"; import { Anthropic } from '@anthropic-ai/sdk'; import * as dotenv from 'dotenv'; import * as fs from 'fs'; import * as path from 'path'; // Load environment variables as fallback dotenv.config(); // Function to load the Claude Desktop config function loadClaudeConfig() { try { const configPath = path.resolve(process.env.HOME || '', 'code', 'claude-search-mcp', 'claude_desktop_config.json'); const configData = fs.readFileSync(configPath, 'utf8'); return JSON.parse(configData); } catch (error) { console.warn(`Warning: Could not load Claude Desktop config: ${(error as Error).message}`); console.warn('Falling back to environment variables'); return null; } } // Get Anthropic API key from config or environment const claudeConfig = loadClaudeConfig(); const anthropicApiKey = process.env.ANTHROPIC_API_KEY || ''; // Initialize the Anthropic client const anthropic = new Anthropic({ apiKey: anthropicApiKey, }); // Define tool schema const WEB_SEARCH_TOOL: Tool = { name: "web_search", description: "Search the web for real-time information about any topic. Use this tool when you need up-to-date information that might not be available in your training data, or when you need to verify current facts.", inputSchema: { type: "object", properties: { query: { type: "string", description: "The search query to look up on the web" }, maxResults: { type: "number", description: "Maximum number of search results to return (default: 5)" }, allowedDomains: { type: "array", items: { type: "string" }, description: "Only include results from these domains" }, blockedDomains: { type: "array", items: { type: "string" }, description: "Never include results from these domains" } }, required: ["query"] } }; // Create the server const server = new Server( { name: "Claude Web Search", version: "1.0.0" }, { capabilities: { tools: {}, } } ); // List tools handler server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [WEB_SEARCH_TOOL] }; }); // Call tool handler server.setRequestHandler(CallToolRequestSchema, async (request: any) => { try { const { name, arguments: args } = request.params; if (name !== "web_search") { throw new Error(`Unknown tool: ${name}`); } if (!args || typeof args !== 'object') { throw new Error("No arguments provided"); } const { query, maxResults = 5, allowedDomains, blockedDomains } = args as any; if (!query || typeof query !== 'string') { throw new Error("Invalid query parameter"); } // Prepare the web search tool configuration const webSearchTool = { type: "web_search_20250305", name: "web_search", max_uses: maxResults }; // Add domain filtering if provided if (allowedDomains && Array.isArray(allowedDomains) && allowedDomains.length > 0) { (webSearchTool as any).allowed_domains = allowedDomains; } if (blockedDomains && Array.isArray(blockedDomains) && blockedDomains.length > 0) { (webSearchTool as any).blocked_domains = blockedDomains; } // Create a Claude message with the web search const response = await anthropic.messages.create({ model: "claude-3-7-sonnet-latest", max_tokens: 1024, messages: [ { role: "user", content: query } ], // @ts-ignore - Ignoring TypeScript error since Claude API does support this tools: [webSearchTool] }); // Extract and format the search results let results = ""; for (const item of response.content) { if (item.type === 'text') { results += item.text + "\n\n"; } else if (item.type === 'web_search_tool_result' && 'content' in item && Array.isArray(item.content)) { results += "### Search Results\n\n"; for (const result of item.content) { if (result.type === 'web_search_result') { results += `- [${result.title}](${result.url})\n`; results += ` Last updated: ${result.page_age || 'Unknown'}\n\n`; } } } } // Return the formatted results return { content: [{ type: "text", text: results.trim() }] }; } catch (error) { console.error('Error performing web search:', error); return { content: [{ type: "text", text: `Error performing web search: ${(error as Error).message}` }], isError: true }; } }); // Run the server via stdio async function runServer() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("Claude Web Search MCP Server running on stdio"); } runServer().catch((error) => { console.error("Fatal error running server:", error); process.exit(1); });

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/Doriandarko/claude-search-mcp'

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