x402_web_search
Search the web for information and get ranked results with titles, URLs, and snippets. Use domain filters to focus research and optionally include synthesized answers summarizing findings.
Instructions
Search the web and return ranked results via Tavily — title, URL, snippet, and relevance score. Price: $0.01 USDC per search (paid mode) | Free test: returns fixture data.
Optional synthesized answer summarizing results. Use include_domains/exclude_domains for focused research. Per-wallet daily limit: 50 queries (resets midnight UTC). Without X402_PRIVATE_KEY, only the free test endpoint is available.
Returns: query, results array (title, url, snippet, score), optional answer field.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query (max 400 chars) | |
| max_results | No | Number of results to return (1-10, default: 5) | |
| include_answer | No | Include a synthesized answer above the results (may be null if Tavily cannot synthesize) | |
| include_domains | No | Restrict results to these domains only (max 20) | |
| exclude_domains | No | Exclude these domains from results (max 20) |
Implementation Reference
- src/index.ts:645-692 (handler)The x402_web_search tool handler is defined in src/index.ts. It handles both paid searches (via Tavily if PRIVATE_KEY is set) and a free test mode.
server.tool( "x402_web_search", `Search the web and return ranked results via Tavily — title, URL, snippet, and relevance score. Price: $0.01 USDC per search (paid mode) | Free test: returns fixture data. Optional synthesized answer summarizing results. Use include_domains/exclude_domains for focused research. Per-wallet daily limit: 50 queries (resets midnight UTC). Without X402_PRIVATE_KEY, only the free test endpoint is available. Returns: query, results array (title, url, snippet, score), optional answer field.`, { query: z.string().min(1).max(400).describe("Search query (max 400 chars)"), max_results: z.number().int().min(1).max(10).default(5) .describe("Number of results to return (1-10, default: 5)"), include_answer: z.boolean().default(false) .describe("Include a synthesized answer above the results (may be null if Tavily cannot synthesize)"), include_domains: z.array(z.string()).max(20).optional() .describe("Restrict results to these domains only (max 20)"), exclude_domains: z.array(z.string()).max(20).optional() .describe("Exclude these domains from results (max 20)"), }, async (params) => { const base = APIS.search.baseUrl; try { const usePaid = !!PRIVATE_KEY; if (usePaid) { const payload: Record<string, unknown> = { query: params.query, max_results: params.max_results, include_answer: params.include_answer, }; if (params.include_domains) payload.include_domains = params.include_domains; if (params.exclude_domains) payload.exclude_domains = params.exclude_domains; const data = await apiPost(base, "/search", payload, true); return textResult({ mode: "paid", cost: "$0.01", ...data }); } else { const data = await apiGet(base, "/search/test"); return textResult({ mode: "free_test", note: "Free test — returns fixture data. Set X402_PRIVATE_KEY for live web search.", ...data, }); } } catch (err: any) { return errorResult(err.message); } } );