Web Search
searchSearch the web and receive a synthesized answer with source URLs for current information, documentation lookups, and research questions.
Instructions
Web search via Claude Code CLI using WebSearch and WebFetch tools. Searches the web and synthesizes a comprehensive answer with source URLs.
Use for: current information, documentation lookups, API references, comparing libraries, and research questions.
Cost: Typically ~$0.02-0.05/search with Sonnet.
Tips:
Ask specific, focused questions for best results.
Results include source URLs for verification.
Use maxResponseLength to control response verbosity.
Increase timeout for complex research queries that may require multiple web fetches.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query or question | |
| model | No | Model alias or full Claude model name | |
| sessionId | No | Claude session ID to resume with --resume | |
| noSessionPersistence | No | Disable session persistence for ephemeral print calls | |
| workingDirectory | No | Working directory for the CLI | |
| timeout | No | Timeout in milliseconds | |
| maxResponseLength | No | Soft limit on response length in words | |
| maxBudgetUsd | No | Maximum cost budget in USD for this call (passed to --max-budget-usd) | |
| effort | No | Effort level: low, medium, high, or max (default: medium for search) |
Implementation Reference
- src/tools/search.ts:32-77 (handler)The core handler function that executes the search tool logic. Resolves model, loads prompt, builds Claude CLI args with WebSearch/WebFetch tools, spawns Claude process, and parses the output.
export async function executeSearch(input: SearchInput): Promise<SearchResult> { const { query, maxResponseLength, sessionId, noSessionPersistence, maxBudgetUsd, effort } = input; const model = resolveModel("search", input.model); const timeout = clampTimeout(input.timeout, SEARCH_TIMEOUT); const cwd = await resolveCwd(input.workingDirectory); const prompt = loadPrompt("search.md", { QUERY: query, LENGTH_LIMIT: buildLengthLimit(maxResponseLength) || "Provide a focused synthesis. Aim for 500-1500 words unless the topic clearly warrants less.", }); const args = buildClaudeArgs({ model, fallbackModel: getFallbackModel(), maxBudgetUsd: resolveMaxBudget(maxBudgetUsd), effort: resolveEffort("search", effort), sessionId, noSessionPersistence, allowedTools: ["WebSearch", "WebFetch"], }); const result = await spawnClaude({ args, cwd, stdin: prompt, timeout }); if (result.timedOut) { return { response: tryParsePartial(result.stdout, result.stderr, timeout), model, timedOut: true, resolvedCwd: cwd, }; } const parsed = parseClaudeOutput(result.stdout, result.stderr); checkAndThrow(result, parsed); return { response: parsed.response, model, sessionId: parsed.sessionId, totalCostUsd: parsed.totalCostUsd, usage: parsed.usage, timedOut: false, resolvedCwd: cwd, }; } - src/tools/search.ts:8-18 (schema)Input schema/interface for the search tool.
export interface SearchInput { query: string; model?: string; sessionId?: string; noSessionPersistence?: boolean; workingDirectory?: string; timeout?: number; maxResponseLength?: number; maxBudgetUsd?: number; effort?: string; } - src/tools/search.ts:20-28 (schema)Output/result interface for the search tool.
export interface SearchResult { response: string; model?: string; sessionId?: string; totalCostUsd?: number; usage?: ClaudeUsage; timedOut: boolean; resolvedCwd: string; } - src/index.ts:234-292 (registration)Registers the 'search' tool on the MCP server with its name, schema, annotations, and handler callback that delegates to executeSearch.
server.registerTool( "search", { title: "Web Search", description: searchDescription, inputSchema: { query: z.string().describe("Search query or question"), model: z.string().optional().describe("Model alias or full Claude model name"), sessionId: z.string().optional().describe("Claude session ID to resume with --resume"), noSessionPersistence: z.boolean().optional().describe("Disable session persistence for ephemeral print calls"), workingDirectory: z.string().optional().describe("Working directory for the CLI"), timeout: z.number().optional().describe("Timeout in milliseconds"), maxResponseLength: z.number().int().positive().optional().describe("Soft limit on response length in words"), maxBudgetUsd: z.number().positive().optional().describe("Maximum cost budget in USD for this call (passed to --max-budget-usd)"), effort: z.string().optional().describe("Effort level: low, medium, high, or max (default: medium for search)"), }, annotations: searchAnnotations, }, async (input, extra) => { const start = Date.now(); const heartbeat = maybeStartHeartbeat( extra._meta as { progressToken?: string | number } | undefined, extra.sendNotification as ProgressNotificationSender, ); try { const result = await executeSearch(input); const sessionId = result.sessionId ?? input.sessionId; if (sessionId) { persist(sessionStore, sessionId, result); } const text = result.timedOut ? `${result.response}\n\n---\n(timed out)` : result.response; return { content: [{ type: "text" as const, text }], _meta: buildMeta({ durationMs: Date.now() - start, model: result.model, sessionId: result.sessionId, totalCostUsd: result.totalCostUsd, usage: result.usage, timedOut: result.timedOut, }), }; } catch (e) { console.error("[search]", e); return { content: [{ type: "text" as const, text: `Error: ${getErrorMessage(e)}` }], isError: true, _meta: buildMeta({ durationMs: Date.now() - start }), }; } finally { heartbeat.stop(); } }, ); - src/descriptions.ts:23-33 (helper)Rich description string for the search tool, used during registration.
export const searchDescription = `Web search via Claude Code CLI using WebSearch and WebFetch tools. Searches the web and synthesizes a comprehensive answer with source URLs. Use for: current information, documentation lookups, API references, comparing libraries, and research questions. Cost: Typically ~$0.02-0.05/search with Sonnet. Tips: - Ask specific, focused questions for best results. - Results include source URLs for verification. - Use maxResponseLength to control response verbosity. - Increase timeout for complex research queries that may require multiple web fetches.`;