adjust-reporting
Generate mobile analytics reports with customizable metrics, dimensions, and filters to analyze app performance data from the Adjust platform.
Instructions
Adjust reporting
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| date | No | Date for the report in YYYY-MM-DD format | 2026-01-03 |
| metrics | No | Comma-separated list of metrics to include | installs,sessions,revenue |
| dimensions | No | Comma-separated values to group by (e.g., day,country,network). Options include: hour, day, week, month, year, quarter, os_name, device_type, app, app_token, store_id, store_type, currency, currency_code, network, campaign, campaign_network, campaign_id_network, adgroup, adgroup_network, adgroup_id_network, creative, country, country_code, region, partner_name, partner_id, channel, platform | |
| format_dates | No | If false, date dimensions are returned in ISO format | |
| date_period | No | Date period (e.g., this_month, yesterday, 2023-01-01:2023-01-31, -10d:-3d) | |
| cohort_maturity | No | Display values for immature or only mature cohorts | |
| utc_offset | No | Timezone used in the report (e.g., +01:00) | |
| attribution_type | No | Type of engagement the attribution awards | click |
| attribution_source | No | Whether in-app activity is assigned to install source or divided | dynamic |
| reattributed | No | Filter for reattributed users | all |
| ad_spend_mode | No | Determines the ad spend source applied in calculations | |
| sort | No | Comma-separated list of metrics/dimensions to sort by (use - for descending) | |
| currency | No | Currency used for conversion of money related metrics | USD |
Implementation Reference
- src/mcp-adjust.ts:59-149 (handler)The handler function for the \"adjust-reporting\" tool. It builds query parameters from input, fetches report data using AdjustApiClient, generates analysis, and returns formatted Markdown content or error response.try { // Convert all params to a query parameters object const queryParams: Record<string, any> = {}; // Add all non-undefined parameters to the query Object.entries(params).forEach(([key, value]) => { if (value !== undefined) { queryParams[key] = value; } }); // Fetch data from Adjust using our API module const reportData = await client.fetchReports(params.date, queryParams); // Handle empty response if (!reportData || Object.keys(reportData).length === 0) { return { isError: false, content: [ { type: "text" as const, text: `## Adjust Report for ${params.date}\n\nNo data available for the specified parameters.`, } ], }; } // Simple analysis of the data const analysis = analyzeReportData(reportData); return { isError: false, content: [ { type: "text" as const, text: `## Adjust Report for ${params.date}\n\n${analysis}\n\n\`\`\`json\n${JSON.stringify(reportData, null, 2)}\n\`\`\``, } ], }; } catch (error) { console.error("Error fetching or analyzing Adjust data:", error); // Extract status code and message let statusCode = 500; let errorMessage = "Unknown error"; if (error instanceof Error) { errorMessage = error.message; // Check for Axios error with response if ('response' in error && error.response && typeof error.response === 'object') { const axiosError = error as any; statusCode = axiosError.response.status; // Provide helpful messages based on status code switch (statusCode) { case 400: errorMessage = "Bad request: Your query contains invalid parameters or is malformed."; break; case 401: errorMessage = "Unauthorized: Please check your API credentials."; break; case 403: errorMessage = "Forbidden: You don't have permission to access this data."; break; case 429: errorMessage = "Too many requests: You've exceeded the rate limit (max 50 simultaneous requests)."; break; case 503: errorMessage = "Service unavailable: The Adjust API is currently unavailable."; break; case 504: errorMessage = "Gateway timeout: The query took too long to process."; break; default: errorMessage = axiosError.response.data?.message || errorMessage; } } } return { isError: true, content: [ { type: "text" as const, text: `## Error Fetching Adjust Data\n\n**Status Code**: ${statusCode}\n\n**Error**: ${errorMessage}\n\nPlease check your parameters and try again.`, }, ], }; } });
- src/mcp-adjust.ts:26-58 (schema)Zod input schema for the \"adjust-reporting\" tool defining parameters such as date, metrics, dimensions, attribution settings, and more.date: z.string() .describe("Date for the report in YYYY-MM-DD format") .default(new Date().toISOString().split('T')[0]), metrics: z.string() .describe("Comma-separated list of metrics to include") .default("installs,sessions,revenue"), dimensions: z.string().optional() .describe("Comma-separated values to group by (e.g., day,country,network). Options include: hour, day, week, month, year, quarter, os_name, device_type, app, app_token, store_id, store_type, currency, currency_code, network, campaign, campaign_network, campaign_id_network, adgroup, adgroup_network, adgroup_id_network, creative, country, country_code, region, partner_name, partner_id, channel, platform"), format_dates: z.boolean().optional() .describe("If false, date dimensions are returned in ISO format"), date_period: z.string().optional() .describe("Date period (e.g., this_month, yesterday, 2023-01-01:2023-01-31, -10d:-3d)"), cohort_maturity: z.enum(["immature", "mature"]).optional() .describe("Display values for immature or only mature cohorts"), utc_offset: z.string().optional() .describe("Timezone used in the report (e.g., +01:00)"), attribution_type: z.enum(["click", "impression", "all"]).optional() .default("click") .describe("Type of engagement the attribution awards"), attribution_source: z.enum(["first", "dynamic"]).optional() .default("dynamic") .describe("Whether in-app activity is assigned to install source or divided"), reattributed: z.enum(["all", "false", "true"]).optional() .default("all") .describe("Filter for reattributed users"), ad_spend_mode: z.enum(["adjust", "network", "mixed"]).optional() .describe("Determines the ad spend source applied in calculations"), sort: z.string().optional() .describe("Comma-separated list of metrics/dimensions to sort by (use - for descending)"), currency: z.string().optional() .default("USD") .describe("Currency used for conversion of money related metrics"), }, async (params, extra) => {
- src/mcp-adjust.ts:25-25 (registration)Registration of the \"adjust-reporting\" tool using McpServer.tool() with description, schema, and handler.server.tool("adjust-reporting", "Adjust reporting", {
- src/adjust/client.ts:21-43 (helper)AdjustApiClient.fetchReports method called by the tool handler to retrieve report data from the Adjust API.async fetchReports(date: string, params: Record<string, any> = {}) { try { // Build query parameters const queryParams: Record<string, any> = { ...params }; // If date_period is not provided, use the date parameter if (!queryParams.date_period) { queryParams.date_period = date; } // Make the request to the reports-service endpoint const response = await this.axiosInstance.get('/reports-service/report', { params: queryParams }); return response.data; } catch (error) { console.error("Adjust API Error:", error); throw error; } }
- src/mcp-adjust.ts:272-329 (helper)Helper function to analyze raw report data into a readable Markdown format with summaries and breakdowns, used in the tool handler.function analyzeReportData(data: any) { let analysis = ""; if (!data || !data.rows || data.rows.length === 0) { return "No data available for analysis."; } // Add totals summary if (data.totals) { analysis += "## Summary\n"; Object.entries(data.totals).forEach(([metric, value]) => { analysis += `**Total ${metric}**: ${value}\n`; }); analysis += "\n"; } // Add row analysis analysis += "## Breakdown\n"; // Get all metrics (non-dimension fields) from the first row const firstRow = data.rows[0]; const metrics = Object.keys(firstRow).filter(key => !['attr_dependency', 'app', 'partner_name', 'campaign', 'campaign_id_network', 'campaign_network', 'adgroup', 'creative', 'country', 'os_name', 'day', 'week', 'month', 'year'].includes(key) ); // Analyze each row data.rows.forEach((row: any, index: number) => { // Create a title for this row based on available dimensions let rowTitle = ""; if (row.campaign) rowTitle += `Campaign: ${row.campaign} `; if (row.partner_name) rowTitle += `(${row.partner_name}) `; if (row.app) rowTitle += `- App: ${row.app} `; if (row.country) rowTitle += `- Country: ${row.country} `; if (row.os_name) rowTitle += `- OS: ${row.os_name} `; analysis += `### ${rowTitle || `Row ${index + 1}`}\n`; // Add metrics for this row metrics.forEach(metric => { if (row[metric] !== undefined) { analysis += `**${metric}**: ${row[metric]}\n`; } }); analysis += "\n"; }); // Add warnings if any if (data.warnings && data.warnings.length > 0) { analysis += "## Warnings\n"; data.warnings.forEach((warning: string) => { analysis += `- ${warning}\n`; }); } return analysis; }