@datadive-tools/mcp 0.17.0 → 0.18.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 +1 -1
- package/dist/index.js +302 -83
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +6 -0
- package/dist/lib.js +302 -83
- package/dist/lib.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -144,7 +144,7 @@ function extractMessage(body) {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
// package.json
|
|
147
|
-
var version = "0.
|
|
147
|
+
var version = "0.18.0";
|
|
148
148
|
|
|
149
149
|
// src/http/client.ts
|
|
150
150
|
var PKG_VERSION = version;
|
|
@@ -184,6 +184,7 @@ async function httpGet(ctx, path, query) {
|
|
|
184
184
|
method: "GET",
|
|
185
185
|
headers: {
|
|
186
186
|
...authHeaders(ctx.config),
|
|
187
|
+
...forwardedForHeader(ctx.config),
|
|
187
188
|
accept: "application/json",
|
|
188
189
|
"user-agent": userAgent(ctx.toolName)
|
|
189
190
|
}
|
|
@@ -201,6 +202,27 @@ async function httpPost(ctx, path, body) {
|
|
|
201
202
|
method: "POST",
|
|
202
203
|
headers: {
|
|
203
204
|
...authHeaders(ctx.config),
|
|
205
|
+
...forwardedForHeader(ctx.config),
|
|
206
|
+
accept: "application/json",
|
|
207
|
+
"content-type": "application/json",
|
|
208
|
+
"user-agent": userAgent(ctx.toolName)
|
|
209
|
+
},
|
|
210
|
+
body: JSON.stringify(body)
|
|
211
|
+
});
|
|
212
|
+
} catch (e) {
|
|
213
|
+
throw networkError(url, e);
|
|
214
|
+
}
|
|
215
|
+
return handleResponse(res);
|
|
216
|
+
}
|
|
217
|
+
async function httpPatch(ctx, path, body) {
|
|
218
|
+
const url = buildUrl(ctx.config.baseUrl, path);
|
|
219
|
+
let res;
|
|
220
|
+
try {
|
|
221
|
+
res = await fetch(url, {
|
|
222
|
+
method: "PATCH",
|
|
223
|
+
headers: {
|
|
224
|
+
...authHeaders(ctx.config),
|
|
225
|
+
...forwardedForHeader(ctx.config),
|
|
204
226
|
accept: "application/json",
|
|
205
227
|
"content-type": "application/json",
|
|
206
228
|
"user-agent": userAgent(ctx.toolName)
|
|
@@ -220,6 +242,7 @@ async function httpDelete(ctx, path) {
|
|
|
220
242
|
method: "DELETE",
|
|
221
243
|
headers: {
|
|
222
244
|
...authHeaders(ctx.config),
|
|
245
|
+
...forwardedForHeader(ctx.config),
|
|
223
246
|
accept: "application/json",
|
|
224
247
|
"user-agent": userAgent(ctx.toolName)
|
|
225
248
|
}
|
|
@@ -265,6 +288,9 @@ function authHeaders(config) {
|
|
|
265
288
|
const c = config.credentials;
|
|
266
289
|
return c.kind === "bearer" ? { authorization: `Bearer ${c.token}` } : { "x-api-key": c.apiKey };
|
|
267
290
|
}
|
|
291
|
+
function forwardedForHeader(config) {
|
|
292
|
+
return config.forwardedFor ? { "x-forwarded-for": config.forwardedFor } : {};
|
|
293
|
+
}
|
|
268
294
|
function unwrap(body) {
|
|
269
295
|
if (!isObject(body)) return body;
|
|
270
296
|
if (!("data" in body)) return body;
|
|
@@ -431,6 +457,10 @@ var KEYWORD_EXCLUSIONS_MAX_PER_CALL = 100;
|
|
|
431
457
|
var KEYWORD_EXCLUSIONS_MAX_PER_NICHE = 1e3;
|
|
432
458
|
var RANK_RADAR_STATES = ["ACTIVE", "PAUSED", "ARCHIVED"];
|
|
433
459
|
var RANK_RADAR_STATUSES = [...RANK_RADAR_STATES, "ALL"];
|
|
460
|
+
var TAG_TITLE_MAX_LENGTH = 100;
|
|
461
|
+
var TAG_KEYWORD_IDS_MAX = 1e3;
|
|
462
|
+
var TAG_RESERVED_COLOR = "#EB5757";
|
|
463
|
+
var TAG_HEX_COLOR_PATTERN = /^#[0-9A-Fa-f]{6}$/;
|
|
434
464
|
var PPC_CAMPAIGN_BASE_SORT_BY = [
|
|
435
465
|
"name",
|
|
436
466
|
"state",
|
|
@@ -566,7 +596,7 @@ async function readAllKeywords(args, ctx) {
|
|
|
566
596
|
var getRankRadarDataTool = {
|
|
567
597
|
name: "get_rank_radar_data",
|
|
568
598
|
title: "Get Keyword Rankings for a Rank Radar",
|
|
569
|
-
description: `Use this to analyze keyword ranking trends over time. Requires startDate and endDate (yyyy-mm-dd), at most ${RANK_RADAR_MAX_DATE_RANGE_DAYS} days apart. Retrieves historical keyword ranking data for the specified Rank Radar within the date range. Without \`currentPage\` and \`pageSize\` it returns every active keyword in one result. To read one page instead \u2014 faster for large Rank Radars \u2014 pass \`currentPage\` and/or \`pageSize\` (max ${RANK_RADAR_KEYWORDS_MAX_PAGE_SIZE}) and continue with \`currentPage\` + 1 while \`hasNext\` is true. The response carries currentPage, pageSize, total, lastPage, hasNext and hasPrev; \`total\` is the Rank Radar's active keyword count. Paused keywords are not included. Each keyword has id, keyword, searchVolume, relevancy, ranks (per-day { date, organicRank, sponsoredRank, impressionRank }), and
|
|
599
|
+
description: `Use this to analyze keyword ranking trends over time. Requires startDate and endDate (yyyy-mm-dd), at most ${RANK_RADAR_MAX_DATE_RANGE_DAYS} days apart. Retrieves historical keyword ranking data for the specified Rank Radar within the date range. Without \`currentPage\` and \`pageSize\` it returns every active keyword in one result. To read one page instead \u2014 faster for large Rank Radars \u2014 pass \`currentPage\` and/or \`pageSize\` (max ${RANK_RADAR_KEYWORDS_MAX_PAGE_SIZE}) and continue with \`currentPage\` + 1 while \`hasNext\` is true. The response carries currentPage, pageSize, total, lastPage, hasNext and hasPrev; \`total\` is the Rank Radar's active keyword count. Paused keywords are not included. Each keyword has id, keyword, searchVolume, relevancy, ranks (per-day { date, organicRank, sponsoredRank, impressionRank }), and \`highlights\` \u2014 the user tags on this keyword. Each \`highlights\` entry is the same object \`list_rank_radar_tags\` returns (id, title, color, description, startAt, endAt, type, krtId, krtKeywordId); its \`id\` is the \`tagId\` the tag-management tools take. A rank of 101 means the product was not in the top 100 results that day. For PPC metrics use \`get_rank_radar_ppc_data\`; for Search Query Performance use \`get_rank_radar_sqp_data\`. Use after \`list_rank_radars\` to discover a \`rankRadarId\`.`,
|
|
570
600
|
inputSchema: inputSchema8,
|
|
571
601
|
annotations: { readOnlyHint: true },
|
|
572
602
|
handler: async (args, ctx) => {
|
|
@@ -1170,17 +1200,193 @@ var resumeRankRadarSearchTermsTool = {
|
|
|
1170
1200
|
}
|
|
1171
1201
|
};
|
|
1172
1202
|
|
|
1173
|
-
// src/tools/
|
|
1203
|
+
// src/tools/list-rank-radar-tags.ts
|
|
1174
1204
|
import { z as z26 } from "zod";
|
|
1205
|
+
var LIST_RANK_RADAR_TAGS_MAX_PAGE_SIZE = 50;
|
|
1175
1206
|
var inputSchema27 = {
|
|
1176
|
-
|
|
1177
|
-
|
|
1207
|
+
rankRadarId: z26.string().uuid().describe("The Rank Radar UUID whose tags to list (from `list_rank_radars`)."),
|
|
1208
|
+
currentPage: z26.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1209
|
+
pageSize: z26.number().int().min(1).max(LIST_RANK_RADAR_TAGS_MAX_PAGE_SIZE).optional().describe(`Items per page (max ${LIST_RANK_RADAR_TAGS_MAX_PAGE_SIZE}). Defaults to 20.`)
|
|
1210
|
+
};
|
|
1211
|
+
var listRankRadarTagsTool = {
|
|
1212
|
+
name: "list_rank_radar_tags",
|
|
1213
|
+
title: "List Tags of a Rank Radar",
|
|
1214
|
+
description: `Use this to find a \`tagId\` before calling \`update_rank_radar_tag\`, \`delete_rank_radar_tag\`, \`add_rank_radar_tag_search_terms\` or \`remove_rank_radar_tag_search_terms\`. Returns the user tags ("highlights") on the specified Rank Radar, ordered by title (case-insensitive, ascending). Each row carries \`id\`, \`title\`, \`color\`, \`description\`, \`startAt\`, \`endAt\`, \`createdAt\`, and \`keywordCount\` \u2014 the number of Rank Radar keywords this tag is applied to. The system "paused" tag (the one the quota pauser writes with a reserved colour) is not listed and cannot be addressed from these tools. Supports pagination metadata (currentPage, pageSize, total, lastPage, hasNext, hasPrev); a page holds at most ${LIST_RANK_RADAR_TAGS_MAX_PAGE_SIZE} tags.`,
|
|
1215
|
+
inputSchema: inputSchema27,
|
|
1216
|
+
annotations: { readOnlyHint: true },
|
|
1217
|
+
handler: async (args, ctx) => {
|
|
1218
|
+
return await httpGet(
|
|
1219
|
+
{ config: ctx.config, toolName: "list_rank_radar_tags" },
|
|
1220
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/tags`,
|
|
1221
|
+
{
|
|
1222
|
+
currentPage: args.currentPage,
|
|
1223
|
+
pageSize: args.pageSize
|
|
1224
|
+
}
|
|
1225
|
+
);
|
|
1226
|
+
}
|
|
1227
|
+
};
|
|
1228
|
+
|
|
1229
|
+
// src/tools/create-rank-radar-tag.ts
|
|
1230
|
+
import { z as z27 } from "zod";
|
|
1231
|
+
var inputSchema28 = {
|
|
1232
|
+
rankRadarId: z27.string().uuid().describe("The Rank Radar UUID to create the tag on (from `list_rank_radars`)."),
|
|
1233
|
+
title: z27.string().min(1).max(TAG_TITLE_MAX_LENGTH).describe(
|
|
1234
|
+
`Display title (1\u2013${TAG_TITLE_MAX_LENGTH} characters, trimmed on write). Must be unique on this Rank Radar, case-insensitive. A clash returns 409 with \`{ error: 'TAG_TITLE_EXISTS', existingTagId }\` \u2014 reuse that id instead of retrying.`
|
|
1235
|
+
),
|
|
1236
|
+
color: z27.string().regex(TAG_HEX_COLOR_PATTERN, "color must be in #RRGGBB form").optional().describe(
|
|
1237
|
+
`Hex colour in \`#RRGGBB\` form. Defaults to the UI grey when omitted. The reserved colour \`${TAG_RESERVED_COLOR}\` (used by the system "paused" tag) is rejected with 400.`
|
|
1238
|
+
),
|
|
1239
|
+
description: z27.string().optional().describe("Free-form description, e.g. 'Prime Day run-up'."),
|
|
1240
|
+
startAt: z27.string().optional().describe("ISO 8601 start date, e.g. '2026-07-01'. Required if `endAt` is set; `endAt >= startAt`."),
|
|
1241
|
+
endAt: z27.string().optional().describe("ISO 8601 end date, e.g. '2026-07-14'. Must be greater than or equal to `startAt`."),
|
|
1242
|
+
rankRadarKeywordIds: z27.array(z27.string().uuid()).min(1).max(TAG_KEYWORD_IDS_MAX).optional().describe(
|
|
1243
|
+
`Optional: Rank Radar keyword ids to tag on creation (1\u2013${TAG_KEYWORD_IDS_MAX}). These are the \`id\` values from \`get_rank_radar_data\`; the ids must all belong to this Rank Radar. To attach more later, use \`add_rank_radar_tag_search_terms\`.`
|
|
1244
|
+
)
|
|
1245
|
+
};
|
|
1246
|
+
var createRankRadarTagTool = {
|
|
1247
|
+
name: "create_rank_radar_tag",
|
|
1248
|
+
title: "Create a Rank Radar Tag",
|
|
1249
|
+
description: `Use this to create a new user tag ("highlight") on a Rank Radar \u2014 the way the UI marks a window on the ranking chart. Writing a tag costs nothing and is reversible with \`delete_rank_radar_tag\`, so no confirmation is required. Returns the new tag row (\`id\`, \`title\`, \`color\`, \`description\`, \`startAt\`, \`endAt\`, \`keywordCount\`, \`createdAt\`); the \`id\` is the \`tagId\` the other tag tools take. If the title clashes with an existing tag on this Rank Radar, the API answers 409 \`{ error: 'TAG_TITLE_EXISTS', existingTagId }\` so callers can reuse the existing tag without a follow-up \`list_rank_radar_tags\`. The reserved colour \`${TAG_RESERVED_COLOR}\` is rejected with 400. Pass \`rankRadarKeywordIds\` to tag a batch of keywords in the same call; otherwise create the tag and attach keywords later with \`add_rank_radar_tag_search_terms\`.`,
|
|
1250
|
+
inputSchema: inputSchema28,
|
|
1251
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1252
|
+
handler: async (args, ctx) => {
|
|
1253
|
+
const body = { title: args.title };
|
|
1254
|
+
if (args.color !== void 0) body.color = args.color;
|
|
1255
|
+
if (args.description !== void 0) body.description = args.description;
|
|
1256
|
+
if (args.startAt !== void 0) body.startAt = args.startAt;
|
|
1257
|
+
if (args.endAt !== void 0) body.endAt = args.endAt;
|
|
1258
|
+
if (args.rankRadarKeywordIds !== void 0) body.rankRadarKeywordIds = args.rankRadarKeywordIds;
|
|
1259
|
+
return await httpPost(
|
|
1260
|
+
{ config: ctx.config, toolName: "create_rank_radar_tag" },
|
|
1261
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/tags`,
|
|
1262
|
+
body
|
|
1263
|
+
);
|
|
1264
|
+
}
|
|
1265
|
+
};
|
|
1266
|
+
|
|
1267
|
+
// src/tools/update-rank-radar-tag.ts
|
|
1268
|
+
import { z as z28 } from "zod";
|
|
1269
|
+
var inputSchema29 = {
|
|
1270
|
+
rankRadarId: z28.string().uuid().describe("The Rank Radar UUID the tag belongs to (from `list_rank_radars`)."),
|
|
1271
|
+
tagId: z28.string().uuid().describe("The tag UUID to update (the `id` from `list_rank_radar_tags` or `create_rank_radar_tag`)."),
|
|
1272
|
+
title: z28.string().min(1).max(TAG_TITLE_MAX_LENGTH).optional().describe(
|
|
1273
|
+
`New title (1\u2013${TAG_TITLE_MAX_LENGTH} characters, trimmed on write). Must be unique on this Rank Radar, case-insensitive. A clash returns 409 with \`{ error: 'TAG_TITLE_EXISTS', existingTagId }\`.`
|
|
1274
|
+
),
|
|
1275
|
+
color: z28.string().regex(TAG_HEX_COLOR_PATTERN, "color must be in #RRGGBB form").optional().describe(`Hex colour in \`#RRGGBB\` form. The reserved colour \`${TAG_RESERVED_COLOR}\` is rejected with 400.`),
|
|
1276
|
+
description: z28.string().optional().describe("Free-form description. Pass an empty string to clear."),
|
|
1277
|
+
startAt: z28.string().optional().describe("ISO 8601 start date, e.g. '2026-07-01'. `endAt >= startAt`."),
|
|
1278
|
+
endAt: z28.string().optional().describe("ISO 8601 end date, e.g. '2026-07-14'. `endAt >= startAt`.")
|
|
1279
|
+
};
|
|
1280
|
+
var updateRankRadarTagTool = {
|
|
1281
|
+
name: "update_rank_radar_tag",
|
|
1282
|
+
title: "Update a Rank Radar Tag",
|
|
1283
|
+
description: "Use this to change a tag's title, colour, description, or date window. Partial update: only the fields you pass are modified, the rest are left as they are. The system \"paused\" tag (reserved colour, written by the quota pauser) cannot be addressed from here \u2014 the API answers 404. Writing a tag costs nothing and is reversible, so no confirmation is required. Returns the updated tag row. Title clashes return 409 `{ error: 'TAG_TITLE_EXISTS', existingTagId }`; the reserved colour returns 400; and `endAt < startAt` returns 400 (for whichever side the body omits, the comparison uses the stored value).",
|
|
1284
|
+
inputSchema: inputSchema29,
|
|
1285
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1286
|
+
handler: async (args, ctx) => {
|
|
1287
|
+
const body = {};
|
|
1288
|
+
if (args.title !== void 0) body.title = args.title;
|
|
1289
|
+
if (args.color !== void 0) body.color = args.color;
|
|
1290
|
+
if (args.description !== void 0) body.description = args.description;
|
|
1291
|
+
if (args.startAt !== void 0) body.startAt = args.startAt;
|
|
1292
|
+
if (args.endAt !== void 0) body.endAt = args.endAt;
|
|
1293
|
+
return await httpPatch(
|
|
1294
|
+
{ config: ctx.config, toolName: "update_rank_radar_tag" },
|
|
1295
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/tags/${encodeURIComponent(args.tagId)}`,
|
|
1296
|
+
body
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
|
|
1301
|
+
// src/tools/delete-rank-radar-tag.ts
|
|
1302
|
+
import { z as z29 } from "zod";
|
|
1303
|
+
var inputSchema30 = {
|
|
1304
|
+
rankRadarId: z29.string().uuid().describe("The Rank Radar UUID the tag belongs to (from `list_rank_radars`)."),
|
|
1305
|
+
tagId: z29.string().uuid().describe("The tag UUID to delete (the `id` from `list_rank_radar_tags`)."),
|
|
1306
|
+
confirm: z29.boolean().optional().describe(
|
|
1307
|
+
"Must be true to proceed. Confirm with the user first \u2014 the tag's keyword assignments are removed too and the tag cannot be recovered."
|
|
1308
|
+
)
|
|
1309
|
+
};
|
|
1310
|
+
var deleteRankRadarTagTool = {
|
|
1311
|
+
name: "delete_rank_radar_tag",
|
|
1312
|
+
title: "Delete a Rank Radar Tag",
|
|
1313
|
+
description: 'Use this to permanently remove a tag from a Rank Radar. \u26A0\uFE0F The tag itself is gone and the assignments linking it to each tagged keyword are removed with it; the keywords themselves keep tracking. The deletion cannot be undone from this tool, so set `confirm: true` only after the user approves. The system "paused" tag (reserved colour, written by the quota pauser) cannot be addressed from here \u2014 the API answers 404. To remove just the assignments and keep the tag, use `remove_rank_radar_tag_search_terms` instead.',
|
|
1314
|
+
inputSchema: inputSchema30,
|
|
1315
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1316
|
+
handler: async (args, ctx) => {
|
|
1317
|
+
const pending = requireConfirmation(
|
|
1318
|
+
args.confirm,
|
|
1319
|
+
ctx,
|
|
1320
|
+
"Deleting this tag removes it from every keyword it was applied to. The tag cannot be recovered \u2014 if the user only wants to clear its keyword list, use `remove_rank_radar_tag_search_terms`."
|
|
1321
|
+
);
|
|
1322
|
+
if (pending) return pending;
|
|
1323
|
+
await httpDelete(
|
|
1324
|
+
{ config: ctx.config, toolName: "delete_rank_radar_tag" },
|
|
1325
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/tags/${encodeURIComponent(args.tagId)}`
|
|
1326
|
+
);
|
|
1327
|
+
return { status: "deleted", rankRadarId: args.rankRadarId, tagId: args.tagId };
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
|
|
1331
|
+
// src/tools/add-rank-radar-tag-search-terms.ts
|
|
1332
|
+
import { z as z30 } from "zod";
|
|
1333
|
+
var inputSchema31 = {
|
|
1334
|
+
rankRadarId: z30.string().uuid().describe("The Rank Radar UUID the tag belongs to (from `list_rank_radars`)."),
|
|
1335
|
+
tagId: z30.string().uuid().describe("The tag UUID to attach keywords to (the `id` from `list_rank_radar_tags`)."),
|
|
1336
|
+
rankRadarKeywordIds: z30.array(z30.string().uuid()).min(1).max(TAG_KEYWORD_IDS_MAX).describe(
|
|
1337
|
+
`Rank Radar keyword ids to attach to this tag (1\u2013${TAG_KEYWORD_IDS_MAX} per call, unique). These are the \`id\` values from \`get_rank_radar_data\`; all ids must belong to this Rank Radar. Safe to repeat: keywords already attached are left unchanged.`
|
|
1338
|
+
)
|
|
1339
|
+
};
|
|
1340
|
+
var addRankRadarTagSearchTermsTool = {
|
|
1341
|
+
name: "add_rank_radar_tag_search_terms",
|
|
1342
|
+
title: "Attach Search Terms to a Rank Radar Tag",
|
|
1343
|
+
description: `Use this to tag a batch of keywords on a Rank Radar \u2014 the same relation \`create_rank_radar_tag\` writes when \`rankRadarKeywordIds\` is passed on creation, so this is how you keep extending a tag's keyword set over time. Reversible with \`remove_rank_radar_tag_search_terms\`, so no confirmation is required. Idempotent: already-attached keywords are left unchanged, so re-sending the same ids after a timeout is safe. Up to ${TAG_KEYWORD_IDS_MAX} ids per call \u2014 split larger batches into multiple calls. The system "paused" tag (reserved colour, written by the quota pauser) is not addressable: the API answers 404.`,
|
|
1344
|
+
inputSchema: inputSchema31,
|
|
1345
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1346
|
+
handler: async (args, ctx) => {
|
|
1347
|
+
return await httpPost(
|
|
1348
|
+
{ config: ctx.config, toolName: "add_rank_radar_tag_search_terms" },
|
|
1349
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/tags/${encodeURIComponent(args.tagId)}/search-terms`,
|
|
1350
|
+
{ rankRadarKeywordIds: args.rankRadarKeywordIds }
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
};
|
|
1354
|
+
|
|
1355
|
+
// src/tools/remove-rank-radar-tag-search-terms.ts
|
|
1356
|
+
import { z as z31 } from "zod";
|
|
1357
|
+
var inputSchema32 = {
|
|
1358
|
+
rankRadarId: z31.string().uuid().describe("The Rank Radar UUID the tag belongs to (from `list_rank_radars`)."),
|
|
1359
|
+
tagId: z31.string().uuid().describe("The tag UUID to detach keywords from (the `id` from `list_rank_radar_tags`)."),
|
|
1360
|
+
rankRadarKeywordIds: z31.array(z31.string().uuid()).min(1).max(TAG_KEYWORD_IDS_MAX).describe(
|
|
1361
|
+
`Rank Radar keyword ids to detach from this tag (1\u2013${TAG_KEYWORD_IDS_MAX} per call, unique). These are the \`id\` values from \`get_rank_radar_data\`. Safe to repeat: keywords that are not currently attached are left unchanged.`
|
|
1362
|
+
)
|
|
1363
|
+
};
|
|
1364
|
+
var removeRankRadarTagSearchTermsTool = {
|
|
1365
|
+
name: "remove_rank_radar_tag_search_terms",
|
|
1366
|
+
title: "Detach Search Terms from a Rank Radar Tag",
|
|
1367
|
+
description: `Use this to remove keywords from a tag without deleting the tag itself. The tag keeps its title, colour and date window; only the keyword assignments listed are cleared. Reversible with \`add_rank_radar_tag_search_terms\`, so no confirmation is required. Idempotent: ids that are not currently attached are left unchanged, so re-sending the same ids after a timeout is safe. Up to ${TAG_KEYWORD_IDS_MAX} ids per call \u2014 split larger batches into multiple calls. To remove the tag itself, use \`delete_rank_radar_tag\`. The system "paused" tag (reserved colour, written by the quota pauser) is not addressable: the API answers 404.`,
|
|
1368
|
+
inputSchema: inputSchema32,
|
|
1369
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1370
|
+
handler: async (args, ctx) => {
|
|
1371
|
+
return await httpPost(
|
|
1372
|
+
{ config: ctx.config, toolName: "remove_rank_radar_tag_search_terms" },
|
|
1373
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/tags/${encodeURIComponent(args.tagId)}/search-terms/remove`,
|
|
1374
|
+
{ rankRadarKeywordIds: args.rankRadarKeywordIds }
|
|
1375
|
+
);
|
|
1376
|
+
}
|
|
1377
|
+
};
|
|
1378
|
+
|
|
1379
|
+
// src/tools/generate-listing-copy.ts
|
|
1380
|
+
import { z as z32 } from "zod";
|
|
1381
|
+
var inputSchema33 = {
|
|
1382
|
+
nicheId: z32.string().min(1).describe("The niche whose keyword data the copy is written from. Get one from `list_niches`."),
|
|
1383
|
+
strategy: z32.enum(LISTING_COPY_STRATEGIES).describe(
|
|
1178
1384
|
"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."
|
|
1179
1385
|
),
|
|
1180
|
-
currentListing:
|
|
1386
|
+
currentListing: z32.record(z32.union([z32.string(), z32.array(z32.string())])).describe(
|
|
1181
1387
|
'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.'
|
|
1182
1388
|
),
|
|
1183
|
-
confirm:
|
|
1389
|
+
confirm: z32.boolean().optional().describe(
|
|
1184
1390
|
"Must be true to proceed \u2014 each generation spends one AI Copywriter prompt from the quota. Confirm the cost with the user first."
|
|
1185
1391
|
)
|
|
1186
1392
|
};
|
|
@@ -1188,7 +1394,7 @@ var generateListingCopyTool = {
|
|
|
1188
1394
|
name: "generate_listing_copy",
|
|
1189
1395
|
title: "Generate Listing Copy for a Niche",
|
|
1190
1396
|
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`.",
|
|
1191
|
-
inputSchema:
|
|
1397
|
+
inputSchema: inputSchema33,
|
|
1192
1398
|
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1193
1399
|
handler: async (args, ctx) => {
|
|
1194
1400
|
const pending = requireConfirmation(
|
|
@@ -1206,16 +1412,16 @@ var generateListingCopyTool = {
|
|
|
1206
1412
|
};
|
|
1207
1413
|
|
|
1208
1414
|
// src/tools/get-listing-copy-generation-status.ts
|
|
1209
|
-
import { z as
|
|
1210
|
-
var
|
|
1211
|
-
nicheId:
|
|
1212
|
-
generationId:
|
|
1415
|
+
import { z as z33 } from "zod";
|
|
1416
|
+
var inputSchema34 = {
|
|
1417
|
+
nicheId: z33.string().min(1).describe("The niche the generation was started for."),
|
|
1418
|
+
generationId: z33.string().min(1).describe("The `generationId` returned by `generate_listing_copy`.")
|
|
1213
1419
|
};
|
|
1214
1420
|
var getListingCopyGenerationStatusTool = {
|
|
1215
1421
|
name: "get_listing_copy_generation_status",
|
|
1216
1422
|
title: "Get Listing Copy Generation Status",
|
|
1217
1423
|
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`.",
|
|
1218
|
-
inputSchema:
|
|
1424
|
+
inputSchema: inputSchema34,
|
|
1219
1425
|
annotations: { readOnlyHint: true },
|
|
1220
1426
|
handler: async (args, ctx) => {
|
|
1221
1427
|
return await httpGet(
|
|
@@ -1226,16 +1432,16 @@ var getListingCopyGenerationStatusTool = {
|
|
|
1226
1432
|
};
|
|
1227
1433
|
|
|
1228
1434
|
// src/tools/list-seller-profiles.ts
|
|
1229
|
-
import { z as
|
|
1230
|
-
var
|
|
1231
|
-
currentPage:
|
|
1232
|
-
pageSize:
|
|
1435
|
+
import { z as z34 } from "zod";
|
|
1436
|
+
var inputSchema35 = {
|
|
1437
|
+
currentPage: z34.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1438
|
+
pageSize: z34.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
|
|
1233
1439
|
};
|
|
1234
1440
|
var listSellerProfilesTool = {
|
|
1235
1441
|
name: "list_seller_profiles",
|
|
1236
1442
|
title: "List Connected Amazon Seller Profiles",
|
|
1237
1443
|
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).',
|
|
1238
|
-
inputSchema:
|
|
1444
|
+
inputSchema: inputSchema35,
|
|
1239
1445
|
annotations: { readOnlyHint: true },
|
|
1240
1446
|
handler: async (args, ctx) => {
|
|
1241
1447
|
return await httpGet(
|
|
@@ -1250,15 +1456,15 @@ var listSellerProfilesTool = {
|
|
|
1250
1456
|
};
|
|
1251
1457
|
|
|
1252
1458
|
// src/tools/get-seller-catalog.ts
|
|
1253
|
-
import { z as
|
|
1459
|
+
import { z as z36 } from "zod";
|
|
1254
1460
|
|
|
1255
1461
|
// src/tools/seller-scoped.ts
|
|
1256
|
-
import { z as
|
|
1462
|
+
import { z as z35 } from "zod";
|
|
1257
1463
|
var sellerScopedInputSchema = {
|
|
1258
|
-
sellerId:
|
|
1464
|
+
sellerId: z35.string().min(1).describe(
|
|
1259
1465
|
"Amazon seller account ID. Get it from `list_seller_profiles`, or find it on the Connections page at https://2.datadive.tools."
|
|
1260
1466
|
),
|
|
1261
|
-
marketplace:
|
|
1467
|
+
marketplace: z35.enum(SUPPORTED_MARKETPLACES).describe('Amazon marketplace code, e.g. "com" for amazon.com or "co.uk" for amazon.co.uk.')
|
|
1262
1468
|
};
|
|
1263
1469
|
function sellerMarketplacePath(sellerId, marketplace, suffix) {
|
|
1264
1470
|
return `/v1/seller_profiles/${encodeURIComponent(sellerId)}/marketplaces/${encodeURIComponent(
|
|
@@ -1267,19 +1473,19 @@ function sellerMarketplacePath(sellerId, marketplace, suffix) {
|
|
|
1267
1473
|
}
|
|
1268
1474
|
|
|
1269
1475
|
// src/tools/get-seller-catalog.ts
|
|
1270
|
-
var
|
|
1476
|
+
var inputSchema36 = {
|
|
1271
1477
|
...sellerScopedInputSchema,
|
|
1272
|
-
search:
|
|
1273
|
-
brand:
|
|
1274
|
-
status:
|
|
1275
|
-
currentPage:
|
|
1276
|
-
pageSize:
|
|
1478
|
+
search: z36.string().min(1).optional().describe("Case-insensitive partial match on product title or brand."),
|
|
1479
|
+
brand: z36.string().min(1).optional().describe("Case-insensitive partial match on brand name."),
|
|
1480
|
+
status: z36.enum(CATALOG_STATUSES).optional().describe('Listing status filter. "Active" (default) or "all".'),
|
|
1481
|
+
currentPage: z36.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1482
|
+
pageSize: z36.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
|
|
1277
1483
|
};
|
|
1278
1484
|
var getSellerCatalogTool = {
|
|
1279
1485
|
name: "get_seller_catalog",
|
|
1280
1486
|
title: "List Catalog ASINs for a Seller",
|
|
1281
1487
|
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).",
|
|
1282
|
-
inputSchema:
|
|
1488
|
+
inputSchema: inputSchema36,
|
|
1283
1489
|
annotations: { readOnlyHint: true },
|
|
1284
1490
|
handler: async (args, ctx) => {
|
|
1285
1491
|
return await httpGet(
|
|
@@ -1297,28 +1503,28 @@ var getSellerCatalogTool = {
|
|
|
1297
1503
|
};
|
|
1298
1504
|
|
|
1299
1505
|
// src/tools/get-seller-listing-changes.ts
|
|
1300
|
-
import { z as
|
|
1301
|
-
var
|
|
1506
|
+
import { z as z37 } from "zod";
|
|
1507
|
+
var inputSchema37 = {
|
|
1302
1508
|
...sellerScopedInputSchema,
|
|
1303
|
-
types:
|
|
1304
|
-
asin:
|
|
1305
|
-
brand:
|
|
1306
|
-
search:
|
|
1307
|
-
startDate:
|
|
1308
|
-
endDate:
|
|
1309
|
-
sortBy:
|
|
1310
|
-
sortOrder:
|
|
1311
|
-
includeCorrelations:
|
|
1509
|
+
types: z37.array(z37.enum(LISTING_CHANGE_TYPES)).min(1).optional().describe('Filter to specific change types. Omit for all. Any of "Price", "Content", "Image".'),
|
|
1510
|
+
asin: z37.string().min(1).optional().describe("Filter to an exact ASIN or parent ASIN."),
|
|
1511
|
+
brand: z37.string().min(1).optional().describe("Case-insensitive partial match on brand name."),
|
|
1512
|
+
search: z37.string().min(1).optional().describe("Case-insensitive partial match on product title or brand."),
|
|
1513
|
+
startDate: z37.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."),
|
|
1514
|
+
endDate: z37.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."),
|
|
1515
|
+
sortBy: z37.enum(LISTING_CHANGE_SORT_BY).optional().describe('Sort field. "date" (default) or "type".'),
|
|
1516
|
+
sortOrder: z37.enum(SORT_ORDER).optional().describe('Sort direction. "DESC" (default) or "ASC".'),
|
|
1517
|
+
includeCorrelations: z37.boolean().optional().describe(
|
|
1312
1518
|
"When true, include the ranking/conversion `correlation` object per change (CVR and search-term movement before vs after). Defaults to false."
|
|
1313
1519
|
),
|
|
1314
|
-
currentPage:
|
|
1315
|
-
pageSize:
|
|
1520
|
+
currentPage: z37.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1521
|
+
pageSize: z37.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
|
|
1316
1522
|
};
|
|
1317
1523
|
var getSellerListingChangesTool = {
|
|
1318
1524
|
name: "get_seller_listing_changes",
|
|
1319
1525
|
title: "List Listing Changes for a Seller",
|
|
1320
1526
|
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).",
|
|
1321
|
-
inputSchema:
|
|
1527
|
+
inputSchema: inputSchema37,
|
|
1322
1528
|
annotations: { readOnlyHint: true },
|
|
1323
1529
|
handler: async (args, ctx) => {
|
|
1324
1530
|
return await httpGet(
|
|
@@ -1343,40 +1549,40 @@ var getSellerListingChangesTool = {
|
|
|
1343
1549
|
};
|
|
1344
1550
|
|
|
1345
1551
|
// src/tools/list-ppc-campaigns.ts
|
|
1346
|
-
import { z as
|
|
1552
|
+
import { z as z38 } from "zod";
|
|
1347
1553
|
var PPC_CAMPAIGNS_MAX_WINDOW_DAYS = 90;
|
|
1348
1554
|
var PPC_CAMPAIGNS_MAX_PAGE_SIZE = 50;
|
|
1349
|
-
var
|
|
1555
|
+
var inputSchema38 = {
|
|
1350
1556
|
...sellerScopedInputSchema,
|
|
1351
|
-
startDate:
|
|
1557
|
+
startDate: z38.string().regex(
|
|
1352
1558
|
ISO_8601,
|
|
1353
1559
|
"startDate must be an ISO-8601 date or timestamp (e.g. 2026-05-01 or 2026-05-01T00:00:00Z)"
|
|
1354
1560
|
).optional().describe("Start of the reporting window, ISO-8601. Defaults to 30 days before endDate."),
|
|
1355
|
-
endDate:
|
|
1561
|
+
endDate: z38.string().regex(
|
|
1356
1562
|
ISO_8601,
|
|
1357
1563
|
"endDate must be an ISO-8601 date or timestamp (e.g. 2026-05-31 or 2026-05-31T23:59:59Z)"
|
|
1358
1564
|
).optional().describe(
|
|
1359
1565
|
`End of the reporting window, ISO-8601. Defaults to now. At most ${PPC_CAMPAIGNS_MAX_WINDOW_DAYS} days after startDate.`
|
|
1360
1566
|
),
|
|
1361
|
-
asin:
|
|
1362
|
-
parentAsin:
|
|
1363
|
-
search:
|
|
1364
|
-
includePlacements:
|
|
1567
|
+
asin: z38.string().min(1).optional().describe("Only campaigns advertising this ASIN. Cannot be combined with parentAsin."),
|
|
1568
|
+
parentAsin: z38.string().min(1).optional().describe("Only campaigns advertising any ASIN of this variation family. Cannot be combined with asin."),
|
|
1569
|
+
search: z38.string().min(3).max(200).optional().describe("Partial match on campaign name or advertised ASIN. At least 3 characters."),
|
|
1570
|
+
includePlacements: z38.boolean().optional().describe(
|
|
1365
1571
|
"Include the per-placement breakdown (topOfSearch, restOfSearch, productPage, offAmazon, each with its bid adjustment). Defaults to true; set false for a smaller response when placements are not needed."
|
|
1366
1572
|
),
|
|
1367
|
-
sortBy:
|
|
1573
|
+
sortBy: z38.enum([...PPC_CAMPAIGN_BASE_SORT_BY, ...PPC_CAMPAIGN_PLACEMENT_SORT_BY]).optional().describe(
|
|
1368
1574
|
`Sort field. Defaults to "name". Any of ${PPC_CAMPAIGN_BASE_SORT_BY.join(", ")}. The placement fields (e.g. "tosSpend", "tosAcos", "ppBidAdjustment") are only accepted when includePlacements is not false.`
|
|
1369
1575
|
),
|
|
1370
|
-
sortOrder:
|
|
1371
|
-
state:
|
|
1372
|
-
currentPage:
|
|
1373
|
-
pageSize:
|
|
1576
|
+
sortOrder: z38.enum(SORT_ORDER).optional().describe('Sort direction. "ASC" (default) or "DESC".'),
|
|
1577
|
+
state: z38.enum(PPC_CAMPAIGN_STATES).optional().describe("Only ENABLED or only PAUSED campaigns. Omit for both."),
|
|
1578
|
+
currentPage: z38.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1579
|
+
pageSize: z38.number().int().min(1).max(PPC_CAMPAIGNS_MAX_PAGE_SIZE).optional().describe(`Campaigns per page (max ${PPC_CAMPAIGNS_MAX_PAGE_SIZE}). Defaults to 20.`)
|
|
1374
1580
|
};
|
|
1375
1581
|
var listPpcCampaignsTool = {
|
|
1376
1582
|
name: "list_ppc_campaigns",
|
|
1377
1583
|
title: "List PPC Campaigns for a Seller",
|
|
1378
1584
|
description: `Use this when the user asks about their Sponsored Products campaigns \u2014 which campaigns spend the most, which have a high ACOS, how placements (top of search, rest of search, product pages) perform, or which campaigns advertise a given product. Requires a \`sellerId\` + \`marketplace\` (use \`list_seller_profiles\` to discover them). Narrow to one product with \`asin\`, or to a variation family with \`parentAsin\` (not both). The reporting window defaults to the last 30 days and cannot exceed ${PPC_CAMPAIGNS_MAX_WINDOW_DAYS} days. Returns a paginated list where each campaign has campaignId, name, type, state, targetingType, bidStrategy, budget { type, amount, currencyCode }, window totals (impressions, clicks, ctr, cpc, cvr, spend, unitsSold, orders, sales, tosImpressionShare, acos, roas, tacos), asinCount and, unless includePlacements is false, \`placements\`; plus pagination metadata (currentPage, pageSize, total, lastPage, hasNext, hasPrev). To find the biggest spenders, sort with \`sortBy: "spend", sortOrder: "DESC"\` rather than paging through every campaign. Each call counts toward API usage and is rate limited (about 60 requests/minute). For per-keyword ad data of a Rank Radar, use \`get_rank_radar_ppc_data\`.`,
|
|
1379
|
-
inputSchema:
|
|
1585
|
+
inputSchema: inputSchema38,
|
|
1380
1586
|
annotations: { readOnlyHint: true },
|
|
1381
1587
|
handler: async (args, ctx) => {
|
|
1382
1588
|
if (args.asin && args.parentAsin) {
|
|
@@ -1407,21 +1613,21 @@ var listPpcCampaignsTool = {
|
|
|
1407
1613
|
};
|
|
1408
1614
|
|
|
1409
1615
|
// src/tools/get-asin-inventory-distribution.ts
|
|
1410
|
-
import { z as
|
|
1411
|
-
var
|
|
1412
|
-
sellerId:
|
|
1616
|
+
import { z as z39 } from "zod";
|
|
1617
|
+
var inputSchema39 = {
|
|
1618
|
+
sellerId: z39.string().min(1).describe(
|
|
1413
1619
|
"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."
|
|
1414
1620
|
),
|
|
1415
|
-
marketplace:
|
|
1416
|
-
asin:
|
|
1621
|
+
marketplace: z39.enum(SUPPORTED_MARKETPLACES).describe('Amazon marketplace code, e.g. "com" for amazon.com or "co.uk" for amazon.co.uk.'),
|
|
1622
|
+
asin: z39.string().regex(/^[A-Z0-9]{10}$/, "ASIN must be 10 uppercase alphanumeric characters (e.g. B08XYZ1234).").describe(
|
|
1417
1623
|
"Amazon Standard Identification Number (10 uppercase alphanumeric characters, e.g. B08XYZ1234)."
|
|
1418
1624
|
)
|
|
1419
1625
|
};
|
|
1420
1626
|
var getAsinInventoryDistributionTool = {
|
|
1421
1627
|
name: "get_asin_inventory_distribution",
|
|
1422
|
-
title: "Get
|
|
1423
|
-
description: "Use this when the user asks about inventory levels, stock
|
|
1424
|
-
inputSchema:
|
|
1628
|
+
title: "Get Inventory Metrics and Fulfillment-Center Distribution for an ASIN",
|
|
1629
|
+
description: "Use this when the user asks about an ASIN's inventory: stock levels, days of stock or when it will run out, low-inventory or aged-inventory risk, low-inventory-level (LILF) or long-term storage (LTSF) fees, or where their units sit across Amazon's fulfillment network. 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 the metrics the DataDive Inventory page shows \u2014 fulfillableStock, totalStock, reservedStock, inboundStock, researchingStock, unfulfillableStock, daysOfStock (with daysOfStockSource AMAZON or ESTIMATE), daysOfStock30, daysOfStock90, inLowInventoryState, estWeeklyLilf, estLtsfNextAssessment, ltsfLastMonthActual, agedUnits, oldestUnitAgeDays, with fees in `currency` \u2014 plus totalSellableUnits and a per-FC `distribution` array (fc, state, availableStock, availableStockPercentage). A metric is null, never 0, when Amazon has no data (e.g. merchant-fulfilled); metrics the user's plan does not include are null and listed in `lockedFields` (say they need a plan upgrade, do not report them as zero). `lastUpdatedAt` dates the stock and metrics; `distributionLastUpdatedAt` dates the distribution, which is usually up to 2 days behind. Either may be null when no successful refresh happened in the last 30 days.",
|
|
1630
|
+
inputSchema: inputSchema39,
|
|
1425
1631
|
annotations: { readOnlyHint: true },
|
|
1426
1632
|
handler: async (args, ctx) => {
|
|
1427
1633
|
return await httpGet(
|
|
@@ -1434,18 +1640,18 @@ var getAsinInventoryDistributionTool = {
|
|
|
1434
1640
|
};
|
|
1435
1641
|
|
|
1436
1642
|
// src/tools/alert-query.ts
|
|
1437
|
-
import { z as
|
|
1643
|
+
import { z as z40 } from "zod";
|
|
1438
1644
|
var alertsQueryInputSchema = {
|
|
1439
|
-
sellerId:
|
|
1440
|
-
marketplace:
|
|
1441
|
-
status:
|
|
1645
|
+
sellerId: z40.string().min(1).max(50).optional().describe('Filter to a single connected Amazon seller account ID, e.g. "A1B2C3D4E5".'),
|
|
1646
|
+
marketplace: z40.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.'),
|
|
1647
|
+
status: z40.enum(ALERT_STATUSES).optional().describe(
|
|
1442
1648
|
"Lifecycle filter. `active` (default) returns unresolved alerts, `resolved` returns resolved alerts, `all` returns both. Dismissed alerts are never returned."
|
|
1443
1649
|
),
|
|
1444
|
-
updatedSince:
|
|
1650
|
+
updatedSince: z40.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(
|
|
1445
1651
|
"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."
|
|
1446
1652
|
),
|
|
1447
|
-
currentPage:
|
|
1448
|
-
pageSize:
|
|
1653
|
+
currentPage: z40.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1654
|
+
pageSize: z40.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
|
|
1449
1655
|
};
|
|
1450
1656
|
|
|
1451
1657
|
// src/tools/list-indexing-issue-alerts.ts
|
|
@@ -1495,12 +1701,12 @@ var listBlindSpendAlertsTool = {
|
|
|
1495
1701
|
};
|
|
1496
1702
|
|
|
1497
1703
|
// src/tools/get-quota.ts
|
|
1498
|
-
var
|
|
1704
|
+
var inputSchema40 = {};
|
|
1499
1705
|
var getQuotaTool = {
|
|
1500
1706
|
name: "get_quota",
|
|
1501
1707
|
title: "Get Quota Usage",
|
|
1502
1708
|
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.",
|
|
1503
|
-
inputSchema:
|
|
1709
|
+
inputSchema: inputSchema40,
|
|
1504
1710
|
annotations: { readOnlyHint: true },
|
|
1505
1711
|
handler: async (_args, ctx) => {
|
|
1506
1712
|
return await httpGet({ config: ctx.config, toolName: "get_quota" }, "/v1/quota");
|
|
@@ -1508,20 +1714,20 @@ var getQuotaTool = {
|
|
|
1508
1714
|
};
|
|
1509
1715
|
|
|
1510
1716
|
// src/tools/list-usage.ts
|
|
1511
|
-
import { z as
|
|
1512
|
-
var
|
|
1513
|
-
type:
|
|
1514
|
-
search:
|
|
1515
|
-
startDate:
|
|
1516
|
-
endDate:
|
|
1517
|
-
currentPage:
|
|
1518
|
-
pageSize:
|
|
1717
|
+
import { z as z41 } from "zod";
|
|
1718
|
+
var inputSchema41 = {
|
|
1719
|
+
type: z41.enum(BILLABLE_FEATURE_TYPES).optional().describe("Filter to a single billable feature type. Omit to return all types."),
|
|
1720
|
+
search: z41.string().min(1).optional().describe("Case-insensitive partial match on the user's name or email."),
|
|
1721
|
+
startDate: z41.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."),
|
|
1722
|
+
endDate: z41.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."),
|
|
1723
|
+
currentPage: z41.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1724
|
+
pageSize: z41.number().int().min(1).max(200).optional().describe("Items per page (max 200). Defaults to 50.")
|
|
1519
1725
|
};
|
|
1520
1726
|
var listUsageTool = {
|
|
1521
1727
|
name: "list_usage",
|
|
1522
1728
|
title: "List Billable Usage Logs",
|
|
1523
1729
|
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).",
|
|
1524
|
-
inputSchema:
|
|
1730
|
+
inputSchema: inputSchema41,
|
|
1525
1731
|
annotations: { readOnlyHint: true },
|
|
1526
1732
|
handler: async (args, ctx) => {
|
|
1527
1733
|
return await httpGet(
|
|
@@ -1551,6 +1757,7 @@ var allTools = [
|
|
|
1551
1757
|
getRankRadarDataTool,
|
|
1552
1758
|
getRankRadarSqpDataTool,
|
|
1553
1759
|
getRankRadarPpcDataTool,
|
|
1760
|
+
listRankRadarTagsTool,
|
|
1554
1761
|
createRankRadarTool,
|
|
1555
1762
|
createNicheDiveTool,
|
|
1556
1763
|
createNicheDiveFromCompetitorsListTool,
|
|
@@ -1563,6 +1770,11 @@ var allTools = [
|
|
|
1563
1770
|
addRankRadarSearchTermsTool,
|
|
1564
1771
|
pauseRankRadarSearchTermsTool,
|
|
1565
1772
|
resumeRankRadarSearchTermsTool,
|
|
1773
|
+
createRankRadarTagTool,
|
|
1774
|
+
updateRankRadarTagTool,
|
|
1775
|
+
addRankRadarTagSearchTermsTool,
|
|
1776
|
+
removeRankRadarTagSearchTermsTool,
|
|
1777
|
+
deleteRankRadarTagTool,
|
|
1566
1778
|
pauseRankRadarTool,
|
|
1567
1779
|
resumeRankRadarTool,
|
|
1568
1780
|
deleteRankRadarTool,
|
|
@@ -1582,6 +1794,13 @@ var allTools = [
|
|
|
1582
1794
|
|
|
1583
1795
|
// src/whats-new.ts
|
|
1584
1796
|
var WHATS_NEW = [
|
|
1797
|
+
{
|
|
1798
|
+
version: "0.17.1",
|
|
1799
|
+
released: "2026-10-13",
|
|
1800
|
+
items: [
|
|
1801
|
+
"Rank Radar tags end-to-end: list, create, update, delete tags, and attach or detach up to 1000 keywords per call (`list_rank_radar_tags`, `create_rank_radar_tag`, `update_rank_radar_tag`, `delete_rank_radar_tag`, `add_rank_radar_tag_search_terms`, `remove_rank_radar_tag_search_terms`). The highlights on each keyword in `get_rank_radar_data` are the same objects, so you can go from a ranking view to editing its tags without a round trip."
|
|
1802
|
+
]
|
|
1803
|
+
},
|
|
1585
1804
|
{
|
|
1586
1805
|
version: "0.17.0",
|
|
1587
1806
|
released: "2026-10-12",
|