4.5 KiB
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:
{
"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:
{
"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 initializationsrc/tools/webSearch.ts- Web search tool implementationsrc/tools/exaCode.ts- Code context search implementationsrc/tools/config.ts- API configuration
API Configuration (src/tools/config.ts:1-11):
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):
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<ExaSearchResponse>(
API_CONFIG.ENDPOINTS.SEARCH,
searchRequest,
{ timeout: 25000 }
);
This exactly matches our working curl command:
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:
- OpenCode spawns
npx -y exa-mcp-serverwithEXA_API_KEY=""(empty string) - The axios request includes header:
x-api-key: ""(empty) - 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
# 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
- Restart OpenCode to reload MCP server with new configuration
- Test the tools:
Use exa_web_search_exa to search for "Belgium ISIL registry" - 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