@datadive-tools/mcp 0.9.0 → 0.11.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 +41 -16
- package/dist/index.js +342 -73
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +27 -4
- package/dist/lib.js +342 -73
- package/dist/lib.js.map +1 -1
- package/package.json +1 -1
package/dist/lib.js
CHANGED
|
@@ -100,7 +100,7 @@ function extractMessage(body) {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
// package.json
|
|
103
|
-
var version = "0.
|
|
103
|
+
var version = "0.11.0";
|
|
104
104
|
|
|
105
105
|
// src/http/client.ts
|
|
106
106
|
var PKG_VERSION = version;
|
|
@@ -168,6 +168,23 @@ async function httpPost(ctx, path, body) {
|
|
|
168
168
|
}
|
|
169
169
|
return handleResponse(res);
|
|
170
170
|
}
|
|
171
|
+
async function httpDelete(ctx, path) {
|
|
172
|
+
const url = buildUrl(ctx.config.baseUrl, path);
|
|
173
|
+
let res;
|
|
174
|
+
try {
|
|
175
|
+
res = await fetch(url, {
|
|
176
|
+
method: "DELETE",
|
|
177
|
+
headers: {
|
|
178
|
+
...authHeaders(ctx.config),
|
|
179
|
+
accept: "application/json",
|
|
180
|
+
"user-agent": userAgent(ctx.toolName)
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
} catch (e) {
|
|
184
|
+
throw networkError(url, e);
|
|
185
|
+
}
|
|
186
|
+
return handleResponse(res);
|
|
187
|
+
}
|
|
171
188
|
function networkError(url, e) {
|
|
172
189
|
const msg = e instanceof Error ? e.message : String(e);
|
|
173
190
|
return new ApiError("network", 0, `Network error reaching ${url}: ${msg}`);
|
|
@@ -217,22 +234,22 @@ function isObject(v) {
|
|
|
217
234
|
}
|
|
218
235
|
|
|
219
236
|
// src/tools/list-niches.ts
|
|
237
|
+
var LIST_NICHES_MAX_PAGE_SIZE = 50;
|
|
220
238
|
var inputSchema = {
|
|
221
239
|
currentPage: z.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
222
|
-
pageSize: z.number().int().min(1).max(
|
|
240
|
+
pageSize: z.number().int().min(1).max(LIST_NICHES_MAX_PAGE_SIZE).optional().describe(`Items per page (max ${LIST_NICHES_MAX_PAGE_SIZE}). Defaults to 20.`)
|
|
223
241
|
};
|
|
224
242
|
var listNichesTool = {
|
|
225
243
|
name: "list_niches",
|
|
226
244
|
title: "List DataDive Niches",
|
|
227
|
-
description: "Use this first when the user asks about their niches, or to find a `nicheId` for use with `get_niche_keywords`, `get_niche_competitors`, or `get_ranking_juice`. Retrieves
|
|
245
|
+
description: "Use this first when the user asks about their niches, or to find a `nicheId` for use with `get_niche_keywords`, `get_niche_competitors`, or `get_ranking_juice`. Retrieves the Niches of the account. Each Niche represents a market segment or product category being tracked. Returns nicheId, heroKeyword, nicheLabel, marketplace (com/uk/de/...), and latestResearchDate per niche, plus pagination metadata (currentPage, pageSize, total, lastPage, hasNext, hasPrev). TEMPORARY LIMITATION: the API does not apply paging yet, so a single call returns every niche of the account whatever `currentPage` and `pageSize` say, and the pagination metadata describes a page that was not applied. Read the whole `data` array and filter it yourself; do not walk `currentPage` while `hasNext` is true, because every page repeats the same rows. Accounts with many niches therefore return a large response. There is no server-side search or sorting.",
|
|
228
246
|
inputSchema,
|
|
229
247
|
annotations: { readOnlyHint: true },
|
|
230
248
|
handler: async (args, ctx) => {
|
|
231
|
-
return await httpGet(
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
);
|
|
249
|
+
return await httpGet({ config: ctx.config, toolName: "list_niches" }, "/v1/niches", {
|
|
250
|
+
currentPage: args.currentPage,
|
|
251
|
+
pageSize: args.pageSize
|
|
252
|
+
});
|
|
236
253
|
}
|
|
237
254
|
};
|
|
238
255
|
|
|
@@ -282,7 +299,7 @@ var inputSchema4 = {
|
|
|
282
299
|
var getNicheCompetitorsTool = {
|
|
283
300
|
name: "get_niche_competitors",
|
|
284
301
|
title: "Get Competitors and Niche Statistics",
|
|
285
|
-
description: "Use this for competitor ASINs, sales/revenue benchmarks, or niche opportunity scoring. Retrieves the list of Competitors within the specified Niche along with Niche statistics. For the Niche: keyword statistics, opportunity evaluation, benchmark median values, and overall competitor strength assessment. For each Competitor: ASIN, sales, revenue, ratings, reviews, price, image URL, and ranking data.",
|
|
302
|
+
description: "Use this for competitor ASINs, product titles, BSR, sales/revenue benchmarks, or niche opportunity scoring. Retrieves the list of Competitors within the specified Niche along with Niche statistics. For the Niche: keyword statistics, opportunity evaluation, benchmark median values, and overall competitor strength assessment. For each Competitor: ASIN, product title, BSR, category and full category tree, sales, revenue, ratings, reviews, price, number of variations, image URL, total Ranking Juice, and ranking data. BSR supports ranking Competitors by sales position within mentioned category. For the Ranking Juice breakdown by title, bullets and description, use `get_ranking_juice`.",
|
|
286
303
|
inputSchema: inputSchema4,
|
|
287
304
|
annotations: { readOnlyHint: true },
|
|
288
305
|
handler: async (args, ctx) => {
|
|
@@ -329,7 +346,8 @@ var SUPPORTED_MARKETPLACES = [
|
|
|
329
346
|
"it",
|
|
330
347
|
"co.jp"
|
|
331
348
|
];
|
|
332
|
-
var
|
|
349
|
+
var RANK_RADAR_STATES = ["ACTIVE", "PAUSED", "ARCHIVED"];
|
|
350
|
+
var RANK_RADAR_STATUSES = [...RANK_RADAR_STATES, "ALL"];
|
|
333
351
|
var ALERT_STATUSES = ["active", "resolved", "all"];
|
|
334
352
|
var BILLABLE_FEATURE_TYPES = [
|
|
335
353
|
"DIVED_ASINS",
|
|
@@ -341,25 +359,32 @@ var CATALOG_STATUSES = ["Active", "all"];
|
|
|
341
359
|
var LISTING_CHANGE_TYPES = ["Price", "Content", "Image"];
|
|
342
360
|
var LISTING_CHANGE_SORT_BY = ["date", "type"];
|
|
343
361
|
var SORT_ORDER = ["ASC", "DESC"];
|
|
362
|
+
var ADD_SEARCH_TERMS_MAX = 1e3;
|
|
363
|
+
var LISTING_COPY_STRATEGIES = ["cosmo", "ranking-juice", "nlp", "cosmo-rufus"];
|
|
344
364
|
|
|
345
365
|
// src/tools/list-rank-radars.ts
|
|
366
|
+
var LIST_RANK_RADARS_MAX_PAGE_SIZE = 50;
|
|
346
367
|
var inputSchema6 = {
|
|
347
368
|
currentPage: z6.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
348
|
-
pageSize: z6.number().int().min(1).max(
|
|
369
|
+
pageSize: z6.number().int().min(1).max(LIST_RANK_RADARS_MAX_PAGE_SIZE).optional().describe(`Items per page (max ${LIST_RANK_RADARS_MAX_PAGE_SIZE}). Defaults to 20.`),
|
|
349
370
|
nicheId: z6.string().min(1).optional().describe("Filter Rank Radars by Niche identifier. Use after `list_niches`."),
|
|
350
371
|
status: z6.enum(RANK_RADAR_STATUSES).optional().describe(
|
|
351
|
-
"
|
|
372
|
+
"Which Rank Radars to return. ACTIVE (the default) are tracking; PAUSED have been stopped but keep their history and can be resumed; ARCHIVED have been deleted; ALL means active and paused together. Archived Rank Radars are returned only by an explicit ARCHIVED."
|
|
352
373
|
),
|
|
353
374
|
searchText: z6.string().optional().describe("Filter Rank Radars by ASIN or product title.")
|
|
354
375
|
};
|
|
376
|
+
function minimize(item) {
|
|
377
|
+
const { asin, ...rest } = item;
|
|
378
|
+
return { ...rest, asin: asin?.asin };
|
|
379
|
+
}
|
|
355
380
|
var listRankRadarsTool = {
|
|
356
381
|
name: "list_rank_radars",
|
|
357
382
|
title: "List Rank Radars",
|
|
358
|
-
description:
|
|
383
|
+
description: `Use this to find a \`rankRadarId\` before calling \`get_rank_radar_data\`. Filter by \`nicheId\` if the user has already identified a niche. Retrieves a paginated list of Rank Radars \u2014 keyword-rank trackers monitoring organic and sponsored positions for specific ASINs over time. Each item includes id, status (ACTIVE, PAUSED or ARCHIVED), asin, marketplace, keywordCount, title, imageUrl, and summary metrics: top10KW, top10SV, top50KW, top50SV. Supports pagination metadata (currentPage, pageSize, total, lastPage, hasNext, hasPrev); a page holds at most ${LIST_RANK_RADARS_MAX_PAGE_SIZE} Rank Radars, so a large account needs several calls.`,
|
|
359
384
|
inputSchema: inputSchema6,
|
|
360
385
|
annotations: { readOnlyHint: true },
|
|
361
386
|
handler: async (args, ctx) => {
|
|
362
|
-
|
|
387
|
+
const page = await httpGet(
|
|
363
388
|
{ config: ctx.config, toolName: "list_rank_radars" },
|
|
364
389
|
"/v1/niches/rank-radars",
|
|
365
390
|
{
|
|
@@ -370,6 +395,7 @@ var listRankRadarsTool = {
|
|
|
370
395
|
searchText: args.searchText
|
|
371
396
|
}
|
|
372
397
|
);
|
|
398
|
+
return { ...page, data: (page.data ?? []).map(minimize) };
|
|
373
399
|
}
|
|
374
400
|
};
|
|
375
401
|
|
|
@@ -421,12 +447,12 @@ var inputSchema8 = {
|
|
|
421
447
|
var createRankRadarTool = {
|
|
422
448
|
name: "create_rank_radar",
|
|
423
449
|
title: "Create a Rank Radar",
|
|
424
|
-
description: "Use this to start tracking organic and sponsored keyword rankings for an ASIN within a niche. \u26A0\uFE0F Spends Search Term tokens (cost scales with `numberOfKeywords`) and cannot be undone \u2014 set `confirm: true` only after the user approves the cost. Returns the new `rankRadarId`; read its data later with `get_rank_radar_data`. Requires `asin`, `numberOfKeywords` (min 1), and a `nicheId` from `list_niches`.",
|
|
450
|
+
description: "Use this to start tracking organic and sponsored keyword rankings for an ASIN within a niche. \u26A0\uFE0F Spends Search Term tokens (cost scales with `numberOfKeywords`) and cannot be undone \u2014 set `confirm: true` only after the user approves the cost. Not safe to retry: each call spends tokens again and creates a separate Rank Radar \u2014 if a call errors or times out, check `list_rank_radars` instead of re-calling. Returns the new `rankRadarId`; read its data later with `get_rank_radar_data`. Requires `asin`, `numberOfKeywords` (min 1), and a `nicheId` from `list_niches`.",
|
|
425
451
|
inputSchema: inputSchema8,
|
|
426
452
|
// destructiveHint is technically "additive" here (this creates a new Rank Radar, it
|
|
427
453
|
// doesn't destroy data), but we flag it destructive so clients prompt before the
|
|
428
454
|
// irreversible token spend. The confirm gate enforces this server-side regardless.
|
|
429
|
-
annotations: { readOnlyHint: false, destructiveHint: true },
|
|
455
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
430
456
|
handler: async (args, ctx) => {
|
|
431
457
|
const pending = requireConfirmation(
|
|
432
458
|
args.confirm,
|
|
@@ -459,12 +485,12 @@ var inputSchema9 = {
|
|
|
459
485
|
var createNicheDiveTool = {
|
|
460
486
|
name: "create_niche_dive",
|
|
461
487
|
title: "Create a Niche Dive",
|
|
462
|
-
description: "Use this to start new niche research from a seed ASIN. \u26A0\uFE0F Spends dive tokens (cost scales with `numberOfCompetitors`) and cannot be undone \u2014 set `confirm: true` only after the user approves the cost. The dive runs asynchronously: this returns immediately with a `diveId` and an `estimatedCompletionDate`. Poll `get_dive_status` with that `diveId` until it reports `success` (which carries the new `nicheId` for use with `list_niches`, `get_niche_keywords`, etc.). Requires `marketplace`, `asin`, and `numberOfCompetitors` (min 2).",
|
|
488
|
+
description: "Use this to start new niche research from a seed ASIN. \u26A0\uFE0F Spends dive tokens (cost scales with `numberOfCompetitors`) and cannot be undone \u2014 set `confirm: true` only after the user approves the cost. Not safe to retry: each call spends tokens again and starts a separate dive \u2014 if a call errors or times out, poll `get_dive_status` (or check `list_niches`) instead of re-calling. The dive runs asynchronously: this returns immediately with a `diveId` and an `estimatedCompletionDate`. Poll `get_dive_status` with that `diveId` until it reports `success` (which carries the new `nicheId` for use with `list_niches`, `get_niche_keywords`, etc.). Requires `marketplace`, `asin`, and `numberOfCompetitors` (min 2).",
|
|
463
489
|
inputSchema: inputSchema9,
|
|
464
490
|
// destructiveHint is technically "additive" here (a dive creates a new niche, it
|
|
465
491
|
// doesn't destroy data), but we flag it destructive so clients prompt before the
|
|
466
492
|
// irreversible token spend. The confirm gate enforces this server-side regardless.
|
|
467
|
-
annotations: { readOnlyHint: false, destructiveHint: true },
|
|
493
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
468
494
|
handler: async (args, ctx) => {
|
|
469
495
|
const pending = requireConfirmation(
|
|
470
496
|
args.confirm,
|
|
@@ -508,11 +534,11 @@ var inputSchema10 = {
|
|
|
508
534
|
var rediveNicheTool = {
|
|
509
535
|
name: "redive_niche",
|
|
510
536
|
title: "Re-dive an Existing Niche",
|
|
511
|
-
description: "Use this to refresh an existing niche's research with current Amazon data, instead of creating a new niche with `create_niche_dive`. \u26A0\uFE0F Spends dive tokens (one batch per ASIN dived) and cannot be undone \u2014 set `confirm: true` only after the user approves the cost. Two modes: `same_competitors` re-dives the niche's current competitor set (no other argument needed) and `discover` finds a fresh set, sized by `numberOfCompetitors` and steerable with `heroAsin` / `lockedAsins` / `excludedAsins`. Runs asynchronously: returns a `diveId` and an `estimatedCompletionDate` \u2014 poll `get_dive_status` with that `diveId` until it reports `success`. The niche keeps its `nicheId`, so existing rank radars and reports follow the refreshed data.",
|
|
537
|
+
description: "Use this to refresh an existing niche's research with current Amazon data, instead of creating a new niche with `create_niche_dive`. \u26A0\uFE0F Spends dive tokens (one batch per ASIN dived) and cannot be undone \u2014 set `confirm: true` only after the user approves the cost. Not safe to retry: each call spends tokens again and starts a separate re-dive \u2014 if a call errors or times out, poll `get_dive_status` instead of re-calling. Two modes: `same_competitors` re-dives the niche's current competitor set (no other argument needed) and `discover` finds a fresh set, sized by `numberOfCompetitors` and steerable with `heroAsin` / `lockedAsins` / `excludedAsins`. Runs asynchronously: returns a `diveId` and an `estimatedCompletionDate` \u2014 poll `get_dive_status` with that `diveId` until it reports `success`. The niche keeps its `nicheId`, so existing rank radars and reports follow the refreshed data.",
|
|
512
538
|
inputSchema: inputSchema10,
|
|
513
539
|
// Same reasoning as create_niche_dive: a re-dive is additive rather than destructive, but the
|
|
514
540
|
// irreversible token spend is what clients need to prompt on. The confirm gate enforces it regardless.
|
|
515
|
-
annotations: { readOnlyHint: false, destructiveHint: true },
|
|
541
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
516
542
|
handler: async (args, ctx) => {
|
|
517
543
|
if (args.mode === "discover" && args.numberOfCompetitors === void 0) {
|
|
518
544
|
throw new ApiError(
|
|
@@ -560,17 +586,251 @@ var getDiveStatusTool = {
|
|
|
560
586
|
}
|
|
561
587
|
};
|
|
562
588
|
|
|
563
|
-
// src/tools/
|
|
589
|
+
// src/tools/delete-niche.ts
|
|
564
590
|
import { z as z12 } from "zod";
|
|
565
591
|
var inputSchema12 = {
|
|
566
|
-
|
|
567
|
-
|
|
592
|
+
nicheId: z12.string().min(1).describe("The niche to delete. Get one from `list_niches`."),
|
|
593
|
+
confirm: z12.boolean().optional().describe(
|
|
594
|
+
"Must be true to proceed \u2014 deleting a niche destroys its keywords, competitors and dive history permanently. Confirm with the user first."
|
|
595
|
+
)
|
|
596
|
+
};
|
|
597
|
+
var deleteNicheTool = {
|
|
598
|
+
name: "delete_niche",
|
|
599
|
+
title: "Delete a Niche",
|
|
600
|
+
description: "Use this to permanently remove a niche the user no longer needs. \u26A0\uFE0F Deletes the niche and everything attached to it \u2014 keywords, competitors, all dives and diveboxes \u2014 and cannot be undone; the dive tokens already spent on it are NOT refunded. Set `confirm: true` only after the user approves. A niche used by any Rank Radar cannot be deleted: the call fails with a conflict, so delete or archive those rank radars first (`list_rank_radars` with the `nicheId` filter shows them).",
|
|
601
|
+
inputSchema: inputSchema12,
|
|
602
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
603
|
+
handler: async (args, ctx) => {
|
|
604
|
+
const pending = requireConfirmation(
|
|
605
|
+
args.confirm,
|
|
606
|
+
ctx,
|
|
607
|
+
"Deleting this niche removes its keywords, competitors and all dive history permanently. The dive tokens already spent on it are not refunded."
|
|
608
|
+
);
|
|
609
|
+
if (pending) return pending;
|
|
610
|
+
await httpDelete(
|
|
611
|
+
{ config: ctx.config, toolName: "delete_niche" },
|
|
612
|
+
`/v1/niches/${encodeURIComponent(args.nicheId)}`
|
|
613
|
+
);
|
|
614
|
+
return { status: "deleted", nicheId: args.nicheId };
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
// src/tools/pause-rank-radar.ts
|
|
619
|
+
import { z as z13 } from "zod";
|
|
620
|
+
var inputSchema13 = {
|
|
621
|
+
rankRadarId: z13.string().uuid().describe("The Rank Radar UUID to pause (from `list_rank_radars`).")
|
|
622
|
+
};
|
|
623
|
+
var pauseRankRadarTool = {
|
|
624
|
+
name: "pause_rank_radar",
|
|
625
|
+
title: "Pause a Rank Radar",
|
|
626
|
+
description: "Use this to pause tracking on a Rank Radar without losing anything \u2014 the action the DataDive API calls 'archiving', so when a user asks to archive a Rank Radar, this is the tool they mean. Tracking stops for all of its keywords and the Daily Tracked Keywords quota they held is freed for other Rank Radars, while the Rank Radar and its ranking history are kept. Fully reversible with `resume_rank_radar`, so it needs no `confirm` \u2014 prefer it over `delete_rank_radar` whenever the user may want the data back. Paused Rank Radars show up in `list_rank_radars` under `status: PAUSED` \u2014 not `ARCHIVED`, which covers Rank Radars removed with `delete_rank_radar`. Safe to repeat: pausing an already paused Rank Radar succeeds and changes nothing.",
|
|
627
|
+
inputSchema: inputSchema13,
|
|
628
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
629
|
+
handler: async (args, ctx) => {
|
|
630
|
+
await httpPost(
|
|
631
|
+
{ config: ctx.config, toolName: "pause_rank_radar" },
|
|
632
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/archive`,
|
|
633
|
+
{}
|
|
634
|
+
);
|
|
635
|
+
return { status: "paused", rankRadarId: args.rankRadarId };
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
// src/tools/resume-rank-radar.ts
|
|
640
|
+
import { z as z14 } from "zod";
|
|
641
|
+
var inputSchema14 = {
|
|
642
|
+
rankRadarId: z14.string().uuid().describe("The Rank Radar UUID to resume (from `list_rank_radars`).")
|
|
643
|
+
};
|
|
644
|
+
var resumeRankRadarTool = {
|
|
645
|
+
name: "resume_rank_radar",
|
|
646
|
+
title: "Resume a Paused Rank Radar",
|
|
647
|
+
description: "Use this to restart tracking on a Rank Radar that was paused with `pause_rank_radar` (shown by `list_rank_radars` under `status: PAUSED`; a deleted, `ARCHIVED` one cannot be resumed). Keywords are resumed as far as the available Daily Tracked Keywords quota allows, most relevant first \u2014 so with a tight quota only part of the original keyword set comes back; check `get_quota` first if that matters. Reversible with `pause_rank_radar`, so it needs no `confirm`. Fails with a bad-request error when there is no quota left at all. Safe to repeat: resuming an already active Rank Radar changes nothing.",
|
|
648
|
+
inputSchema: inputSchema14,
|
|
649
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
650
|
+
handler: async (args, ctx) => {
|
|
651
|
+
await httpPost(
|
|
652
|
+
{ config: ctx.config, toolName: "resume_rank_radar" },
|
|
653
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/resume`,
|
|
654
|
+
{}
|
|
655
|
+
);
|
|
656
|
+
return { status: "resumed", rankRadarId: args.rankRadarId };
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
// src/tools/delete-rank-radar.ts
|
|
661
|
+
import { z as z15 } from "zod";
|
|
662
|
+
var inputSchema15 = {
|
|
663
|
+
rankRadarId: z15.string().uuid().describe("The Rank Radar UUID to delete (from `list_rank_radars`)."),
|
|
664
|
+
confirm: z15.boolean().optional().describe(
|
|
665
|
+
"Must be true to proceed \u2014 deleting a Rank Radar destroys its ranking history permanently. Confirm with the user first."
|
|
666
|
+
)
|
|
667
|
+
};
|
|
668
|
+
var deleteRankRadarTool = {
|
|
669
|
+
name: "delete_rank_radar",
|
|
670
|
+
title: "Delete a Rank Radar",
|
|
671
|
+
description: "Use this to permanently remove a Rank Radar and all of its keyword ranking history. \u26A0\uFE0F Cannot be undone \u2014 there is no restore endpoint; set `confirm: true` only after the user approves. It does free the Daily Tracked Keywords quota those keywords held. Deleted Rank Radars are what `list_rank_radars` returns for `status: ARCHIVED`. If the user only wants to stop tracking for a while and keep the history \u2014 or asks to 'archive' the Rank Radar, which is what the DataDive API calls pausing \u2014 use `pause_rank_radar` instead: it frees the same quota and is reversible with `resume_rank_radar`.",
|
|
672
|
+
inputSchema: inputSchema15,
|
|
673
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
674
|
+
handler: async (args, ctx) => {
|
|
675
|
+
const pending = requireConfirmation(
|
|
676
|
+
args.confirm,
|
|
677
|
+
ctx,
|
|
678
|
+
"Deleting this Rank Radar removes its keyword ranking history permanently. It frees the Daily Tracked Keywords quota, but the history cannot be recovered \u2014 `pause_rank_radar` frees the same quota and is reversible."
|
|
679
|
+
);
|
|
680
|
+
if (pending) return pending;
|
|
681
|
+
await httpDelete(
|
|
682
|
+
{ config: ctx.config, toolName: "delete_rank_radar" },
|
|
683
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}`
|
|
684
|
+
);
|
|
685
|
+
return { status: "deleted", rankRadarId: args.rankRadarId };
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
// src/tools/add-rank-radar-search-terms.ts
|
|
690
|
+
import { z as z16 } from "zod";
|
|
691
|
+
var inputSchema16 = {
|
|
692
|
+
rankRadarId: z16.string().uuid().describe("The Rank Radar UUID to add the search terms to (from `list_rank_radars`)."),
|
|
693
|
+
searchTerms: z16.array(z16.string().min(1)).min(1).max(ADD_SEARCH_TERMS_MAX).describe(
|
|
694
|
+
`The keywords to start tracking, 1\u2013${ADD_SEARCH_TERMS_MAX} per call. Must be unique. Amazon-ignored special characters (@, #, _, parentheses, \u2026) are rejected.`
|
|
695
|
+
)
|
|
696
|
+
};
|
|
697
|
+
var addRankRadarSearchTermsTool = {
|
|
698
|
+
name: "add_rank_radar_search_terms",
|
|
699
|
+
title: "Add Search Terms to a Rank Radar",
|
|
700
|
+
description: "Use this to start tracking extra keywords on an existing Rank Radar, instead of creating a new one with `create_rank_radar`. New keywords are added to the niche and tracked from now on; any matching keyword that was previously paused is resumed. Each newly tracked keyword takes one Daily Tracked Keywords slot, and the call fails if the quota is exhausted \u2014 check `get_quota` first. Reversible with `pause_rank_radar_search_terms`, which frees the slots again, so it needs no `confirm`. Returns `originBreakdown` (where each submitted term ended up) and `keywordToRankRadarKeywordIdMap`, whose ids are what the pause/resume search-term tools take.",
|
|
701
|
+
inputSchema: inputSchema16,
|
|
702
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
703
|
+
handler: async (args, ctx) => {
|
|
704
|
+
return await httpPost(
|
|
705
|
+
{ config: ctx.config, toolName: "add_rank_radar_search_terms" },
|
|
706
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/search-terms`,
|
|
707
|
+
{ searchTerms: args.searchTerms }
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
// src/tools/pause-rank-radar-search-terms.ts
|
|
713
|
+
import { z as z17 } from "zod";
|
|
714
|
+
var inputSchema17 = {
|
|
715
|
+
rankRadarId: z17.string().uuid().describe("The Rank Radar UUID the search terms belong to."),
|
|
716
|
+
rankRadarKeywordIds: z17.array(z17.string().uuid()).min(1).describe(
|
|
717
|
+
"The Rank Radar keyword ids to pause. These are the `id` values from `get_rank_radar_data`, or the values of `keywordToRankRadarKeywordIdMap` returned by `add_rank_radar_search_terms` \u2014 not the keyword text."
|
|
718
|
+
)
|
|
719
|
+
};
|
|
720
|
+
var pauseRankRadarSearchTermsTool = {
|
|
721
|
+
name: "pause_rank_radar_search_terms",
|
|
722
|
+
title: "Pause Search Terms of a Rank Radar",
|
|
723
|
+
description: "Use this to stop tracking individual keywords on a Rank Radar while keeping the Rank Radar itself active \u2014 the way to trim a keyword set the user finds too broad. The DataDive API calls this 'archiving' the search terms; nothing is lost. The paused keywords keep their history and their Daily Tracked Keywords slots are freed for other keywords. Reversible with `resume_rank_radar_search_terms`, so it needs no `confirm`. Takes keyword ids, not keyword text: get them from `get_rank_radar_data`. Safe to repeat: already-paused terms are left unchanged.",
|
|
724
|
+
inputSchema: inputSchema17,
|
|
725
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
726
|
+
handler: async (args, ctx) => {
|
|
727
|
+
await httpPost(
|
|
728
|
+
{ config: ctx.config, toolName: "pause_rank_radar_search_terms" },
|
|
729
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/search-terms/archive`,
|
|
730
|
+
{ rankRadarKeywordIds: args.rankRadarKeywordIds }
|
|
731
|
+
);
|
|
732
|
+
return {
|
|
733
|
+
status: "paused",
|
|
734
|
+
rankRadarId: args.rankRadarId,
|
|
735
|
+
rankRadarKeywordIds: args.rankRadarKeywordIds
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
// src/tools/resume-rank-radar-search-terms.ts
|
|
741
|
+
import { z as z18 } from "zod";
|
|
742
|
+
var inputSchema18 = {
|
|
743
|
+
rankRadarId: z18.string().uuid().describe("The Rank Radar UUID the search terms belong to."),
|
|
744
|
+
rankRadarKeywordIds: z18.array(z18.string().uuid()).min(1).describe(
|
|
745
|
+
"The Rank Radar keyword ids to resume. These are the `id` values from `get_rank_radar_data`, or the values of `keywordToRankRadarKeywordIdMap` returned by `add_rank_radar_search_terms` \u2014 not the keyword text."
|
|
746
|
+
)
|
|
747
|
+
};
|
|
748
|
+
var resumeRankRadarSearchTermsTool = {
|
|
749
|
+
name: "resume_rank_radar_search_terms",
|
|
750
|
+
title: "Resume Paused Search Terms of a Rank Radar",
|
|
751
|
+
description: "Use this to start tracking keywords again that were paused with `pause_rank_radar_search_terms`. Each resumed keyword takes back one Daily Tracked Keywords slot, and the call fails if the quota is exhausted \u2014 check `get_quota` first. Reversible with `pause_rank_radar_search_terms`, so it needs no `confirm`. Takes keyword ids, not keyword text: get them from `get_rank_radar_data`. Safe to repeat: already-active terms are left unchanged.",
|
|
752
|
+
inputSchema: inputSchema18,
|
|
753
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
754
|
+
handler: async (args, ctx) => {
|
|
755
|
+
await httpPost(
|
|
756
|
+
{ config: ctx.config, toolName: "resume_rank_radar_search_terms" },
|
|
757
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/search-terms/resume`,
|
|
758
|
+
{ rankRadarKeywordIds: args.rankRadarKeywordIds }
|
|
759
|
+
);
|
|
760
|
+
return {
|
|
761
|
+
status: "resumed",
|
|
762
|
+
rankRadarId: args.rankRadarId,
|
|
763
|
+
rankRadarKeywordIds: args.rankRadarKeywordIds
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
|
|
768
|
+
// src/tools/generate-listing-copy.ts
|
|
769
|
+
import { z as z19 } from "zod";
|
|
770
|
+
var inputSchema19 = {
|
|
771
|
+
nicheId: z19.string().min(1).describe("The niche whose keyword data the copy is written from. Get one from `list_niches`."),
|
|
772
|
+
strategy: z19.enum(LISTING_COPY_STRATEGIES).describe(
|
|
773
|
+
"Which generation strategy to use. `cosmo` targets Amazon's COSMO relevance model, `ranking-juice` optimises for DataDive's ranking-juice score, `nlp` writes for keyword coverage, and `cosmo-rufus` targets COSMO plus the Rufus shopping assistant. Ask the user if they have no preference."
|
|
774
|
+
),
|
|
775
|
+
currentListing: z19.record(z19.union([z19.string(), z19.array(z19.string())])).describe(
|
|
776
|
+
'The seller\'s existing listing to rewrite, as an object \u2014 e.g. `{ "title": "...", "description": "...", "bullets": ["...", "..."] }`. Pass what the user has; it is the starting point the generated copy builds on.'
|
|
777
|
+
),
|
|
778
|
+
confirm: z19.boolean().optional().describe(
|
|
779
|
+
"Must be true to proceed \u2014 each generation spends one AI Copywriter prompt from the quota. Confirm the cost with the user first."
|
|
780
|
+
)
|
|
781
|
+
};
|
|
782
|
+
var generateListingCopyTool = {
|
|
783
|
+
name: "generate_listing_copy",
|
|
784
|
+
title: "Generate Listing Copy for a Niche",
|
|
785
|
+
description: "Use this to draft an optimised Amazon listing \u2014 title, bullets and description \u2014 from a niche's keyword research and the seller's current listing. It writes text only: nothing is published to Amazon, and the user still has to paste the result into Seller Central. \u26A0\uFE0F Spends one AI Copywriter prompt from the quota per call and cannot be undone \u2014 set `confirm: true` only after the user approves. Not safe to retry: each call spends another prompt, so if a call errors or times out, poll `get_listing_copy_generation_status` instead of re-calling. Runs asynchronously: returns a `generationId` \u2014 poll `get_listing_copy_generation_status` with it until the status is `complete`.",
|
|
786
|
+
inputSchema: inputSchema19,
|
|
787
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
788
|
+
handler: async (args, ctx) => {
|
|
789
|
+
const pending = requireConfirmation(
|
|
790
|
+
args.confirm,
|
|
791
|
+
ctx,
|
|
792
|
+
"Generating listing copy consumes one AI Copywriter prompt from the organization's quota. Check the remaining balance with `get_quota` if the user needs it."
|
|
793
|
+
);
|
|
794
|
+
if (pending) return pending;
|
|
795
|
+
return await httpPost(
|
|
796
|
+
{ config: ctx.config, toolName: "generate_listing_copy" },
|
|
797
|
+
`/v1/niches/${encodeURIComponent(args.nicheId)}/ai-copywriter`,
|
|
798
|
+
{ prompt: args.strategy, listingToInclude: args.currentListing }
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
};
|
|
802
|
+
|
|
803
|
+
// src/tools/get-listing-copy-generation-status.ts
|
|
804
|
+
import { z as z20 } from "zod";
|
|
805
|
+
var inputSchema20 = {
|
|
806
|
+
nicheId: z20.string().min(1).describe("The niche the generation was started for."),
|
|
807
|
+
generationId: z20.string().min(1).describe("The `generationId` returned by `generate_listing_copy`.")
|
|
808
|
+
};
|
|
809
|
+
var getListingCopyGenerationStatusTool = {
|
|
810
|
+
name: "get_listing_copy_generation_status",
|
|
811
|
+
title: "Get Listing Copy Generation Status",
|
|
812
|
+
description: "Use this to poll a listing-copy draft started with `generate_listing_copy` until it finishes. Returns one of three shapes keyed by `status`: `generating` (still running \u2014 poll again in a few seconds), `complete` (with `result`, carrying the generated `title`, `bullets`, `description`, `itemHighlights` and its `rankingJuice` score), or `failed` (with an `error` message). Polling is free \u2014 it does not spend another AI Copywriter prompt, so always poll rather than re-calling `generate_listing_copy`.",
|
|
813
|
+
inputSchema: inputSchema20,
|
|
814
|
+
annotations: { readOnlyHint: true },
|
|
815
|
+
handler: async (args, ctx) => {
|
|
816
|
+
return await httpGet(
|
|
817
|
+
{ config: ctx.config, toolName: "get_listing_copy_generation_status" },
|
|
818
|
+
`/v1/niches/${encodeURIComponent(args.nicheId)}/ai-copywriter/${encodeURIComponent(args.generationId)}`
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
|
|
823
|
+
// src/tools/list-seller-profiles.ts
|
|
824
|
+
import { z as z21 } from "zod";
|
|
825
|
+
var inputSchema21 = {
|
|
826
|
+
currentPage: z21.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
827
|
+
pageSize: z21.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
|
|
568
828
|
};
|
|
569
829
|
var listSellerProfilesTool = {
|
|
570
830
|
name: "list_seller_profiles",
|
|
571
831
|
title: "List Connected Amazon Seller Profiles",
|
|
572
832
|
description: 'Use this when the user asks which Amazon seller accounts are connected, or as the discovery step to find the `sellerId` and `marketplace` required by `get_asin_inventory_distribution`, `get_seller_catalog`, `get_seller_listing_changes`, and the alert tools. Returns a paginated list of the organization\'s connected seller profiles \u2014 each item has sellerId, sellerName, marketplace (e.g. "com", "co.uk"), hasAdApi (whether Advertising API credentials are connected), and createdAt \u2014 plus pagination metadata (currentPage, pageSize, total, lastPage, hasNext, hasPrev).',
|
|
573
|
-
inputSchema:
|
|
833
|
+
inputSchema: inputSchema21,
|
|
574
834
|
annotations: { readOnlyHint: true },
|
|
575
835
|
handler: async (args, ctx) => {
|
|
576
836
|
return await httpGet(
|
|
@@ -585,15 +845,15 @@ var listSellerProfilesTool = {
|
|
|
585
845
|
};
|
|
586
846
|
|
|
587
847
|
// src/tools/get-seller-catalog.ts
|
|
588
|
-
import { z as
|
|
848
|
+
import { z as z23 } from "zod";
|
|
589
849
|
|
|
590
850
|
// src/tools/seller-scoped.ts
|
|
591
|
-
import { z as
|
|
851
|
+
import { z as z22 } from "zod";
|
|
592
852
|
var sellerScopedInputSchema = {
|
|
593
|
-
sellerId:
|
|
853
|
+
sellerId: z22.string().min(1).describe(
|
|
594
854
|
"Amazon seller account ID. Get it from `list_seller_profiles`, or find it on the Connections page at https://2.datadive.tools."
|
|
595
855
|
),
|
|
596
|
-
marketplace:
|
|
856
|
+
marketplace: z22.enum(SUPPORTED_MARKETPLACES).describe('Amazon marketplace code, e.g. "com" for amazon.com or "co.uk" for amazon.co.uk.')
|
|
597
857
|
};
|
|
598
858
|
function sellerMarketplacePath(sellerId, marketplace, suffix) {
|
|
599
859
|
return `/v1/seller_profiles/${encodeURIComponent(sellerId)}/marketplaces/${encodeURIComponent(
|
|
@@ -602,19 +862,19 @@ function sellerMarketplacePath(sellerId, marketplace, suffix) {
|
|
|
602
862
|
}
|
|
603
863
|
|
|
604
864
|
// src/tools/get-seller-catalog.ts
|
|
605
|
-
var
|
|
865
|
+
var inputSchema22 = {
|
|
606
866
|
...sellerScopedInputSchema,
|
|
607
|
-
search:
|
|
608
|
-
brand:
|
|
609
|
-
status:
|
|
610
|
-
currentPage:
|
|
611
|
-
pageSize:
|
|
867
|
+
search: z23.string().min(1).optional().describe("Case-insensitive partial match on product title or brand."),
|
|
868
|
+
brand: z23.string().min(1).optional().describe("Case-insensitive partial match on brand name."),
|
|
869
|
+
status: z23.enum(CATALOG_STATUSES).optional().describe('Listing status filter. "Active" (default) or "all".'),
|
|
870
|
+
currentPage: z23.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
871
|
+
pageSize: z23.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
|
|
612
872
|
};
|
|
613
873
|
var getSellerCatalogTool = {
|
|
614
874
|
name: "get_seller_catalog",
|
|
615
875
|
title: "List Catalog ASINs for a Seller",
|
|
616
876
|
description: "Use this when the user wants to browse or search a seller's own Amazon catalog \u2014 the products they sell on a given marketplace. Requires a `sellerId` + `marketplace` (use `list_seller_profiles` to discover them). Filter by `search` (title/brand), `brand`, and `status` (Active by default, or all). Returns a paginated list where each item has asin, title, parentAsin, brand, status, imageUrl, and hasVariations, plus pagination metadata (currentPage, pageSize, total, lastPage, hasNext, hasPrev).",
|
|
617
|
-
inputSchema:
|
|
877
|
+
inputSchema: inputSchema22,
|
|
618
878
|
annotations: { readOnlyHint: true },
|
|
619
879
|
handler: async (args, ctx) => {
|
|
620
880
|
return await httpGet(
|
|
@@ -632,28 +892,28 @@ var getSellerCatalogTool = {
|
|
|
632
892
|
};
|
|
633
893
|
|
|
634
894
|
// src/tools/get-seller-listing-changes.ts
|
|
635
|
-
import { z as
|
|
636
|
-
var
|
|
895
|
+
import { z as z24 } from "zod";
|
|
896
|
+
var inputSchema23 = {
|
|
637
897
|
...sellerScopedInputSchema,
|
|
638
|
-
types:
|
|
639
|
-
asin:
|
|
640
|
-
brand:
|
|
641
|
-
search:
|
|
642
|
-
startDate:
|
|
643
|
-
endDate:
|
|
644
|
-
sortBy:
|
|
645
|
-
sortOrder:
|
|
646
|
-
includeCorrelations:
|
|
898
|
+
types: z24.array(z24.enum(LISTING_CHANGE_TYPES)).min(1).optional().describe('Filter to specific change types. Omit for all. Any of "Price", "Content", "Image".'),
|
|
899
|
+
asin: z24.string().min(1).optional().describe("Filter to an exact ASIN or parent ASIN."),
|
|
900
|
+
brand: z24.string().min(1).optional().describe("Case-insensitive partial match on brand name."),
|
|
901
|
+
search: z24.string().min(1).optional().describe("Case-insensitive partial match on product title or brand."),
|
|
902
|
+
startDate: z24.string().regex(ISO_8601, "startDate must be an ISO-8601 date or timestamp (e.g. 2026-05-01 or 2026-05-01T00:00:00Z)").optional().describe("ISO-8601 date/timestamp; return only changes detected on or after this time."),
|
|
903
|
+
endDate: z24.string().regex(ISO_8601, "endDate must be an ISO-8601 date or timestamp (e.g. 2026-05-31 or 2026-05-31T23:59:59Z)").optional().describe("ISO-8601 date/timestamp; return only changes detected on or before this time."),
|
|
904
|
+
sortBy: z24.enum(LISTING_CHANGE_SORT_BY).optional().describe('Sort field. "date" (default) or "type".'),
|
|
905
|
+
sortOrder: z24.enum(SORT_ORDER).optional().describe('Sort direction. "DESC" (default) or "ASC".'),
|
|
906
|
+
includeCorrelations: z24.boolean().optional().describe(
|
|
647
907
|
"When true, include the ranking/conversion `correlation` object per change (CVR and search-term movement before vs after). Defaults to false."
|
|
648
908
|
),
|
|
649
|
-
currentPage:
|
|
650
|
-
pageSize:
|
|
909
|
+
currentPage: z24.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
910
|
+
pageSize: z24.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
|
|
651
911
|
};
|
|
652
912
|
var getSellerListingChangesTool = {
|
|
653
913
|
name: "get_seller_listing_changes",
|
|
654
914
|
title: "List Listing Changes for a Seller",
|
|
655
915
|
description: "Use this when the user asks what changed on their Amazon listings \u2014 price, content (title/bullets/description), or image edits \u2014 for a seller account. Requires a `sellerId` + `marketplace` (use `list_seller_profiles` to discover them). Filter by `types`, `asin`/parent ASIN, `brand`, `search`, and a `startDate`/`endDate` range; sort with `sortBy`/`sortOrder`. Set `includeCorrelations: true` to attach the ranking/conversion impact per change. Returns a paginated list where each item has asin, title, imageUrl, date, type, contentType, description, previousValue, newValue, and (optionally) correlation, plus pagination metadata (currentPage, pageSize, total, lastPage, hasNext, hasPrev).",
|
|
656
|
-
inputSchema:
|
|
916
|
+
inputSchema: inputSchema23,
|
|
657
917
|
annotations: { readOnlyHint: true },
|
|
658
918
|
handler: async (args, ctx) => {
|
|
659
919
|
return await httpGet(
|
|
@@ -678,13 +938,13 @@ var getSellerListingChangesTool = {
|
|
|
678
938
|
};
|
|
679
939
|
|
|
680
940
|
// src/tools/get-asin-inventory-distribution.ts
|
|
681
|
-
import { z as
|
|
682
|
-
var
|
|
683
|
-
sellerId:
|
|
941
|
+
import { z as z25 } from "zod";
|
|
942
|
+
var inputSchema24 = {
|
|
943
|
+
sellerId: z25.string().min(1).describe(
|
|
684
944
|
"Amazon seller account ID as connected to DataDive. Get it from `list_seller_profiles`, or find it on the Connections page at https://2.datadive.tools."
|
|
685
945
|
),
|
|
686
|
-
marketplace:
|
|
687
|
-
asin:
|
|
946
|
+
marketplace: z25.enum(SUPPORTED_MARKETPLACES).describe('Amazon marketplace code, e.g. "com" for amazon.com or "co.uk" for amazon.co.uk.'),
|
|
947
|
+
asin: z25.string().regex(/^[A-Z0-9]{10}$/, "ASIN must be 10 uppercase alphanumeric characters (e.g. B08XYZ1234).").describe(
|
|
688
948
|
"Amazon Standard Identification Number (10 uppercase alphanumeric characters, e.g. B08XYZ1234)."
|
|
689
949
|
)
|
|
690
950
|
};
|
|
@@ -692,7 +952,7 @@ var getAsinInventoryDistributionTool = {
|
|
|
692
952
|
name: "get_asin_inventory_distribution",
|
|
693
953
|
title: "Get Per-Fulfillment-Center Inventory Distribution for an ASIN",
|
|
694
954
|
description: "Use this when the user asks about inventory levels, stock by fulfillment center, or where their units are sitting across Amazon's fulfillment network for a specific ASIN. Requires the Amazon sellerId (from `list_seller_profiles` or the user's DataDive Connections page at https://2.datadive.tools), the marketplace code, and the ASIN. Returns totalSellableUnits and a per-FC `distribution` array (fc, state, availableStock, availableStockPercentage). `lastUpdatedAt` may be null when no successful inventory ingestion has occurred in the last 30 days.",
|
|
695
|
-
inputSchema:
|
|
955
|
+
inputSchema: inputSchema24,
|
|
696
956
|
annotations: { readOnlyHint: true },
|
|
697
957
|
handler: async (args, ctx) => {
|
|
698
958
|
return await httpGet(
|
|
@@ -705,18 +965,18 @@ var getAsinInventoryDistributionTool = {
|
|
|
705
965
|
};
|
|
706
966
|
|
|
707
967
|
// src/tools/alert-query.ts
|
|
708
|
-
import { z as
|
|
968
|
+
import { z as z26 } from "zod";
|
|
709
969
|
var alertsQueryInputSchema = {
|
|
710
|
-
sellerId:
|
|
711
|
-
marketplace:
|
|
712
|
-
status:
|
|
970
|
+
sellerId: z26.string().min(1).max(50).optional().describe('Filter to a single connected Amazon seller account ID, e.g. "A1B2C3D4E5".'),
|
|
971
|
+
marketplace: z26.enum(SUPPORTED_MARKETPLACES).optional().describe('Filter to a single Amazon marketplace code, e.g. "com" for amazon.com or "co.uk" for amazon.co.uk.'),
|
|
972
|
+
status: z26.enum(ALERT_STATUSES).optional().describe(
|
|
713
973
|
"Lifecycle filter. `active` (default) returns unresolved alerts, `resolved` returns resolved alerts, `all` returns both. Dismissed alerts are never returned."
|
|
714
974
|
),
|
|
715
|
-
updatedSince:
|
|
975
|
+
updatedSince: z26.string().regex(ISO_8601, "updatedSince must be an ISO-8601 date or timestamp (e.g. 2026-05-01 or 2026-05-01T00:00:00Z)").optional().describe(
|
|
716
976
|
"ISO-8601 timestamp; return only alerts surfaced at or after this time (filters on `lastAlertedAt`). Use it to incrementally sync since your last poll. Defaults to the last 30 days when omitted."
|
|
717
977
|
),
|
|
718
|
-
currentPage:
|
|
719
|
-
pageSize:
|
|
978
|
+
currentPage: z26.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
979
|
+
pageSize: z26.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
|
|
720
980
|
};
|
|
721
981
|
|
|
722
982
|
// src/tools/list-indexing-issue-alerts.ts
|
|
@@ -766,12 +1026,12 @@ var listBlindSpendAlertsTool = {
|
|
|
766
1026
|
};
|
|
767
1027
|
|
|
768
1028
|
// src/tools/get-quota.ts
|
|
769
|
-
var
|
|
1029
|
+
var inputSchema25 = {};
|
|
770
1030
|
var getQuotaTool = {
|
|
771
1031
|
name: "get_quota",
|
|
772
1032
|
title: "Get Quota Usage",
|
|
773
1033
|
description: "Use this when the user asks how much quota or how many tokens they have left, or before creating a Niche Dive or Rank Radar to check remaining headroom. Returns current quota usage and capacity for each billable feature \u2014 DIVED_ASINS (Dive tokens), RANK_RADAR_KEYWORDS (tracked keywords), PRODUCT_BRIEF_ASINS, and AI_COPYWRITER_PROMPTS \u2014 each with `used` and `capacity` (null when unlimited / not applicable), plus `nextRefreshDate` (ISO-8601 timestamp of the next quota reset, or null). Takes no arguments.",
|
|
774
|
-
inputSchema:
|
|
1034
|
+
inputSchema: inputSchema25,
|
|
775
1035
|
annotations: { readOnlyHint: true },
|
|
776
1036
|
handler: async (_args, ctx) => {
|
|
777
1037
|
return await httpGet({ config: ctx.config, toolName: "get_quota" }, "/v1/quota");
|
|
@@ -779,20 +1039,20 @@ var getQuotaTool = {
|
|
|
779
1039
|
};
|
|
780
1040
|
|
|
781
1041
|
// src/tools/list-usage.ts
|
|
782
|
-
import { z as
|
|
783
|
-
var
|
|
784
|
-
type:
|
|
785
|
-
search:
|
|
786
|
-
startDate:
|
|
787
|
-
endDate:
|
|
788
|
-
currentPage:
|
|
789
|
-
pageSize:
|
|
1042
|
+
import { z as z27 } from "zod";
|
|
1043
|
+
var inputSchema26 = {
|
|
1044
|
+
type: z27.enum(BILLABLE_FEATURE_TYPES).optional().describe("Filter to a single billable feature type. Omit to return all types."),
|
|
1045
|
+
search: z27.string().min(1).optional().describe("Case-insensitive partial match on the user's name or email."),
|
|
1046
|
+
startDate: z27.string().regex(ISO_8601, "startDate must be an ISO-8601 date or timestamp (e.g. 2026-05-01 or 2026-05-01T00:00:00Z)").optional().describe("ISO-8601 date/timestamp; return only usage logs recorded on or after this time."),
|
|
1047
|
+
endDate: z27.string().regex(ISO_8601, "endDate must be an ISO-8601 date or timestamp (e.g. 2026-05-31 or 2026-05-31T23:59:59Z)").optional().describe("ISO-8601 date/timestamp; return only usage logs recorded on or before this time."),
|
|
1048
|
+
currentPage: z27.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1049
|
+
pageSize: z27.number().int().min(1).max(200).optional().describe("Items per page (max 200). Defaults to 50.")
|
|
790
1050
|
};
|
|
791
1051
|
var listUsageTool = {
|
|
792
1052
|
name: "list_usage",
|
|
793
1053
|
title: "List Billable Usage Logs",
|
|
794
1054
|
description: "Use this when the user asks who consumed tokens, how their quota was spent, or wants an audit of billable activity over a date range. Retrieves a paginated list of billable feature usage logs for the organization \u2014 each entry is a token-consumption event (a dive, rank-radar creation, AI copywriter prompt, etc.). Filter by `type` (billable feature), `search` (user name/email), and `startDate`/`endDate`. Each item includes name, email, qty (tokens consumed), type, action (specific operation), nicheId/nicheName, rankRadarId, and date, plus pagination metadata (currentPage, pageSize, total, lastPage, hasNext, hasPrev).",
|
|
795
|
-
inputSchema:
|
|
1055
|
+
inputSchema: inputSchema26,
|
|
796
1056
|
annotations: { readOnlyHint: true },
|
|
797
1057
|
handler: async (args, ctx) => {
|
|
798
1058
|
return await httpGet(
|
|
@@ -823,6 +1083,15 @@ var allTools = [
|
|
|
823
1083
|
createNicheDiveTool,
|
|
824
1084
|
rediveNicheTool,
|
|
825
1085
|
getDiveStatusTool,
|
|
1086
|
+
addRankRadarSearchTermsTool,
|
|
1087
|
+
pauseRankRadarSearchTermsTool,
|
|
1088
|
+
resumeRankRadarSearchTermsTool,
|
|
1089
|
+
pauseRankRadarTool,
|
|
1090
|
+
resumeRankRadarTool,
|
|
1091
|
+
deleteRankRadarTool,
|
|
1092
|
+
deleteNicheTool,
|
|
1093
|
+
generateListingCopyTool,
|
|
1094
|
+
getListingCopyGenerationStatusTool,
|
|
826
1095
|
listSellerProfilesTool,
|
|
827
1096
|
getSellerCatalogTool,
|
|
828
1097
|
getSellerListingChangesTool,
|