atracker-mcp-server 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "atracker-mcp-server",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "MCP Server for ATracker self-hosted ad tracker",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "atracker-mcp-server": "./src/index.js"
8
8
  },
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
9
12
  "files": [
10
13
  "src"
11
14
  ],
package/src/index.js CHANGED
@@ -12,6 +12,8 @@ import { registerReportTools } from './tools/reports.js';
12
12
  import { registerStatusTools } from './tools/status.js';
13
13
  import { registerSettingsTools } from './tools/settings.js';
14
14
  import { registerGeoTools } from './tools/geo.js';
15
+ import { registerInsightsTools } from './tools/insights.js';
16
+ import { registerFunnelTools } from './tools/funnels.js';
15
17
 
16
18
  const url = process.env.ATRACKER_URL;
17
19
  const token = process.env.ATRACKER_TOKEN;
@@ -27,7 +29,7 @@ const client = createClient(url, token);
27
29
 
28
30
  const server = new McpServer({
29
31
  name: 'atracker',
30
- version: '1.1.1',
32
+ version: '1.2.0',
31
33
  });
32
34
 
33
35
  registerCampaignTools(server, client);
@@ -40,6 +42,8 @@ registerReportTools(server, client);
40
42
  registerStatusTools(server, client);
41
43
  registerSettingsTools(server, client);
42
44
  registerGeoTools(server, client);
45
+ registerInsightsTools(server, client);
46
+ registerFunnelTools(server, client);
43
47
 
44
48
  const transport = new StdioServerTransport();
45
49
  await server.connect(transport);
@@ -0,0 +1,113 @@
1
+ import { defineTool, jsonText } from '../util.js';
2
+
3
+ export function registerFunnelTools(server, client) {
4
+ // ── Registry ──
5
+ defineTool(server, 'get_funnel_registry', 'Get funnel registry: available modes, steps, breakdowns, filter fields.', {}, async () => {
6
+ const data = await client.get('/funnels/registry');
7
+ return jsonText(data);
8
+ });
9
+
10
+ // ── Query ──
11
+ defineTool(server, 'execute_funnel_query', 'Execute a funnel visualization query. Analyze drop-off and conversion rates between steps.', {
12
+ mode: { type: 'string', description: 'Funnel mode: status, path, or events.', enum: ['status', 'path', 'events'] },
13
+ steps: { type: 'string', description: 'JSON array of step names (status mode: click,lead,sale,rebill; path mode: traffic_source,campaign,flow,landing_page,offer,conversion; events mode: [{"table":"clicks","field":"country_code","value":"US"},...])' },
14
+ range_key: { type: 'string', description: 'Time range key. Default: 7d.', enum: ['today', 'yesterday', '7d', '14d', '21d', '1m'], default: '7d' },
15
+ filters: { type: 'string', description: 'JSON array of filters: [{"field":"campaign_id","operator":"in","value":["uuid1","uuid2"]}] (optional)' },
16
+ breakdown: { type: 'string', description: 'Breakdown field (e.g. campaign_id) for segmented results (optional)' },
17
+ visualization: { type: 'string', description: 'Chart type: bars, funnel, horizontal, sankey, table, trend, segmented. Default: bars.', default: 'bars' },
18
+ }, async ({ mode, steps, range_key, filters, breakdown, visualization }) => {
19
+ let parsedSteps;
20
+ try { parsedSteps = JSON.parse(steps || '[]'); } catch { parsedSteps = []; }
21
+ let parsedFilters;
22
+ try { parsedFilters = JSON.parse(filters || '[]'); } catch { parsedFilters = []; }
23
+
24
+ const body = {
25
+ mode,
26
+ steps: parsedSteps,
27
+ range_key: range_key || '7d',
28
+ filters: parsedFilters,
29
+ breakdown: breakdown || undefined,
30
+ visualization: visualization || 'bars',
31
+ };
32
+ const data = await client.post('/funnels/query', body);
33
+ return jsonText(data);
34
+ });
35
+
36
+ // ── Trends ──
37
+ defineTool(server, 'execute_funnel_trends', 'Execute funnel trends over time. Shows how each step performs day-by-day, hour-by-hour, or week-by-week.', {
38
+ mode: { type: 'string', description: 'Funnel mode: status, path, or events.', enum: ['status', 'path', 'events'] },
39
+ steps: { type: 'string', description: 'JSON array of step names (same format as query)' },
40
+ range_key: { type: 'string', description: 'Time range key. Default: 7d.', enum: ['today', 'yesterday', '7d', '14d', '21d', '1m'], default: '7d' },
41
+ filters: { type: 'string', description: 'JSON array of filters (optional)' },
42
+ time_grain: { type: 'string', description: 'Time granularity: hour, day, week. Default: day.', enum: ['hour', 'day', 'week'], default: 'day' },
43
+ }, async ({ mode, steps, range_key, filters, time_grain }) => {
44
+ let parsedSteps;
45
+ try { parsedSteps = JSON.parse(steps || '[]'); } catch { parsedSteps = []; }
46
+ let parsedFilters;
47
+ try { parsedFilters = JSON.parse(filters || '[]'); } catch { parsedFilters = []; }
48
+
49
+ const body = {
50
+ mode,
51
+ steps: parsedSteps,
52
+ range_key: range_key || '7d',
53
+ filters: parsedFilters,
54
+ time_grain: time_grain || 'day',
55
+ };
56
+ const data = await client.post('/funnels/trends', body);
57
+ return jsonText(data);
58
+ });
59
+
60
+ // ── Presets ──
61
+ defineTool(server, 'list_funnel_presets', 'List saved funnel presets for the account.', {}, async () => {
62
+ const data = await client.get('/funnels/presets');
63
+ return jsonText(data);
64
+ });
65
+
66
+ defineTool(server, 'create_funnel_preset', 'Save a new funnel preset (configuration).', {
67
+ name: { type: 'string', description: 'Preset name' },
68
+ config: { type: 'string', description: 'JSON funnel config: {mode, steps, filters, breakdown, visualization, range_key}' },
69
+ description: { type: 'string', description: 'Optional description' },
70
+ }, async ({ name, config, description }) => {
71
+ let parsedConfig;
72
+ try { parsedConfig = JSON.parse(config || '{}'); } catch { parsedConfig = {}; }
73
+
74
+ const row = await client.post('/funnels/presets', {
75
+ name,
76
+ config: parsedConfig,
77
+ description: description || '',
78
+ });
79
+ return jsonText(row);
80
+ });
81
+
82
+ defineTool(server, 'update_funnel_preset', 'Update an existing funnel preset.', {
83
+ id: { type: 'string', description: 'Preset UUID' },
84
+ name: { type: 'string', description: 'New name (optional)' },
85
+ config: { type: 'string', description: 'New JSON funnel config (optional)' },
86
+ description: { type: 'string', description: 'New description (optional)' },
87
+ }, async ({ id, name, config, description }) => {
88
+ const body = {};
89
+ if (name !== undefined) body.name = name;
90
+ if (description !== undefined) body.description = description;
91
+ if (config !== undefined) {
92
+ let parsedConfig;
93
+ try { parsedConfig = JSON.parse(config); } catch { parsedConfig = config; }
94
+ body.config = parsedConfig;
95
+ }
96
+ const row = await client.patch(`/funnels/presets/${id}`, body);
97
+ return jsonText(row);
98
+ });
99
+
100
+ defineTool(server, 'delete_funnel_preset', 'Delete a funnel preset.', {
101
+ id: { type: 'string', description: 'Preset UUID' },
102
+ }, async ({ id }) => {
103
+ await client.del(`/funnels/presets/${id}`);
104
+ return { content: [{ type: 'text', text: 'Funnel preset deleted.' }] };
105
+ });
106
+
107
+ defineTool(server, 'share_funnel_preset', 'Generate a share link for a funnel preset.', {
108
+ id: { type: 'string', description: 'Preset UUID' },
109
+ }, async ({ id }) => {
110
+ const data = await client.post(`/funnels/presets/${id}/share`);
111
+ return jsonText(data);
112
+ });
113
+ }
@@ -0,0 +1,11 @@
1
+ import { defineTool, jsonText } from '../util.js';
2
+
3
+ export function registerInsightsTools(server, client) {
4
+ defineTool(server, 'get_insights', 'Get AI-powered campaign insights and recommendations. Uses the configured AI provider to analyze click/conversion data for the selected time range.', {
5
+ mode: { type: 'string', description: 'Analysis mode: "ai" (LLM) or "offline" (rule-based). Default: "ai".', enum: ['ai', 'offline'], default: 'ai' },
6
+ range: { type: 'string', description: 'Time range key: today, yesterday, 7d, 14d, 21d, 1m. Default: 7d.', enum: ['today', 'yesterday', '7d', '14d', '21d', '1m'], default: '7d' },
7
+ }, async ({ mode, range }) => {
8
+ const data = await client.post('/insights/analyze', { mode: mode || 'ai', range: range || '7d' });
9
+ return jsonText(data);
10
+ });
11
+ }
@@ -26,4 +26,14 @@ export function registerSettingsTools(server, client) {
26
26
  const data = await client.put('/settings', items);
27
27
  return jsonText(data);
28
28
  });
29
+
30
+ defineTool(server, 'get_global_postback', 'Get global postback URL and installation token (resolves campaign from subid).', {}, async () => {
31
+ const data = await client.get('/global-postback');
32
+ return jsonText(data);
33
+ });
34
+
35
+ defineTool(server, 'regenerate_global_postback_token', 'Regenerate global postback token. The old global postback URL stops working.', {}, async () => {
36
+ const data = await client.post('/global-postback/regenerate');
37
+ return jsonText(data);
38
+ });
29
39
  }