Skip to main content
Glama

Exa MCP Server

by joerup
http.ts4.23 kB
import { createServer, IncomingMessage, ServerResponse } from 'http'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import { createStandaloneServer } from '../server.js'; import { randomUUID } from 'crypto'; /** Session storage for streamable HTTP connections */ const sessions = new Map<string, { transport: StreamableHTTPServerTransport; server: any }>(); /** * Start HTTP transport server for cloud deployment * @param config Server configuration */ export function startHttpTransport(config: { apiKey: string; port: number; enabledTools?: string[]; debug?: boolean; }): void { const httpServer = createServer(); httpServer.on('request', async (req, res) => { const url = new URL(req.url!, `http://${req.headers.host}`); switch (url.pathname) { case '/mcp': await handleMcpRequest(req, res, config); break; case '/health': handleHealthCheck(res); break; default: handleNotFound(res); } }); httpServer.listen(config.port, 'localhost', () => { console.log(`Exa MCP Server listening on http://localhost:${config.port}`); console.log('Put this in your client config:'); console.log(JSON.stringify({ mcpServers: { exa: { url: `http://localhost:${config.port}/mcp` } } }, null, 2)); }); } /** * Handles MCP protocol requests * @param req HTTP request * @param res HTTP response * @param config Server configuration */ async function handleMcpRequest( req: IncomingMessage, res: ServerResponse, config: { apiKey: string; port: number; enabledTools?: string[]; debug?: boolean; } ): Promise<void> { const sessionId = req.headers['mcp-session-id'] as string | undefined; if (sessionId) { const session = sessions.get(sessionId); if (!session) { res.statusCode = 404; res.end('Session not found'); return; } return await session.transport.handleRequest(req, res); } if (req.method === 'POST') { await createNewSession(req, res, config); return; } res.statusCode = 400; res.end('Invalid request'); } /** * Creates a new MCP session for HTTP transport * @param req HTTP request * @param res HTTP response * @param config Server configuration */ async function createNewSession( req: IncomingMessage, res: ServerResponse, config: { apiKey: string; port: number; enabledTools?: string[]; debug?: boolean; } ): Promise<void> { const serverInstance = createStandaloneServer(config.apiKey, config.enabledTools, config.debug); const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (sessionId) => { sessions.set(sessionId, { transport, server: serverInstance }); console.log('New Exa session created:', sessionId); } }); transport.onclose = () => { if (transport.sessionId) { sessions.delete(transport.sessionId); console.log('Exa session closed:', transport.sessionId); } }; try { await serverInstance.connect(transport); await transport.handleRequest(req, res); } catch (error) { console.error('Streamable HTTP connection error:', error); res.statusCode = 500; res.end('Internal server error'); } } /** * Handles health check endpoint * @param res HTTP response */ function handleHealthCheck(res: ServerResponse): void { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ status: 'healthy', service: 'exa-search-server', timestamp: new Date().toISOString() })); } /** * Handles 404 Not Found responses * @param res HTTP response */ function handleNotFound(res: ServerResponse): void { res.writeHead(404, { 'Content-Type': 'text/plain' }); res.end('Not Found'); }

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/joerup/exa-mcp'

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