Skip to main content
Glama

Google Trends MCP Server

by ainightshift
trends.ts3.18 kB
const SEARCH_API_URL = "https://www.searchapi.io/api/v1/search"; export type TrendPoint = { dateLabel: string; timestamp: number; value: number; }; export class SearchApiError extends Error { status: number; details?: string; constructor(message: string, status: number, details?: string) { super(message); this.name = "SearchApiError"; this.status = status; this.details = details; } } type FetchTrendsParams = { term: string; geo?: string; category?: string; apiKey?: string; }; type TimelineDataPoint = { date: string; timestamp: string; values?: Array<{ value?: string; extracted_value?: number; }>; }; type TrendsResponse = { interest_over_time?: { timeline_data?: TimelineDataPoint[]; }; message?: string; error?: string; }; const THIN_SPACE_PATTERN = /\u2009/g; export async function fetchTrendSeries({ term, geo, category, apiKey, }: FetchTrendsParams): Promise<TrendPoint[]> { const resolvedKey = apiKey ?? process.env.SEARCH_API_KEY; if (!resolvedKey) { throw new SearchApiError( "SEARCH_API_KEY is not configured on the server.", 500, ); } const trimmedTerm = term.trim(); if (!trimmedTerm) { throw new SearchApiError("Search term is required.", 400); } const params = new URLSearchParams({ engine: "google_trends", q: trimmedTerm, date: "now 12-m", data_type: "TIMESERIES", }); if (geo?.trim()) { params.set("geo", geo.trim()); } if (category?.trim()) { params.set("cat", category.trim()); } let response: Response; try { response = await fetch(`${SEARCH_API_URL}?${params.toString()}`, { headers: { Accept: "application/json", Authorization: `Bearer ${resolvedKey}`, }, }); } catch (error) { const details = error instanceof Error ? error.message : "Unknown network error."; throw new SearchApiError( "Unable to reach SearchAPI.", 502, details || undefined, ); } if (!response.ok) { let details: string | undefined; try { const payload = (await response.json()) as TrendsResponse; details = payload.error ?? payload.message; } catch { details = undefined; } throw new SearchApiError( "Failed to retrieve trends data from SearchAPI.", response.status, details, ); } const data = (await response.json()) as TrendsResponse; const timelineData = data.interest_over_time?.timeline_data ?? []; return timelineData.map((entry) => { const timestampSeconds = Number(entry.timestamp); const derivedTimestamp = Number.isFinite(timestampSeconds) ? timestampSeconds * 1000 : Date.parse(entry.date); const firstValue = entry.values?.[0]; const extracted = typeof firstValue?.extracted_value === "number" ? firstValue.extracted_value : Number(firstValue?.value ?? 0); return { dateLabel: entry.date.replace(THIN_SPACE_PATTERN, " "), timestamp: Number.isFinite(derivedTimestamp) ? derivedTimestamp : Date.now(), value: Number.isFinite(extracted) ? extracted : 0, }; }); }

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/ainightshift/google_trends_mcp'

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