Skip to main content
Glama
mackenly

MCP Fathom Analytics

by mackenly

get-aggregation

Retrieve aggregated analytics data from Fathom Analytics to analyze website performance, track user behavior, and generate custom reports with flexible filtering and grouping options.

Instructions

Get aggregated analytics data from Fathom

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
entityYesThe entity to aggregate (pageview or event)
entity_idYesID of the entity (site ID or event ID)
aggregatesYesComma-separated list of aggregates to include (visits,uniques,pageviews,avg_duration,bounce_rate,conversions,unique_conversions,value)
date_groupingNoOptional date grouping
field_groupingNoComma-separated fields to group by (e.g., hostname,pathname)
sort_byNoField to sort by (e.g., pageviews:desc)
timezoneNoTimezone for date calculations (default: UTC)
date_fromYesStart date (e.g., 2025-01-01 00:00:00 or 2025-01-01)
date_toYesEnd date (e.g., 2025-12-31 23:59:59 or 2025-12-31)
limitNoLimit on number of results
filtersNoArray of filter objects

Implementation Reference

  • The handler function that executes the get-aggregation tool: calls Fathom API for aggregation data, formats results into readable text, handles empty data and errors.
    async (params: AggregationParams) => { try { const aggregationData = await fathomClient.api.reports.aggregation(params); // Check if data exists and is a proper array if (!aggregationData || !Array.isArray(aggregationData)) { return { content: [ { type: "text", text: "No aggregation data found for the given parameters.", }, ], }; } if (aggregationData.length === 0) { return { content: [ { type: "text", text: "No aggregation data found for the given parameters.", }, ], }; } // Format the aggregation results in a readable way let resultText = `Aggregation Results (${aggregationData.length} entries):\n\n`; // Get all possible keys from all data entries const allKeys = new Set<string>(); aggregationData.forEach(item => { if (item) { Object.keys(item).forEach(key => allKeys.add(key)); } }); // Format each data entry aggregationData.forEach((item, index) => { if (!item) return; resultText += `Entry ${index + 1}:\n`; Array.from(allKeys).sort().forEach(key => { if (item[key] !== undefined) { resultText += `${key}: ${item[key]}\n`; } }); resultText += "---\n\n"; }); return { content: [ { type: "text", text: resultText, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to retrieve aggregation data: ${error instanceof FathomApiError ? `${error.status}: ${error.message}` : String(error)}`, }, ], }; } },
  • Zod schema defining parameters for the get-aggregation tool, including entity, aggregates, dates, filters, etc.
    { entity: z.enum(["pageview", "event"]).describe("The entity to aggregate (pageview or event)"), entity_id: z.string().describe("ID of the entity (site ID or event ID)"), aggregates: z.string().describe("Comma-separated list of aggregates to include (visits,uniques,pageviews,avg_duration,bounce_rate,conversions,unique_conversions,value)"), date_grouping: z.enum(["hour", "day", "month", "year"]).optional().describe("Optional date grouping"), field_grouping: z.string().optional().describe("Comma-separated fields to group by (e.g., hostname,pathname)"), sort_by: z.string().optional().describe("Field to sort by (e.g., pageviews:desc)"), timezone: z.string().optional().describe("Timezone for date calculations (default: UTC)"), date_from: z.string().describe("Start date (e.g., 2025-01-01 00:00:00 or 2025-01-01)"), date_to: z.string().describe("End date (e.g., 2025-12-31 23:59:59 or 2025-12-31)"), limit: z.number().positive().optional().describe("Limit on number of results"), filters: z.array( z.object({ property: z.string(), operator: z.enum(["is", "is not", "is like", "is not like"]), value: z.string(), }) ).optional().describe("Array of filter objects"), },
  • Registration function that sets up the get-aggregation tool on the MCP server using server.tool().
    export function registerAggregationTool(server: McpServer, fathomClient: FathomApi): void { server.tool( "get-aggregation", "Get aggregated analytics data from Fathom", { entity: z.enum(["pageview", "event"]).describe("The entity to aggregate (pageview or event)"), entity_id: z.string().describe("ID of the entity (site ID or event ID)"), aggregates: z.string().describe("Comma-separated list of aggregates to include (visits,uniques,pageviews,avg_duration,bounce_rate,conversions,unique_conversions,value)"), date_grouping: z.enum(["hour", "day", "month", "year"]).optional().describe("Optional date grouping"), field_grouping: z.string().optional().describe("Comma-separated fields to group by (e.g., hostname,pathname)"), sort_by: z.string().optional().describe("Field to sort by (e.g., pageviews:desc)"), timezone: z.string().optional().describe("Timezone for date calculations (default: UTC)"), date_from: z.string().describe("Start date (e.g., 2025-01-01 00:00:00 or 2025-01-01)"), date_to: z.string().describe("End date (e.g., 2025-12-31 23:59:59 or 2025-12-31)"), limit: z.number().positive().optional().describe("Limit on number of results"), filters: z.array( z.object({ property: z.string(), operator: z.enum(["is", "is not", "is like", "is not like"]), value: z.string(), }) ).optional().describe("Array of filter objects"), }, async (params: AggregationParams) => { try { const aggregationData = await fathomClient.api.reports.aggregation(params); // Check if data exists and is a proper array if (!aggregationData || !Array.isArray(aggregationData)) { return { content: [ { type: "text", text: "No aggregation data found for the given parameters.", }, ], }; } if (aggregationData.length === 0) { return { content: [ { type: "text", text: "No aggregation data found for the given parameters.", }, ], }; } // Format the aggregation results in a readable way let resultText = `Aggregation Results (${aggregationData.length} entries):\n\n`; // Get all possible keys from all data entries const allKeys = new Set<string>(); aggregationData.forEach(item => { if (item) { Object.keys(item).forEach(key => allKeys.add(key)); } }); // Format each data entry aggregationData.forEach((item, index) => { if (!item) return; resultText += `Entry ${index + 1}:\n`; Array.from(allKeys).sort().forEach(key => { if (item[key] !== undefined) { resultText += `${key}: ${item[key]}\n`; } }); resultText += "---\n\n"; }); return { content: [ { type: "text", text: resultText, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to retrieve aggregation data: ${error instanceof FathomApiError ? `${error.status}: ${error.message}` : String(error)}`, }, ], }; } }, ); }
  • src/index.ts:36-36 (registration)
    Call to register the get-aggregation tool during server initialization.
    registerAggregationTool(server, fathomClient);

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/mackenly/mcp-fathom-analytics'

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