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

TableJSON 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

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;
      }
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. 'Search the web' implies a read-only operation, but it doesn't disclose important behavioral traits like rate limits, authentication requirements, error handling, response format, or whether it performs live web searches versus cached results. The description is too minimal for a tool with 9 parameters.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise - a single 6-word sentence that states the core purpose without any fluff. It's front-loaded and wastes no words, though this conciseness comes at the cost of completeness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex web search tool with 9 parameters, no annotations, and no output schema, the description is severely incomplete. It doesn't explain what kind of results to expect, how they're formatted, whether there's pagination, or any behavioral constraints. The minimal description fails to provide adequate context for effective tool use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds no parameter-specific information beyond what's already in the schema (which has 100% coverage). It doesn't explain how parameters interact, provide usage examples, or clarify semantics like what 'neural' search means versus 'keyword'. With complete schema coverage, the baseline is 3, but the description doesn't add meaningful value.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Search the web') and the resource/API being used ('using Exa API'), which is specific and unambiguous. It doesn't explicitly distinguish from sibling tools like 'exa_answer' or other search-related tools, but the verb+resource combination is clear enough for basic understanding.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives like 'exa_answer' (which appears to be a sibling tool) or other search-related tools in the list. There's no mention of use cases, prerequisites, or comparisons with similar tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Related Tools

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