search
Search the web and retrieve AI-synthesized answers, raw SERP results, or a combination of both. Choose from three modes to control output type and cost.
Instructions
Search the web. Returns AI-synthesized answers, raw SERP results, or both. Cost: serp 1 credit, ai 2 credits, deep 3 credits.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query | |
| mode | No | ai (2 credits, synthesized answer), serp (1 credit, raw links), or deep (3 credits, both) | ai |
| num_results | No | Max results for serp/deep mode |
Implementation Reference
- src/index.ts:36-46 (schema)Input schema definition for the 'search' tool, defining query (string), mode (optional string with default 'ai'), and num_results (optional number with default 10).
const CAPABILITIES: CapabilityDef[] = [ { name: "search", description: "Search the web. Returns AI-synthesized answers, raw SERP results, or both. Cost: serp 1 credit, ai 2 credits, deep 3 credits.", inputSchema: { query: z.string().describe("Search query"), mode: z.string().optional().default("ai").describe("ai (2 credits, synthesized answer), serp (1 credit, raw links), or deep (3 credits, both)"), num_results: z.number().optional().default(10).describe("Max results for serp/deep mode"), }, }, { - src/index.ts:247-259 (registration)Registration of the 'search' tool (and all other capabilities) via server.registerTool(). The loop iterates over CAPABILITIES and registers each with its name, description, inputSchema, and an async handler that delegates to callSuprsonic.
for (const cap of CAPABILITIES) { // Cast inputSchema to avoid TS2589 (excessively deep type instantiation from Zod chains) server.registerTool( cap.name, { description: cap.description, inputSchema: cap.inputSchema as any, }, async (args: any): Promise<CallToolResult> => { return callSuprsonic(cap.name, args as Record<string, unknown>); }, ); } - src/index.ts:183-234 (handler)The callSuprsonic function is the actual handler for all tools including 'search'. It sends a POST request to the Suprsonic API with the capability name and params, then formats the response.
async function callSuprsonic(capability: string, params: Record<string, unknown>): Promise<CallToolResult> { if (!API_KEY) { return { content: [{ type: "text", text: "Error: SUPRSONIC_API_KEY environment variable is not set. Get your key at https://suprsonic.ai/app/apis" }], isError: true, }; } try { const resp = await fetch(`${BASE_URL}/v1/agent`, { method: "POST", headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ capability, params }), }); const result = await resp.json() as any; // Handle non-envelope responses (401, 429, etc. return {"detail": ...}) if (result.detail && result.success === undefined) { const msg = typeof result.detail === "object" ? (result.detail.title || result.detail.detail || JSON.stringify(result.detail)) : String(result.detail); return { content: [{ type: "text", text: `Error (HTTP ${resp.status}): ${msg}` }], isError: true, }; } if (!result.success) { const errMsg = result.error?.detail || result.error?.title || "Request failed"; return { content: [{ type: "text", text: `Error: ${errMsg}` }], isError: true, }; } const text = JSON.stringify(result.data, null, 2); const meta = result.metadata ? `\n\n[Provider: ${(result.metadata as any).provider_used || "unknown"}, ${(result.metadata as any).response_time_ms || 0}ms, ${result.credits_used || 0} credits]` : ""; return { content: [{ type: "text", text: text + meta }], }; } catch (err) { return { content: [{ type: "text", text: `Network error: ${err instanceof Error ? err.message : String(err)}` }], isError: true, }; } }