search_volume
Retrieve monthly search volume, CPC, competition, and trend data for up to 1,000 keywords. Supports local SEO keyword research by geographic location and language.
Instructions
Get search volume and keyword metrics for up to 1000 keywords. Returns monthly search volume, CPC, competition, and trend data. Costs 1 credit per 50 keywords.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| keywords | Yes | Array of keywords to analyze | |
| location | Yes | Geographic location (e.g. "Orchard Park, NY") | |
| language | No | Language code. Default: "en" |
Implementation Reference
- src/tools/keywords.ts:21-28 (handler)The handler function for the search_volume tool. Calls the API endpoint /v1/keywords/search-volume with keywords, location, and optional language, then formats the result.
withErrorHandling(async ({ keywords, location, language }) => { const result = await callApi( "/v1/keywords/search-volume", { keywords, location, ...(language && { language }) }, getAuth() ); return { content: [{ type: "text" as const, text: formatResult(result.data, result) }] }; }) - src/tools/keywords.ts:15-20 (schema)Zod schema defining the input parameters for search_volume: keywords (array of 1-1000 strings), location (string), and optional language (string).
{ keywords: z.array(z.string().min(1)).min(1).max(1000).describe("Array of keywords to analyze"), location: z.string().min(1).describe('Geographic location (e.g. "Orchard Park, NY")'), language: z.string().optional().describe('Language code. Default: "en"'), }, READ_ONLY, - src/tools/keywords.ts:12-29 (registration)Registration of the search_volume tool on the MCP server via server.tool(), inside registerKeywordTools().
server.tool( "search_volume", "Get search volume and keyword metrics for up to 1000 keywords. Returns monthly search volume, CPC, competition, and trend data. Costs 1 credit per 50 keywords.", { keywords: z.array(z.string().min(1)).min(1).max(1000).describe("Array of keywords to analyze"), location: z.string().min(1).describe('Geographic location (e.g. "Orchard Park, NY")'), language: z.string().optional().describe('Language code. Default: "en"'), }, READ_ONLY, withErrorHandling(async ({ keywords, location, language }) => { const result = await callApi( "/v1/keywords/search-volume", { keywords, location, ...(language && { language }) }, getAuth() ); return { content: [{ type: "text" as const, text: formatResult(result.data, result) }] }; }) ); - src/api-client.ts:143-158 (helper)Helper wrapper used to catch errors in the handler and return them as structured MCP error content.
export function withErrorHandling<T>( fn: (args: T) => Promise<ToolResult> ): (args: T) => Promise<ToolResult> { return async (args) => { try { return await fn(args); } catch (err) { const message = err instanceof Error ? err.message : String(err); console.error(`[mcp] Tool error: ${message}`); return { content: [{ type: "text" as const, text: `Error: ${message}` }], isError: true, }; } }; } - src/api-client.ts:132-138 (helper)Helper function that formats the API response data along with credit usage metadata into a human-readable string.
export function formatResult( data: unknown, meta: { credits_used: number; credits_remaining: number; cached: boolean } ): string { const metaLine = `[${meta.credits_used} credit${meta.credits_used !== 1 ? "s" : ""} used | ${meta.credits_remaining} remaining${meta.cached ? " | cached" : ""}]`; return `${metaLine}\n\n${JSON.stringify(data, null, 2)}`; }