UNPKG

exa-mcp-server

Version:

A Model Context Protocol server with Exa for web search, academic paper search, and Twitter/X.com search. Provides real-time web searches with configurable tool selection, allowing users to enable or disable specific search capabilities. Supports customiz

112 lines (111 loc) 4.14 kB
#!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import dotenv from "dotenv"; import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; // Import the tool registry system import { toolRegistry } from "./tools/index.js"; import { log } from "./utils/logger.js"; dotenv.config(); // Parse command line arguments to determine which tools to enable const argv = yargs(hideBin(process.argv)) .option('tools', { type: 'string', description: 'Comma-separated list of tools to enable (if not specified, all enabled-by-default tools are used)', default: '' }) .option('list-tools', { type: 'boolean', description: 'List all available tools and exit', default: false }) .help() .argv; // Convert comma-separated string to Set for easier lookups const argvObj = argv; const toolsString = argvObj['tools'] || ''; const specifiedTools = new Set(toolsString ? toolsString.split(',').map((tool) => tool.trim()) : []); // List all available tools if requested if (argvObj['list-tools']) { console.log("Available tools:"); Object.entries(toolRegistry).forEach(([id, tool]) => { console.log(`- ${id}: ${tool.name}`); console.log(` Description: ${tool.description}`); console.log(` Enabled by default: ${tool.enabled ? 'Yes' : 'No'}`); console.log(); }); process.exit(0); } // Check for API key after handling list-tools to allow listing without a key const API_KEY = process.env.EXA_API_KEY; if (!API_KEY) { throw new Error("EXA_API_KEY environment variable is required"); } /** * Exa AI Web Search MCP Server * * This MCP server integrates Exa AI's search capabilities with Claude and other MCP-compatible clients. * Exa is a search engine and API specifically designed for up-to-date web searching and retrieval, * offering more recent and comprehensive results than what might be available in an LLM's training data. * * The server provides tools that enable: * - Real-time web searching with configurable parameters * - Research paper searches * - And more to come! */ class ExaServer { server; constructor() { this.server = new McpServer({ name: "exa-search-server", version: "0.3.10" }); log("Server initialized"); } setupTools() { // Register tools based on specifications const registeredTools = []; Object.entries(toolRegistry).forEach(([toolId, tool]) => { // If specific tools were provided, only enable those. // Otherwise, enable all tools marked as enabled by default const shouldRegister = specifiedTools.size > 0 ? specifiedTools.has(toolId) : tool.enabled; if (shouldRegister) { this.server.tool(tool.name, tool.description, tool.schema, tool.handler); registeredTools.push(toolId); } }); return registeredTools; } async run() { try { // Set up tools before connecting const registeredTools = this.setupTools(); log(`Starting Exa MCP server with ${registeredTools.length} tools: ${registeredTools.join(', ')}`); const transport = new StdioServerTransport(); // Handle connection errors transport.onerror = (error) => { log(`Transport error: ${error.message}`); }; await this.server.connect(transport); log("Exa Search MCP server running on stdio"); } catch (error) { log(`Server initialization error: ${error instanceof Error ? error.message : String(error)}`); throw error; } } } // Create and run the server with proper error handling (async () => { try { const server = new ExaServer(); await server.run(); } catch (error) { log(`Fatal server error: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } })();