atracker-mcp-server 1.0.0 → 1.1.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/README.md CHANGED
@@ -105,6 +105,14 @@ npm install -g atracker-mcp-server
105
105
  - `get_settings` — Get tracker settings
106
106
  - `update_settings` — Update tracker settings
107
107
 
108
+
109
+ ### Geo2IP Bundles
110
+
111
+ - `geo_status` — Current geo bundle versions, sizes, and last download status
112
+ - `geo_check_update` — Check the platform for newer bundle versions (returns delta/full info)
113
+ - `geo_update` — Download and apply latest bundles (`categories?`, `force?`); polls until done
114
+ - `geo_lookup` — Test IP lookup with resolved geo/asn/threat data and per-field sources
115
+
108
116
  ## Environment Variables
109
117
 
110
118
  | Variable | Required | Description |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atracker-mcp-server",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "MCP Server for ATracker self-hosted ad tracker",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -11,6 +11,7 @@ import { registerDomainTools } from './tools/domains.js';
11
11
  import { registerReportTools } from './tools/reports.js';
12
12
  import { registerStatusTools } from './tools/status.js';
13
13
  import { registerSettingsTools } from './tools/settings.js';
14
+ import { registerGeoTools } from './tools/geo.js';
14
15
 
15
16
  const url = process.env.ATRACKER_URL;
16
17
  const token = process.env.ATRACKER_TOKEN;
@@ -26,7 +27,7 @@ const client = createClient(url, token);
26
27
 
27
28
  const server = new McpServer({
28
29
  name: 'atracker',
29
- version: '1.0.0',
30
+ version: '1.1.0',
30
31
  });
31
32
 
32
33
  registerCampaignTools(server, client);
@@ -38,6 +39,7 @@ registerDomainTools(server, client);
38
39
  registerReportTools(server, client);
39
40
  registerStatusTools(server, client);
40
41
  registerSettingsTools(server, client);
42
+ registerGeoTools(server, client);
41
43
 
42
44
  const transport = new StdioServerTransport();
43
45
  await server.connect(transport);
@@ -0,0 +1,78 @@
1
+ const CATEGORIES = ['geo', 'asn', 'threat'];
2
+ const POLL_INTERVAL_MS = 1000;
3
+ const POLL_TIMEOUT_MS = 30 * 60 * 1000;
4
+
5
+ async function waitForDownload(client, categories) {
6
+ const targets = categories && categories.length ? categories : CATEGORIES;
7
+ const startedAt = Date.now();
8
+ // eslint-disable-next-line no-constant-condition
9
+ while (true) {
10
+ if (Date.now() - startedAt > POLL_TIMEOUT_MS) {
11
+ throw new Error('Timed out waiting for geo bundle download');
12
+ }
13
+ const state = await client.get('/geo2ip/download-status');
14
+ const summaries = targets.map((c) => ({ category: c, ...(state[c] || {}) }));
15
+ const errored = summaries.find((s) => s.status === 'error');
16
+ if (errored) throw new Error(`Download failed for ${errored.category}: ${errored.error || 'unknown'}`);
17
+ const active = summaries.find((s) => !['done', 'idle'].includes(s.status));
18
+ if (!active) return summaries;
19
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
20
+ }
21
+ }
22
+
23
+ export function registerGeoTools(server, client) {
24
+ server.tool(
25
+ 'geo_status',
26
+ 'Get current geo2ip bundle versions, sizes, and last download status for all three categories (geo, asn, threat).',
27
+ {},
28
+ async () => {
29
+ const data = await client.get('/geo2ip/bundle-status');
30
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
31
+ }
32
+ );
33
+
34
+ server.tool(
35
+ 'geo_check_update',
36
+ 'Check the ATracker platform for newer geo bundle versions. Returns current versions, available manifests (including delta info), and the list of categories that have updates.',
37
+ {},
38
+ async () => {
39
+ const data = await client.post('/geo2ip/check-updates', {});
40
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
41
+ }
42
+ );
43
+
44
+ server.tool(
45
+ 'geo_update',
46
+ 'Download and apply the latest geo bundles from the platform. Optionally limit to specific categories (geo|asn|threat). Polls until completion and returns the final bundle status.',
47
+ {
48
+ categories: { type: 'array', items: { type: 'string', enum: CATEGORIES }, description: 'Optional subset of categories to update' },
49
+ force: { type: 'boolean', description: 'Re-download even if bundles are up to date' },
50
+ },
51
+ async (args = {}) => {
52
+ const body = {};
53
+ if (Array.isArray(args.categories) && args.categories.length) body.categories = args.categories;
54
+ if (args.force) body.force = true;
55
+ await client.post('/geo2ip/download-bundle', body);
56
+ const summaries = await waitForDownload(client, body.categories);
57
+ const finalStatus = await client.get('/geo2ip/bundle-status');
58
+ return {
59
+ content: [{
60
+ type: 'text',
61
+ text: JSON.stringify({ summaries, status: finalStatus }, null, 2),
62
+ }],
63
+ };
64
+ }
65
+ );
66
+
67
+ server.tool(
68
+ 'geo_lookup',
69
+ 'Look up geo, ASN, and threat info for an IPv4/IPv6 address using the locally loaded bundles. Returns resolved data with per-field source attribution.',
70
+ {
71
+ ip: { type: 'string', description: 'IPv4 or IPv6 address to look up' },
72
+ },
73
+ async ({ ip }) => {
74
+ const data = await client.post('/geo2ip/test-lookup', { ip });
75
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
76
+ }
77
+ );
78
+ }