Skip to main content
Glama

exa_search

Search the web with precision using the Exa API. Filter results by date, domain, category, or search type to retrieve relevant information efficiently.

Instructions

Search the web using Exa API

Input Schema

NameRequiredDescriptionDefault
categoryNoFilter results by content categorygeneral
end_published_dateNoFilter results published before this date (ISO format)
exclude_domainsNoExclude results from these domains
include_domainsNoOnly include results from these domains
live_crawlNoWhen to use live crawling: 'always' or 'fallback' (when cached not available)always
num_resultsNoNumber of results to return (1-100)
queryYesThe search query to execute
start_published_dateNoFilter results published after this date (ISO format)
typeNoSearch type: auto (default), keyword (exact matching), or neural (semantic search)auto

Input Schema (JSON Schema)

{ "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "category": { "default": "general", "description": "Filter results by content category", "enum": [ "general", "company", "research paper", "news", "pdf", "github", "tweet", "personal site", "linkedin profile", "financial report" ], "type": "string" }, "end_published_date": { "description": "Filter results published before this date (ISO format)", "type": "string" }, "exclude_domains": { "description": "Exclude results from these domains", "items": { "type": "string" }, "type": "array" }, "include_domains": { "description": "Only include results from these domains", "items": { "type": "string" }, "type": "array" }, "live_crawl": { "default": "always", "description": "When to use live crawling: 'always' or 'fallback' (when cached not available)", "enum": [ "always", "fallback" ], "type": "string" }, "num_results": { "default": 5, "description": "Number of results to return (1-100)", "maximum": 100, "minimum": 1, "type": "number" }, "query": { "description": "The search query to execute", "type": "string" }, "start_published_date": { "description": "Filter results published after this date (ISO format)", "type": "string" }, "type": { "default": "auto", "description": "Search type: auto (default), keyword (exact matching), or neural (semantic search)", "enum": [ "auto", "keyword", "neural" ], "type": "string" } }, "required": [ "query" ], "type": "object" }

Implementation Reference

  • The execute handler for the 'exa_search' tool. Performs web search using Exa JS SDK, transforms parameters, checks for API key, handles errors, and returns JSON results.
    execute: async (params, context) => { const log = context && context.log ? context.log : { info() {}, error() {}, warn() {}, debug() {} }; try { // Only check for API key when actually executing the search // This allows tool listing without requiring the API key if (!process.env.EXA_API_KEY) { return JSON.stringify({ error: 'EXA_API_KEY environment variable is not set. Please set it in your configuration before using this tool.' }); } const exa = new Exa(process.env.EXA_API_KEY); // Transform parameters to match Exa API const searchParams = { numResults: params.num_results, type: params.type, // This should match the Exa API's expected values startPublishedDate: params.start_published_date, endPublishedDate: params.end_published_date, includeDomains: params.include_domains, excludeDomains: params.exclude_domains, category: params.category !== 'general' ? params.category : undefined // Only set category if not 'general' }; const results = await exa.search(params.query, searchParams); return JSON.stringify(results); } catch (error) { const errorMessage = `Error executing Exa search: ${error}`; log.error(errorMessage); return JSON.stringify({ error: errorMessage }); } } });
  • Zod input schema defining parameters for the exa_search tool: query, num_results, type, date filters, domain filters, category, and live_crawl options.
    parameters: z.object({ query: z.string().describe("The search query to execute"), num_results: z.number().min(1).max(100).default(5).describe("Number of results to return (1-100)"), type: z.enum(['auto', 'keyword', 'neural']).default('auto').describe("Search type: auto (default), keyword (exact matching), or neural (semantic search)"), start_published_date: z.string().optional().describe("Filter results published after this date (ISO format)"), end_published_date: z.string().optional().describe("Filter results published before this date (ISO format)"), include_domains: z.array(z.string()).optional().describe("Only include results from these domains"), exclude_domains: z.array(z.string()).optional().describe("Exclude results from these domains"), category: z.enum([ 'general', 'company', 'research paper', 'news', 'pdf', 'github', 'tweet', 'personal site', 'linkedin profile', 'financial report' ]).default('general').describe("Filter results by content category"), live_crawl: z.enum(['always', 'fallback']).default('always').describe("When to use live crawling: 'always' or 'fallback' (when cached not available)") }),
  • Registers the 'exa_search' tool on the FastMCP server, defining name, description, schema, and handler.
    export function registerExaSearchTool(server: FastMCP): void { server.addTool({ name: 'exa_search', description: 'Search the web using Exa API', parameters: z.object({ query: z.string().describe("The search query to execute"), num_results: z.number().min(1).max(100).default(5).describe("Number of results to return (1-100)"), type: z.enum(['auto', 'keyword', 'neural']).default('auto').describe("Search type: auto (default), keyword (exact matching), or neural (semantic search)"), start_published_date: z.string().optional().describe("Filter results published after this date (ISO format)"), end_published_date: z.string().optional().describe("Filter results published before this date (ISO format)"), include_domains: z.array(z.string()).optional().describe("Only include results from these domains"), exclude_domains: z.array(z.string()).optional().describe("Exclude results from these domains"), category: z.enum([ 'general', 'company', 'research paper', 'news', 'pdf', 'github', 'tweet', 'personal site', 'linkedin profile', 'financial report' ]).default('general').describe("Filter results by content category"), live_crawl: z.enum(['always', 'fallback']).default('always').describe("When to use live crawling: 'always' or 'fallback' (when cached not available)") }), execute: async (params, context) => { const log = context && context.log ? context.log : { info() {}, error() {}, warn() {}, debug() {} }; try { // Only check for API key when actually executing the search // This allows tool listing without requiring the API key if (!process.env.EXA_API_KEY) { return JSON.stringify({ error: 'EXA_API_KEY environment variable is not set. Please set it in your configuration before using this tool.' }); } const exa = new Exa(process.env.EXA_API_KEY); // Transform parameters to match Exa API const searchParams = { numResults: params.num_results, type: params.type, // This should match the Exa API's expected values startPublishedDate: params.start_published_date, endPublishedDate: params.end_published_date, includeDomains: params.include_domains, excludeDomains: params.exclude_domains, category: params.category !== 'general' ? params.category : undefined // Only set category if not 'general' }; const results = await exa.search(params.query, searchParams); return JSON.stringify(results); } catch (error) { const errorMessage = `Error executing Exa search: ${error}`; log.error(errorMessage); return JSON.stringify({ error: errorMessage }); } } }); }
  • Higher-level registration function that calls registerExaSearchTool to add the tool to the server.
    export function registerResearchTools(server: FastMCP): void { // Register Exa search tool registerExaSearchTool(server); // Register Exa answer tool registerExaAnswerTool(server); // No logging needed }
  • Helper wrapper function for exa_search execution that suppresses console output during tool call and formats errors properly.
    async function callExaSearch( originalExecute: (params: any, context: any) => Promise<any>, params: any, context: any ): Promise<any> { // Store original console functions const originalLog = console.log; const originalError = console.error; try { // Temporarily disable console output to prevent it from mixing with JSON console.log = () => {}; console.error = () => {}; // Execute the tool with suppressed logging const result = await originalExecute(params, { ...context, direct: true }); return result; } catch (error: any) { // Return properly formatted error JSON instead of throwing return JSON.stringify({ status: 'ERROR', message: `Error executing Exa search: ${error.message}`, query: params.query }); } finally { // Always restore original console functions console.log = originalLog; console.error = originalError; } }

Latest Blog Posts

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/flight505/mcp-think-tank'

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