Skip to main content
Glama

web_search_exa

Perform real-time web searches and scrape content from URLs using AI-powered search. Configure result counts and search types to find relevant information.

Instructions

Search the web using Exa AI - performs real-time web searches and can scrape content from specific URLs. Supports configurable result counts and returns the content from the most relevant websites.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesWebsearch query
numResultsNoNumber of search results to return (default: 8)
livecrawlNoLive crawl mode - 'fallback': use live crawling as backup if cached content unavailable, 'preferred': prioritize live crawling (default: 'fallback')
typeNoSearch type - 'auto': balanced search (default), 'fast': quick results, 'deep': comprehensive search
contextMaxCharactersNoMaximum characters for context string optimized for LLMs (default: 10000)

Implementation Reference

  • Async handler that performs the web search using Exa API: logs the request, sends POST with query and config, processes results as JSON, handles axios and generic errors with appropriate responses.
    handler: async ({ query, numResults }, extra) => { const requestId = `web_search_exa-${Date.now()}-${Math.random().toString(36).substring(2, 7)}`; const logger = createRequestLogger(requestId, 'web_search_exa'); logger.start(query); try { // Create a fresh axios instance for each request const axiosInstance = axios.create({ baseURL: API_CONFIG.BASE_URL, headers: { 'accept': 'application/json', 'content-type': 'application/json', 'x-api-key': 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: 'always' } }; logger.log("Sending request to Exa API"); const response = await axiosInstance.post<ExaSearchResponse>( API_CONFIG.ENDPOINTS.SEARCH, searchRequest, { timeout: 25000 } ); logger.log("Received response from Exa API"); if (!response.data || !response.data.results) { logger.log("Warning: Empty or invalid response from Exa API"); return { content: [{ type: "text" as const, text: "No search results found. Please try a different query." }] }; } logger.log(`Found ${response.data.results.length} results`); const result = { content: [{ type: "text" as const, text: JSON.stringify(response.data, null, 2) }] }; logger.complete(); return result; } catch (error) { logger.error(error); if (axios.isAxiosError(error)) { // Handle Axios errors specifically const statusCode = error.response?.status || 'unknown'; const errorMessage = error.response?.data?.message || error.message; logger.log(`Axios error (${statusCode}): ${errorMessage}`); return { content: [{ type: "text" as const, text: `Search error (${statusCode}): ${errorMessage}` }], isError: true, }; } // Handle generic errors return { content: [{ type: "text" as const, text: `Search error: ${error instanceof Error ? error.message : String(error)}` }], isError: true, }; } },
  • Zod input schema defining 'query' as required string and 'numResults' as optional number.
    schema: { query: z.string().describe("Search query"), numResults: z.number().optional().describe("Number of search results to return (default: 5)") },
  • Registers the 'web_search_exa' tool in the toolRegistry with name, description, schema, handler function, and enabled flag.
    toolRegistry["web_search_exa"] = { name: "web_search_exa", description: "Search the web using Exa AI - performs real-time web searches and can scrape content from specific URLs. Supports configurable result counts and returns the content from the most relevant websites.", schema: { query: z.string().describe("Search query"), numResults: z.number().optional().describe("Number of search results to return (default: 5)") }, handler: async ({ query, numResults }, extra) => { const requestId = `web_search_exa-${Date.now()}-${Math.random().toString(36).substring(2, 7)}`; const logger = createRequestLogger(requestId, 'web_search_exa'); logger.start(query); try { // Create a fresh axios instance for each request const axiosInstance = axios.create({ baseURL: API_CONFIG.BASE_URL, headers: { 'accept': 'application/json', 'content-type': 'application/json', 'x-api-key': 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: 'always' } }; logger.log("Sending request to Exa API"); const response = await axiosInstance.post<ExaSearchResponse>( API_CONFIG.ENDPOINTS.SEARCH, searchRequest, { timeout: 25000 } ); logger.log("Received response from Exa API"); if (!response.data || !response.data.results) { logger.log("Warning: Empty or invalid response from Exa API"); return { content: [{ type: "text" as const, text: "No search results found. Please try a different query." }] }; } logger.log(`Found ${response.data.results.length} results`); const result = { content: [{ type: "text" as const, text: JSON.stringify(response.data, null, 2) }] }; logger.complete(); return result; } catch (error) { logger.error(error); if (axios.isAxiosError(error)) { // Handle Axios errors specifically const statusCode = error.response?.status || 'unknown'; const errorMessage = error.response?.data?.message || error.message; logger.log(`Axios error (${statusCode}): ${errorMessage}`); return { content: [{ type: "text" as const, text: `Search error (${statusCode}): ${errorMessage}` }], isError: true, }; } // Handle generic errors return { content: [{ type: "text" as const, text: `Search error: ${error instanceof Error ? error.message : String(error)}` }], isError: true, }; } }, enabled: true // Enabled by default };
Install Server

Other 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/jackedelic/exa-mcp-server'

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