# EXA MCP Server Bug Fix ## Problem Summary The `exa_web_search_exa` and `exa_get_code_context_exa` tools were returning 400 errors on all requests, even though the EXA API itself worked perfectly when called directly with curl. ## Root Cause The issue was **NOT a bug in the exa-mcp-server package**. The source code is correct and properly formatted. **The actual problem**: The OpenCode configuration file used an environment variable reference `{env:EXA_API_KEY}` but the environment variable was not set in the shell where OpenCode runs. ## Configuration Files ### Before (BROKEN) `/Users/kempersc/.config/opencode/opencode.json`: ```json { "mcp": { "exa": { "type": "local", "command": ["npx", "-y", "exa-mcp-server"], "enabled": true, "environment": { "EXA_API_KEY": "{env:EXA_API_KEY}" ❌ This env var wasn't set } } } } ``` ### After (FIXED) `/Users/kempersc/.config/opencode/opencode.json`: ```json { "mcp": { "exa": { "type": "local", "command": ["npx", "-y", "exa-mcp-server"], "enabled": true, "environment": { "EXA_API_KEY": "dba69040-f87e-46a2-85d7-5b2e9fe17497" ✅ Direct API key } } } } ``` ## How the EXA MCP Server Works ### Source Code Analysis **Repository**: https://github.com/exa-labs/exa-mcp-server **Key files**: - `src/index.ts` - Main server initialization - `src/tools/webSearch.ts` - Web search tool implementation - `src/tools/exaCode.ts` - Code context search implementation - `src/tools/config.ts` - API configuration **API Configuration** (`src/tools/config.ts:1-11`): ```typescript export const API_CONFIG = { BASE_URL: 'https://api.exa.ai', ENDPOINTS: { SEARCH: '/search', RESEARCH_TASKS: '/research/v0/tasks', CONTEXT: '/context' }, DEFAULT_NUM_RESULTS: 8, DEFAULT_MAX_CHARACTERS: 2000 } as const; ``` **HTTP Request Format** (from `src/tools/webSearch.ts:24-52`): ```typescript const axiosInstance = axios.create({ baseURL: API_CONFIG.BASE_URL, headers: { 'accept': 'application/json', 'content-type': 'application/json', 'x-api-key': config?.exaApiKey || process.env.EXA_API_KEY || '' }, timeout: 25000 }); const searchRequest: ExaSearchRequest = { query, type: "auto", numResults: numResults || API_CONFIG.DEFAULT_NUM_RESULTS, contents: { text: { maxCharacters: API_CONFIG.DEFAULT_MAX_CHARACTERS }, livecrawl: 'preferred' } }; const response = await axiosInstance.post( API_CONFIG.ENDPOINTS.SEARCH, searchRequest, { timeout: 25000 } ); ``` This exactly matches our working curl command: ```bash curl -X POST "https://api.exa.ai/search" \ -H "Content-Type: application/json" \ -H "x-api-key: dba69040-f87e-46a2-85d7-5b2e9fe17497" \ -d '{"query": "Belgium ISIL registry", "numResults": 3}' ``` ## Why the Error Occurred When `EXA_API_KEY` environment variable is not set: 1. OpenCode spawns `npx -y exa-mcp-server` with `EXA_API_KEY=""` (empty string) 2. The axios request includes header: `x-api-key: ""` (empty) 3. EXA API rejects the request with **400 Bad Request** ## Solution **Option 1** (APPLIED): Set API key directly in OpenCode config - ✅ Simple, works immediately after OpenCode restart - ❌ API key visible in config file (but it's in your home directory) **Option 2**: Set shell environment variable globally ```bash # In ~/.zshrc or ~/.bashrc export EXA_API_KEY=dba69040-f87e-46a2-85d7-5b2e9fe17497 ``` - ✅ More secure (not in config files) - ❌ Requires shell restart, affects all processes **Option 3**: Load from project .env file - Would require modifying exa-mcp-server to load .env - Not practical for this use case ## Next Steps 1. **Restart OpenCode** to reload MCP server with new configuration 2. **Test the tools**: ``` Use exa_web_search_exa to search for "Belgium ISIL registry" ``` 3. **Verify** we get proper search results instead of 400 errors ## Verification Commands After restarting OpenCode, test with: ``` Search for "Belgium heritage institutions ISIL registry" ``` Expected: JSON results with Belgian GLAM institution URLs ## Source Code Findings The exa-mcp-server package (v3.0.7) is **correctly implemented**: - ✅ Proper HTTP headers (`x-api-key`) - ✅ Correct API endpoints (`/search`, `/context`) - ✅ Valid request formatting - ✅ Error handling with detailed messages - ✅ Timeout handling (25-30 seconds) No bugs found in the source code. The issue was purely configuration. --- **Date**: November 6, 2025 **Fixed by**: Configuration update to `/Users/kempersc/.config/opencode/opencode.json`