UNPKG

markov-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

148 lines (147 loc) 7.31 kB
#!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // Import tool implementations import { registerWebSearchTool } from "./tools/webSearch.js"; import { registerResearchPaperSearchTool } from "./tools/researchPaperSearch.js"; import { registerCompanyResearchTool } from "./tools/companyResearch.js"; import { registerCrawlingTool } from "./tools/crawling.js"; import { registerCompetitorFinderTool } from "./tools/competitorFinder.js"; import { registerLinkedInSearchTool } from "./tools/linkedInSearch.js"; import { registerWikipediaSearchTool } from "./tools/wikipediaSearch.js"; import { registerGithubSearchTool } from "./tools/githubSearch.js"; import { registerResearchTaskTools } from "./tools/researchTasks.js"; import { registerContentsTool } from "./tools/contents.js"; import { registerWebsetsTools } from "./tools/websets.js"; import { registerOpenAIDeepResearchTools } from "./tools/openaiDeepResearch.js"; import { registerOpenAISparringTools } from "./tools/openaiSparring.js"; import { log } from "./utils/logger.js"; // Configuration schema for the EXA API key and tool selection export const configSchema = z.object({ exaApiKey: z.string().optional().describe("Exa AI API key for search operations"), enabledTools: z.array(z.string()).optional().describe("List of tools to enable (if not specified, all tools are enabled)"), debug: z.boolean().default(false).describe("Enable debug logging") }); // Tool registry for managing available tools const availableTools = { 'web_search_exa': { name: 'Web Search (Exa)', description: 'Real-time web search using Exa AI', enabled: true }, 'research_paper_search_exa': { name: 'Research Paper Search', description: 'Search academic papers and research', enabled: true }, 'company_research_exa': { name: 'Company Research', description: 'Research companies and organizations', enabled: true }, 'crawling_exa': { name: 'Web Crawling', description: 'Crawl and extract content from web pages', enabled: true }, 'competitor_finder_exa': { name: 'Competitor Finder', description: 'Find competitors for companies', enabled: true }, 'linkedin_search_exa': { name: 'LinkedIn Search', description: 'Search LinkedIn profiles and content', enabled: true }, 'wikipedia_search_exa': { name: 'Wikipedia Search', description: 'Search Wikipedia articles', enabled: true }, 'github_search_exa': { name: 'GitHub Search', description: 'Search GitHub repositories and code', enabled: true }, 'research_tasks_exa': { name: 'Research Tasks', description: 'Create and manage AI research tasks', enabled: true }, 'contents_exa': { name: 'Contents Retrieval', description: 'Retrieve content from specific URLs', enabled: true }, 'websets_exa': { name: 'Websets', description: 'Create and manage websets for continuous data collection', enabled: true }, 'openai_deep_research': { name: 'OpenAI Deep Research', description: 'Execute actual research tasks with web search using o3/o4-mini deep research models', enabled: true }, 'openai_sparring': { name: 'OpenAI Sparring', description: 'Refine research methodology through Q&A with o3 (creates research plans, not results)', enabled: true } }; // Process ENABLED_TOOLS environment variable const enabledToolsEnv = process.env.ENABLED_TOOLS; if (enabledToolsEnv) { // Disable all tools first Object.keys(availableTools).forEach(toolKey => { availableTools[toolKey].enabled = false; }); // Enable only specified tools const enabledToolsList = enabledToolsEnv.split(',').map(tool => tool.trim()); enabledToolsList.forEach(toolName => { if (availableTools[toolName]) { availableTools[toolName].enabled = true; log(`Enabled tool: ${toolName}`); } else { log(`Warning: Unknown tool specified in ENABLED_TOOLS: ${toolName}`); } }); } else { log("All tools enabled by default"); } // Main server setup async function main() { const args = process.argv.slice(2); const transport = args.find(arg => arg.startsWith('--transport='))?.split('=')[1] || 'stdio'; log(`Starting MCP server with transport: ${transport}`); const server = new McpServer({ name: "exa-mcp-server", version: "2.0.0", description: "MCP server for Exa AI search capabilities" }); // Note: The MCP server handles configuration through the client's connection // API key should be set via environment variable EXA_API_KEY // Register enabled tools const registerTools = () => { if (availableTools.web_search_exa.enabled) { registerWebSearchTool(server); log("Registered Web Search tool"); } if (availableTools.research_paper_search_exa.enabled) { registerResearchPaperSearchTool(server); log("Registered Research Paper Search tool"); } if (availableTools.company_research_exa.enabled) { registerCompanyResearchTool(server); log("Registered Company Research tool"); } if (availableTools.crawling_exa.enabled) { registerCrawlingTool(server); log("Registered Crawling tool"); } if (availableTools.competitor_finder_exa.enabled) { registerCompetitorFinderTool(server); log("Registered Competitor Finder tool"); } if (availableTools.linkedin_search_exa.enabled) { registerLinkedInSearchTool(server); log("Registered LinkedIn Search tool"); } if (availableTools.wikipedia_search_exa.enabled) { registerWikipediaSearchTool(server); log("Registered Wikipedia Search tool"); } if (availableTools.github_search_exa.enabled) { registerGithubSearchTool(server); log("Registered GitHub Search tool"); } if (availableTools.research_tasks_exa.enabled) { registerResearchTaskTools(server); log("Registered Research Tasks tools"); } if (availableTools.contents_exa.enabled) { registerContentsTool(server); log("Registered Contents Retrieval tool"); } if (availableTools.websets_exa.enabled) { registerWebsetsTools(server); log("Registered Websets tools"); } if (availableTools.openai_deep_research.enabled) { registerOpenAIDeepResearchTools(server); log("Registered OpenAI Deep Research tools"); } if (availableTools.openai_sparring.enabled) { registerOpenAISparringTools(server); log("Registered OpenAI Sparring tools"); } }; // Register tools initially registerTools(); // Connect based on transport if (transport === 'stdio') { const stdioTransport = new StdioServerTransport(); await server.connect(stdioTransport); log("Connected via stdio"); } else { throw new Error(`Unsupported transport: ${transport}`); } } // Run the server main().catch((error) => { console.error("Fatal error:", error); process.exit(1); });