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
| Name | Required | Description | Default |
|---|---|---|---|
| entity | Yes | The entity to aggregate (pageview or event) | |
| entity_id | Yes | ID of the entity (site ID or event ID) | |
| aggregates | Yes | Comma-separated list of aggregates to include (visits,uniques,pageviews,avg_duration,bounce_rate,conversions,unique_conversions,value) | |
| date_grouping | No | Optional date grouping | |
| field_grouping | No | Comma-separated fields to group by (e.g., hostname,pathname) | |
| sort_by | No | Field to sort by (e.g., pageviews:desc) | |
| timezone | No | Timezone for date calculations (default: UTC) | |
| date_from | Yes | Start date (e.g., 2025-01-01 00:00:00 or 2025-01-01) | |
| date_to | Yes | End date (e.g., 2025-12-31 23:59:59 or 2025-12-31) | |
| limit | No | Limit on number of results | |
| filters | No | Array of filter objects |
Implementation Reference
- src/tools/aggregation.ts:28-98 (handler)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)}`, }, ], }; } },
- src/tools/aggregation.ts:9-27 (schema)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"), },
- src/tools/aggregation.ts:5-100 (registration)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);