@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/lib.js
CHANGED
|
@@ -139,7 +139,7 @@ function extractMessage(body) {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
// package.json
|
|
142
|
-
var version = "0.
|
|
142
|
+
var version = "0.18.0";
|
|
143
143
|
|
|
144
144
|
// src/http/client.ts
|
|
145
145
|
var PKG_VERSION = version;
|
|
@@ -179,6 +179,7 @@ async function httpGet(ctx, path, query) {
|
|
|
179
179
|
method: "GET",
|
|
180
180
|
headers: {
|
|
181
181
|
...authHeaders(ctx.config),
|
|
182
|
+
...forwardedForHeader(ctx.config),
|
|
182
183
|
accept: "application/json",
|
|
183
184
|
"user-agent": userAgent(ctx.toolName)
|
|
184
185
|
}
|
|
@@ -196,6 +197,27 @@ async function httpPost(ctx, path, body) {
|
|
|
196
197
|
method: "POST",
|
|
197
198
|
headers: {
|
|
198
199
|
...authHeaders(ctx.config),
|
|
200
|
+
...forwardedForHeader(ctx.config),
|
|
201
|
+
accept: "application/json",
|
|
202
|
+
"content-type": "application/json",
|
|
203
|
+
"user-agent": userAgent(ctx.toolName)
|
|
204
|
+
},
|
|
205
|
+
body: JSON.stringify(body)
|
|
206
|
+
});
|
|
207
|
+
} catch (e) {
|
|
208
|
+
throw networkError(url, e);
|
|
209
|
+
}
|
|
210
|
+
return handleResponse(res);
|
|
211
|
+
}
|
|
212
|
+
async function httpPatch(ctx, path, body) {
|
|
213
|
+
const url = buildUrl(ctx.config.baseUrl, path);
|
|
214
|
+
let res;
|
|
215
|
+
try {
|
|
216
|
+
res = await fetch(url, {
|
|
217
|
+
method: "PATCH",
|
|
218
|
+
headers: {
|
|
219
|
+
...authHeaders(ctx.config),
|
|
220
|
+
...forwardedForHeader(ctx.config),
|
|
199
221
|
accept: "application/json",
|
|
200
222
|
"content-type": "application/json",
|
|
201
223
|
"user-agent": userAgent(ctx.toolName)
|
|
@@ -215,6 +237,7 @@ async function httpDelete(ctx, path) {
|
|
|
215
237
|
method: "DELETE",
|
|
216
238
|
headers: {
|
|
217
239
|
...authHeaders(ctx.config),
|
|
240
|
+
...forwardedForHeader(ctx.config),
|
|
218
241
|
accept: "application/json",
|
|
219
242
|
"user-agent": userAgent(ctx.toolName)
|
|
220
243
|
}
|
|
@@ -260,6 +283,9 @@ function authHeaders(config) {
|
|
|
260
283
|
const c = config.credentials;
|
|
261
284
|
return c.kind === "bearer" ? { authorization: `Bearer ${c.token}` } : { "x-api-key": c.apiKey };
|
|
262
285
|
}
|
|
286
|
+
function forwardedForHeader(config) {
|
|
287
|
+
return config.forwardedFor ? { "x-forwarded-for": config.forwardedFor } : {};
|
|
288
|
+
}
|
|
263
289
|
function unwrap(body) {
|
|
264
290
|
if (!isObject(body)) return body;
|
|
265
291
|
if (!("data" in body)) return body;
|
|
@@ -426,6 +452,10 @@ var KEYWORD_EXCLUSIONS_MAX_PER_CALL = 100;
|
|
|
426
452
|
var KEYWORD_EXCLUSIONS_MAX_PER_NICHE = 1e3;
|
|
427
453
|
var RANK_RADAR_STATES = ["ACTIVE", "PAUSED", "ARCHIVED"];
|
|
428
454
|
var RANK_RADAR_STATUSES = [...RANK_RADAR_STATES, "ALL"];
|
|
455
|
+
var TAG_TITLE_MAX_LENGTH = 100;
|
|
456
|
+
var TAG_KEYWORD_IDS_MAX = 1e3;
|
|
457
|
+
var TAG_RESERVED_COLOR = "#EB5757";
|
|
458
|
+
var TAG_HEX_COLOR_PATTERN = /^#[0-9A-Fa-f]{6}$/;
|
|
429
459
|
var PPC_CAMPAIGN_BASE_SORT_BY = [
|
|
430
460
|
"name",
|
|
431
461
|
"state",
|
|
@@ -561,7 +591,7 @@ async function readAllKeywords(args, ctx) {
|
|
|
561
591
|
var getRankRadarDataTool = {
|
|
562
592
|
name: "get_rank_radar_data",
|
|
563
593
|
title: "Get Keyword Rankings for a Rank Radar",
|
|
564
|
-
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
|
|
594
|
+
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\`.`,
|
|
565
595
|
inputSchema: inputSchema8,
|
|
566
596
|
annotations: { readOnlyHint: true },
|
|
567
597
|
handler: async (args, ctx) => {
|
|
@@ -1165,17 +1195,193 @@ var resumeRankRadarSearchTermsTool = {
|
|
|
1165
1195
|
}
|
|
1166
1196
|
};
|
|
1167
1197
|
|
|
1168
|
-
// src/tools/
|
|
1198
|
+
// src/tools/list-rank-radar-tags.ts
|
|
1169
1199
|
import { z as z26 } from "zod";
|
|
1200
|
+
var LIST_RANK_RADAR_TAGS_MAX_PAGE_SIZE = 50;
|
|
1170
1201
|
var inputSchema27 = {
|
|
1171
|
-
|
|
1172
|
-
|
|
1202
|
+
rankRadarId: z26.string().uuid().describe("The Rank Radar UUID whose tags to list (from `list_rank_radars`)."),
|
|
1203
|
+
currentPage: z26.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1204
|
+
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.`)
|
|
1205
|
+
};
|
|
1206
|
+
var listRankRadarTagsTool = {
|
|
1207
|
+
name: "list_rank_radar_tags",
|
|
1208
|
+
title: "List Tags of a Rank Radar",
|
|
1209
|
+
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.`,
|
|
1210
|
+
inputSchema: inputSchema27,
|
|
1211
|
+
annotations: { readOnlyHint: true },
|
|
1212
|
+
handler: async (args, ctx) => {
|
|
1213
|
+
return await httpGet(
|
|
1214
|
+
{ config: ctx.config, toolName: "list_rank_radar_tags" },
|
|
1215
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/tags`,
|
|
1216
|
+
{
|
|
1217
|
+
currentPage: args.currentPage,
|
|
1218
|
+
pageSize: args.pageSize
|
|
1219
|
+
}
|
|
1220
|
+
);
|
|
1221
|
+
}
|
|
1222
|
+
};
|
|
1223
|
+
|
|
1224
|
+
// src/tools/create-rank-radar-tag.ts
|
|
1225
|
+
import { z as z27 } from "zod";
|
|
1226
|
+
var inputSchema28 = {
|
|
1227
|
+
rankRadarId: z27.string().uuid().describe("The Rank Radar UUID to create the tag on (from `list_rank_radars`)."),
|
|
1228
|
+
title: z27.string().min(1).max(TAG_TITLE_MAX_LENGTH).describe(
|
|
1229
|
+
`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.`
|
|
1230
|
+
),
|
|
1231
|
+
color: z27.string().regex(TAG_HEX_COLOR_PATTERN, "color must be in #RRGGBB form").optional().describe(
|
|
1232
|
+
`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.`
|
|
1233
|
+
),
|
|
1234
|
+
description: z27.string().optional().describe("Free-form description, e.g. 'Prime Day run-up'."),
|
|
1235
|
+
startAt: z27.string().optional().describe("ISO 8601 start date, e.g. '2026-07-01'. Required if `endAt` is set; `endAt >= startAt`."),
|
|
1236
|
+
endAt: z27.string().optional().describe("ISO 8601 end date, e.g. '2026-07-14'. Must be greater than or equal to `startAt`."),
|
|
1237
|
+
rankRadarKeywordIds: z27.array(z27.string().uuid()).min(1).max(TAG_KEYWORD_IDS_MAX).optional().describe(
|
|
1238
|
+
`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\`.`
|
|
1239
|
+
)
|
|
1240
|
+
};
|
|
1241
|
+
var createRankRadarTagTool = {
|
|
1242
|
+
name: "create_rank_radar_tag",
|
|
1243
|
+
title: "Create a Rank Radar Tag",
|
|
1244
|
+
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\`.`,
|
|
1245
|
+
inputSchema: inputSchema28,
|
|
1246
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1247
|
+
handler: async (args, ctx) => {
|
|
1248
|
+
const body = { title: args.title };
|
|
1249
|
+
if (args.color !== void 0) body.color = args.color;
|
|
1250
|
+
if (args.description !== void 0) body.description = args.description;
|
|
1251
|
+
if (args.startAt !== void 0) body.startAt = args.startAt;
|
|
1252
|
+
if (args.endAt !== void 0) body.endAt = args.endAt;
|
|
1253
|
+
if (args.rankRadarKeywordIds !== void 0) body.rankRadarKeywordIds = args.rankRadarKeywordIds;
|
|
1254
|
+
return await httpPost(
|
|
1255
|
+
{ config: ctx.config, toolName: "create_rank_radar_tag" },
|
|
1256
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/tags`,
|
|
1257
|
+
body
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
|
|
1262
|
+
// src/tools/update-rank-radar-tag.ts
|
|
1263
|
+
import { z as z28 } from "zod";
|
|
1264
|
+
var inputSchema29 = {
|
|
1265
|
+
rankRadarId: z28.string().uuid().describe("The Rank Radar UUID the tag belongs to (from `list_rank_radars`)."),
|
|
1266
|
+
tagId: z28.string().uuid().describe("The tag UUID to update (the `id` from `list_rank_radar_tags` or `create_rank_radar_tag`)."),
|
|
1267
|
+
title: z28.string().min(1).max(TAG_TITLE_MAX_LENGTH).optional().describe(
|
|
1268
|
+
`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 }\`.`
|
|
1269
|
+
),
|
|
1270
|
+
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.`),
|
|
1271
|
+
description: z28.string().optional().describe("Free-form description. Pass an empty string to clear."),
|
|
1272
|
+
startAt: z28.string().optional().describe("ISO 8601 start date, e.g. '2026-07-01'. `endAt >= startAt`."),
|
|
1273
|
+
endAt: z28.string().optional().describe("ISO 8601 end date, e.g. '2026-07-14'. `endAt >= startAt`.")
|
|
1274
|
+
};
|
|
1275
|
+
var updateRankRadarTagTool = {
|
|
1276
|
+
name: "update_rank_radar_tag",
|
|
1277
|
+
title: "Update a Rank Radar Tag",
|
|
1278
|
+
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).",
|
|
1279
|
+
inputSchema: inputSchema29,
|
|
1280
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1281
|
+
handler: async (args, ctx) => {
|
|
1282
|
+
const body = {};
|
|
1283
|
+
if (args.title !== void 0) body.title = args.title;
|
|
1284
|
+
if (args.color !== void 0) body.color = args.color;
|
|
1285
|
+
if (args.description !== void 0) body.description = args.description;
|
|
1286
|
+
if (args.startAt !== void 0) body.startAt = args.startAt;
|
|
1287
|
+
if (args.endAt !== void 0) body.endAt = args.endAt;
|
|
1288
|
+
return await httpPatch(
|
|
1289
|
+
{ config: ctx.config, toolName: "update_rank_radar_tag" },
|
|
1290
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/tags/${encodeURIComponent(args.tagId)}`,
|
|
1291
|
+
body
|
|
1292
|
+
);
|
|
1293
|
+
}
|
|
1294
|
+
};
|
|
1295
|
+
|
|
1296
|
+
// src/tools/delete-rank-radar-tag.ts
|
|
1297
|
+
import { z as z29 } from "zod";
|
|
1298
|
+
var inputSchema30 = {
|
|
1299
|
+
rankRadarId: z29.string().uuid().describe("The Rank Radar UUID the tag belongs to (from `list_rank_radars`)."),
|
|
1300
|
+
tagId: z29.string().uuid().describe("The tag UUID to delete (the `id` from `list_rank_radar_tags`)."),
|
|
1301
|
+
confirm: z29.boolean().optional().describe(
|
|
1302
|
+
"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."
|
|
1303
|
+
)
|
|
1304
|
+
};
|
|
1305
|
+
var deleteRankRadarTagTool = {
|
|
1306
|
+
name: "delete_rank_radar_tag",
|
|
1307
|
+
title: "Delete a Rank Radar Tag",
|
|
1308
|
+
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.',
|
|
1309
|
+
inputSchema: inputSchema30,
|
|
1310
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1311
|
+
handler: async (args, ctx) => {
|
|
1312
|
+
const pending = requireConfirmation(
|
|
1313
|
+
args.confirm,
|
|
1314
|
+
ctx,
|
|
1315
|
+
"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`."
|
|
1316
|
+
);
|
|
1317
|
+
if (pending) return pending;
|
|
1318
|
+
await httpDelete(
|
|
1319
|
+
{ config: ctx.config, toolName: "delete_rank_radar_tag" },
|
|
1320
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/tags/${encodeURIComponent(args.tagId)}`
|
|
1321
|
+
);
|
|
1322
|
+
return { status: "deleted", rankRadarId: args.rankRadarId, tagId: args.tagId };
|
|
1323
|
+
}
|
|
1324
|
+
};
|
|
1325
|
+
|
|
1326
|
+
// src/tools/add-rank-radar-tag-search-terms.ts
|
|
1327
|
+
import { z as z30 } from "zod";
|
|
1328
|
+
var inputSchema31 = {
|
|
1329
|
+
rankRadarId: z30.string().uuid().describe("The Rank Radar UUID the tag belongs to (from `list_rank_radars`)."),
|
|
1330
|
+
tagId: z30.string().uuid().describe("The tag UUID to attach keywords to (the `id` from `list_rank_radar_tags`)."),
|
|
1331
|
+
rankRadarKeywordIds: z30.array(z30.string().uuid()).min(1).max(TAG_KEYWORD_IDS_MAX).describe(
|
|
1332
|
+
`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.`
|
|
1333
|
+
)
|
|
1334
|
+
};
|
|
1335
|
+
var addRankRadarTagSearchTermsTool = {
|
|
1336
|
+
name: "add_rank_radar_tag_search_terms",
|
|
1337
|
+
title: "Attach Search Terms to a Rank Radar Tag",
|
|
1338
|
+
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.`,
|
|
1339
|
+
inputSchema: inputSchema31,
|
|
1340
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1341
|
+
handler: async (args, ctx) => {
|
|
1342
|
+
return await httpPost(
|
|
1343
|
+
{ config: ctx.config, toolName: "add_rank_radar_tag_search_terms" },
|
|
1344
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/tags/${encodeURIComponent(args.tagId)}/search-terms`,
|
|
1345
|
+
{ rankRadarKeywordIds: args.rankRadarKeywordIds }
|
|
1346
|
+
);
|
|
1347
|
+
}
|
|
1348
|
+
};
|
|
1349
|
+
|
|
1350
|
+
// src/tools/remove-rank-radar-tag-search-terms.ts
|
|
1351
|
+
import { z as z31 } from "zod";
|
|
1352
|
+
var inputSchema32 = {
|
|
1353
|
+
rankRadarId: z31.string().uuid().describe("The Rank Radar UUID the tag belongs to (from `list_rank_radars`)."),
|
|
1354
|
+
tagId: z31.string().uuid().describe("The tag UUID to detach keywords from (the `id` from `list_rank_radar_tags`)."),
|
|
1355
|
+
rankRadarKeywordIds: z31.array(z31.string().uuid()).min(1).max(TAG_KEYWORD_IDS_MAX).describe(
|
|
1356
|
+
`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.`
|
|
1357
|
+
)
|
|
1358
|
+
};
|
|
1359
|
+
var removeRankRadarTagSearchTermsTool = {
|
|
1360
|
+
name: "remove_rank_radar_tag_search_terms",
|
|
1361
|
+
title: "Detach Search Terms from a Rank Radar Tag",
|
|
1362
|
+
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.`,
|
|
1363
|
+
inputSchema: inputSchema32,
|
|
1364
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1365
|
+
handler: async (args, ctx) => {
|
|
1366
|
+
return await httpPost(
|
|
1367
|
+
{ config: ctx.config, toolName: "remove_rank_radar_tag_search_terms" },
|
|
1368
|
+
`/v1/niches/rank-radars/${encodeURIComponent(args.rankRadarId)}/tags/${encodeURIComponent(args.tagId)}/search-terms/remove`,
|
|
1369
|
+
{ rankRadarKeywordIds: args.rankRadarKeywordIds }
|
|
1370
|
+
);
|
|
1371
|
+
}
|
|
1372
|
+
};
|
|
1373
|
+
|
|
1374
|
+
// src/tools/generate-listing-copy.ts
|
|
1375
|
+
import { z as z32 } from "zod";
|
|
1376
|
+
var inputSchema33 = {
|
|
1377
|
+
nicheId: z32.string().min(1).describe("The niche whose keyword data the copy is written from. Get one from `list_niches`."),
|
|
1378
|
+
strategy: z32.enum(LISTING_COPY_STRATEGIES).describe(
|
|
1173
1379
|
"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."
|
|
1174
1380
|
),
|
|
1175
|
-
currentListing:
|
|
1381
|
+
currentListing: z32.record(z32.union([z32.string(), z32.array(z32.string())])).describe(
|
|
1176
1382
|
'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.'
|
|
1177
1383
|
),
|
|
1178
|
-
confirm:
|
|
1384
|
+
confirm: z32.boolean().optional().describe(
|
|
1179
1385
|
"Must be true to proceed \u2014 each generation spends one AI Copywriter prompt from the quota. Confirm the cost with the user first."
|
|
1180
1386
|
)
|
|
1181
1387
|
};
|
|
@@ -1183,7 +1389,7 @@ var generateListingCopyTool = {
|
|
|
1183
1389
|
name: "generate_listing_copy",
|
|
1184
1390
|
title: "Generate Listing Copy for a Niche",
|
|
1185
1391
|
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`.",
|
|
1186
|
-
inputSchema:
|
|
1392
|
+
inputSchema: inputSchema33,
|
|
1187
1393
|
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1188
1394
|
handler: async (args, ctx) => {
|
|
1189
1395
|
const pending = requireConfirmation(
|
|
@@ -1201,16 +1407,16 @@ var generateListingCopyTool = {
|
|
|
1201
1407
|
};
|
|
1202
1408
|
|
|
1203
1409
|
// src/tools/get-listing-copy-generation-status.ts
|
|
1204
|
-
import { z as
|
|
1205
|
-
var
|
|
1206
|
-
nicheId:
|
|
1207
|
-
generationId:
|
|
1410
|
+
import { z as z33 } from "zod";
|
|
1411
|
+
var inputSchema34 = {
|
|
1412
|
+
nicheId: z33.string().min(1).describe("The niche the generation was started for."),
|
|
1413
|
+
generationId: z33.string().min(1).describe("The `generationId` returned by `generate_listing_copy`.")
|
|
1208
1414
|
};
|
|
1209
1415
|
var getListingCopyGenerationStatusTool = {
|
|
1210
1416
|
name: "get_listing_copy_generation_status",
|
|
1211
1417
|
title: "Get Listing Copy Generation Status",
|
|
1212
1418
|
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`.",
|
|
1213
|
-
inputSchema:
|
|
1419
|
+
inputSchema: inputSchema34,
|
|
1214
1420
|
annotations: { readOnlyHint: true },
|
|
1215
1421
|
handler: async (args, ctx) => {
|
|
1216
1422
|
return await httpGet(
|
|
@@ -1221,16 +1427,16 @@ var getListingCopyGenerationStatusTool = {
|
|
|
1221
1427
|
};
|
|
1222
1428
|
|
|
1223
1429
|
// src/tools/list-seller-profiles.ts
|
|
1224
|
-
import { z as
|
|
1225
|
-
var
|
|
1226
|
-
currentPage:
|
|
1227
|
-
pageSize:
|
|
1430
|
+
import { z as z34 } from "zod";
|
|
1431
|
+
var inputSchema35 = {
|
|
1432
|
+
currentPage: z34.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1433
|
+
pageSize: z34.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
|
|
1228
1434
|
};
|
|
1229
1435
|
var listSellerProfilesTool = {
|
|
1230
1436
|
name: "list_seller_profiles",
|
|
1231
1437
|
title: "List Connected Amazon Seller Profiles",
|
|
1232
1438
|
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).',
|
|
1233
|
-
inputSchema:
|
|
1439
|
+
inputSchema: inputSchema35,
|
|
1234
1440
|
annotations: { readOnlyHint: true },
|
|
1235
1441
|
handler: async (args, ctx) => {
|
|
1236
1442
|
return await httpGet(
|
|
@@ -1245,15 +1451,15 @@ var listSellerProfilesTool = {
|
|
|
1245
1451
|
};
|
|
1246
1452
|
|
|
1247
1453
|
// src/tools/get-seller-catalog.ts
|
|
1248
|
-
import { z as
|
|
1454
|
+
import { z as z36 } from "zod";
|
|
1249
1455
|
|
|
1250
1456
|
// src/tools/seller-scoped.ts
|
|
1251
|
-
import { z as
|
|
1457
|
+
import { z as z35 } from "zod";
|
|
1252
1458
|
var sellerScopedInputSchema = {
|
|
1253
|
-
sellerId:
|
|
1459
|
+
sellerId: z35.string().min(1).describe(
|
|
1254
1460
|
"Amazon seller account ID. Get it from `list_seller_profiles`, or find it on the Connections page at https://2.datadive.tools."
|
|
1255
1461
|
),
|
|
1256
|
-
marketplace:
|
|
1462
|
+
marketplace: z35.enum(SUPPORTED_MARKETPLACES).describe('Amazon marketplace code, e.g. "com" for amazon.com or "co.uk" for amazon.co.uk.')
|
|
1257
1463
|
};
|
|
1258
1464
|
function sellerMarketplacePath(sellerId, marketplace, suffix) {
|
|
1259
1465
|
return `/v1/seller_profiles/${encodeURIComponent(sellerId)}/marketplaces/${encodeURIComponent(
|
|
@@ -1262,19 +1468,19 @@ function sellerMarketplacePath(sellerId, marketplace, suffix) {
|
|
|
1262
1468
|
}
|
|
1263
1469
|
|
|
1264
1470
|
// src/tools/get-seller-catalog.ts
|
|
1265
|
-
var
|
|
1471
|
+
var inputSchema36 = {
|
|
1266
1472
|
...sellerScopedInputSchema,
|
|
1267
|
-
search:
|
|
1268
|
-
brand:
|
|
1269
|
-
status:
|
|
1270
|
-
currentPage:
|
|
1271
|
-
pageSize:
|
|
1473
|
+
search: z36.string().min(1).optional().describe("Case-insensitive partial match on product title or brand."),
|
|
1474
|
+
brand: z36.string().min(1).optional().describe("Case-insensitive partial match on brand name."),
|
|
1475
|
+
status: z36.enum(CATALOG_STATUSES).optional().describe('Listing status filter. "Active" (default) or "all".'),
|
|
1476
|
+
currentPage: z36.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1477
|
+
pageSize: z36.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
|
|
1272
1478
|
};
|
|
1273
1479
|
var getSellerCatalogTool = {
|
|
1274
1480
|
name: "get_seller_catalog",
|
|
1275
1481
|
title: "List Catalog ASINs for a Seller",
|
|
1276
1482
|
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).",
|
|
1277
|
-
inputSchema:
|
|
1483
|
+
inputSchema: inputSchema36,
|
|
1278
1484
|
annotations: { readOnlyHint: true },
|
|
1279
1485
|
handler: async (args, ctx) => {
|
|
1280
1486
|
return await httpGet(
|
|
@@ -1292,28 +1498,28 @@ var getSellerCatalogTool = {
|
|
|
1292
1498
|
};
|
|
1293
1499
|
|
|
1294
1500
|
// src/tools/get-seller-listing-changes.ts
|
|
1295
|
-
import { z as
|
|
1296
|
-
var
|
|
1501
|
+
import { z as z37 } from "zod";
|
|
1502
|
+
var inputSchema37 = {
|
|
1297
1503
|
...sellerScopedInputSchema,
|
|
1298
|
-
types:
|
|
1299
|
-
asin:
|
|
1300
|
-
brand:
|
|
1301
|
-
search:
|
|
1302
|
-
startDate:
|
|
1303
|
-
endDate:
|
|
1304
|
-
sortBy:
|
|
1305
|
-
sortOrder:
|
|
1306
|
-
includeCorrelations:
|
|
1504
|
+
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".'),
|
|
1505
|
+
asin: z37.string().min(1).optional().describe("Filter to an exact ASIN or parent ASIN."),
|
|
1506
|
+
brand: z37.string().min(1).optional().describe("Case-insensitive partial match on brand name."),
|
|
1507
|
+
search: z37.string().min(1).optional().describe("Case-insensitive partial match on product title or brand."),
|
|
1508
|
+
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."),
|
|
1509
|
+
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."),
|
|
1510
|
+
sortBy: z37.enum(LISTING_CHANGE_SORT_BY).optional().describe('Sort field. "date" (default) or "type".'),
|
|
1511
|
+
sortOrder: z37.enum(SORT_ORDER).optional().describe('Sort direction. "DESC" (default) or "ASC".'),
|
|
1512
|
+
includeCorrelations: z37.boolean().optional().describe(
|
|
1307
1513
|
"When true, include the ranking/conversion `correlation` object per change (CVR and search-term movement before vs after). Defaults to false."
|
|
1308
1514
|
),
|
|
1309
|
-
currentPage:
|
|
1310
|
-
pageSize:
|
|
1515
|
+
currentPage: z37.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1516
|
+
pageSize: z37.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
|
|
1311
1517
|
};
|
|
1312
1518
|
var getSellerListingChangesTool = {
|
|
1313
1519
|
name: "get_seller_listing_changes",
|
|
1314
1520
|
title: "List Listing Changes for a Seller",
|
|
1315
1521
|
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).",
|
|
1316
|
-
inputSchema:
|
|
1522
|
+
inputSchema: inputSchema37,
|
|
1317
1523
|
annotations: { readOnlyHint: true },
|
|
1318
1524
|
handler: async (args, ctx) => {
|
|
1319
1525
|
return await httpGet(
|
|
@@ -1338,40 +1544,40 @@ var getSellerListingChangesTool = {
|
|
|
1338
1544
|
};
|
|
1339
1545
|
|
|
1340
1546
|
// src/tools/list-ppc-campaigns.ts
|
|
1341
|
-
import { z as
|
|
1547
|
+
import { z as z38 } from "zod";
|
|
1342
1548
|
var PPC_CAMPAIGNS_MAX_WINDOW_DAYS = 90;
|
|
1343
1549
|
var PPC_CAMPAIGNS_MAX_PAGE_SIZE = 50;
|
|
1344
|
-
var
|
|
1550
|
+
var inputSchema38 = {
|
|
1345
1551
|
...sellerScopedInputSchema,
|
|
1346
|
-
startDate:
|
|
1552
|
+
startDate: z38.string().regex(
|
|
1347
1553
|
ISO_8601,
|
|
1348
1554
|
"startDate must be an ISO-8601 date or timestamp (e.g. 2026-05-01 or 2026-05-01T00:00:00Z)"
|
|
1349
1555
|
).optional().describe("Start of the reporting window, ISO-8601. Defaults to 30 days before endDate."),
|
|
1350
|
-
endDate:
|
|
1556
|
+
endDate: z38.string().regex(
|
|
1351
1557
|
ISO_8601,
|
|
1352
1558
|
"endDate must be an ISO-8601 date or timestamp (e.g. 2026-05-31 or 2026-05-31T23:59:59Z)"
|
|
1353
1559
|
).optional().describe(
|
|
1354
1560
|
`End of the reporting window, ISO-8601. Defaults to now. At most ${PPC_CAMPAIGNS_MAX_WINDOW_DAYS} days after startDate.`
|
|
1355
1561
|
),
|
|
1356
|
-
asin:
|
|
1357
|
-
parentAsin:
|
|
1358
|
-
search:
|
|
1359
|
-
includePlacements:
|
|
1562
|
+
asin: z38.string().min(1).optional().describe("Only campaigns advertising this ASIN. Cannot be combined with parentAsin."),
|
|
1563
|
+
parentAsin: z38.string().min(1).optional().describe("Only campaigns advertising any ASIN of this variation family. Cannot be combined with asin."),
|
|
1564
|
+
search: z38.string().min(3).max(200).optional().describe("Partial match on campaign name or advertised ASIN. At least 3 characters."),
|
|
1565
|
+
includePlacements: z38.boolean().optional().describe(
|
|
1360
1566
|
"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."
|
|
1361
1567
|
),
|
|
1362
|
-
sortBy:
|
|
1568
|
+
sortBy: z38.enum([...PPC_CAMPAIGN_BASE_SORT_BY, ...PPC_CAMPAIGN_PLACEMENT_SORT_BY]).optional().describe(
|
|
1363
1569
|
`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.`
|
|
1364
1570
|
),
|
|
1365
|
-
sortOrder:
|
|
1366
|
-
state:
|
|
1367
|
-
currentPage:
|
|
1368
|
-
pageSize:
|
|
1571
|
+
sortOrder: z38.enum(SORT_ORDER).optional().describe('Sort direction. "ASC" (default) or "DESC".'),
|
|
1572
|
+
state: z38.enum(PPC_CAMPAIGN_STATES).optional().describe("Only ENABLED or only PAUSED campaigns. Omit for both."),
|
|
1573
|
+
currentPage: z38.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1574
|
+
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.`)
|
|
1369
1575
|
};
|
|
1370
1576
|
var listPpcCampaignsTool = {
|
|
1371
1577
|
name: "list_ppc_campaigns",
|
|
1372
1578
|
title: "List PPC Campaigns for a Seller",
|
|
1373
1579
|
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\`.`,
|
|
1374
|
-
inputSchema:
|
|
1580
|
+
inputSchema: inputSchema38,
|
|
1375
1581
|
annotations: { readOnlyHint: true },
|
|
1376
1582
|
handler: async (args, ctx) => {
|
|
1377
1583
|
if (args.asin && args.parentAsin) {
|
|
@@ -1402,21 +1608,21 @@ var listPpcCampaignsTool = {
|
|
|
1402
1608
|
};
|
|
1403
1609
|
|
|
1404
1610
|
// src/tools/get-asin-inventory-distribution.ts
|
|
1405
|
-
import { z as
|
|
1406
|
-
var
|
|
1407
|
-
sellerId:
|
|
1611
|
+
import { z as z39 } from "zod";
|
|
1612
|
+
var inputSchema39 = {
|
|
1613
|
+
sellerId: z39.string().min(1).describe(
|
|
1408
1614
|
"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."
|
|
1409
1615
|
),
|
|
1410
|
-
marketplace:
|
|
1411
|
-
asin:
|
|
1616
|
+
marketplace: z39.enum(SUPPORTED_MARKETPLACES).describe('Amazon marketplace code, e.g. "com" for amazon.com or "co.uk" for amazon.co.uk.'),
|
|
1617
|
+
asin: z39.string().regex(/^[A-Z0-9]{10}$/, "ASIN must be 10 uppercase alphanumeric characters (e.g. B08XYZ1234).").describe(
|
|
1412
1618
|
"Amazon Standard Identification Number (10 uppercase alphanumeric characters, e.g. B08XYZ1234)."
|
|
1413
1619
|
)
|
|
1414
1620
|
};
|
|
1415
1621
|
var getAsinInventoryDistributionTool = {
|
|
1416
1622
|
name: "get_asin_inventory_distribution",
|
|
1417
|
-
title: "Get
|
|
1418
|
-
description: "Use this when the user asks about inventory levels, stock
|
|
1419
|
-
inputSchema:
|
|
1623
|
+
title: "Get Inventory Metrics and Fulfillment-Center Distribution for an ASIN",
|
|
1624
|
+
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.",
|
|
1625
|
+
inputSchema: inputSchema39,
|
|
1420
1626
|
annotations: { readOnlyHint: true },
|
|
1421
1627
|
handler: async (args, ctx) => {
|
|
1422
1628
|
return await httpGet(
|
|
@@ -1429,18 +1635,18 @@ var getAsinInventoryDistributionTool = {
|
|
|
1429
1635
|
};
|
|
1430
1636
|
|
|
1431
1637
|
// src/tools/alert-query.ts
|
|
1432
|
-
import { z as
|
|
1638
|
+
import { z as z40 } from "zod";
|
|
1433
1639
|
var alertsQueryInputSchema = {
|
|
1434
|
-
sellerId:
|
|
1435
|
-
marketplace:
|
|
1436
|
-
status:
|
|
1640
|
+
sellerId: z40.string().min(1).max(50).optional().describe('Filter to a single connected Amazon seller account ID, e.g. "A1B2C3D4E5".'),
|
|
1641
|
+
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.'),
|
|
1642
|
+
status: z40.enum(ALERT_STATUSES).optional().describe(
|
|
1437
1643
|
"Lifecycle filter. `active` (default) returns unresolved alerts, `resolved` returns resolved alerts, `all` returns both. Dismissed alerts are never returned."
|
|
1438
1644
|
),
|
|
1439
|
-
updatedSince:
|
|
1645
|
+
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(
|
|
1440
1646
|
"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."
|
|
1441
1647
|
),
|
|
1442
|
-
currentPage:
|
|
1443
|
-
pageSize:
|
|
1648
|
+
currentPage: z40.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1649
|
+
pageSize: z40.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
|
|
1444
1650
|
};
|
|
1445
1651
|
|
|
1446
1652
|
// src/tools/list-indexing-issue-alerts.ts
|
|
@@ -1490,12 +1696,12 @@ var listBlindSpendAlertsTool = {
|
|
|
1490
1696
|
};
|
|
1491
1697
|
|
|
1492
1698
|
// src/tools/get-quota.ts
|
|
1493
|
-
var
|
|
1699
|
+
var inputSchema40 = {};
|
|
1494
1700
|
var getQuotaTool = {
|
|
1495
1701
|
name: "get_quota",
|
|
1496
1702
|
title: "Get Quota Usage",
|
|
1497
1703
|
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.",
|
|
1498
|
-
inputSchema:
|
|
1704
|
+
inputSchema: inputSchema40,
|
|
1499
1705
|
annotations: { readOnlyHint: true },
|
|
1500
1706
|
handler: async (_args, ctx) => {
|
|
1501
1707
|
return await httpGet({ config: ctx.config, toolName: "get_quota" }, "/v1/quota");
|
|
@@ -1503,20 +1709,20 @@ var getQuotaTool = {
|
|
|
1503
1709
|
};
|
|
1504
1710
|
|
|
1505
1711
|
// src/tools/list-usage.ts
|
|
1506
|
-
import { z as
|
|
1507
|
-
var
|
|
1508
|
-
type:
|
|
1509
|
-
search:
|
|
1510
|
-
startDate:
|
|
1511
|
-
endDate:
|
|
1512
|
-
currentPage:
|
|
1513
|
-
pageSize:
|
|
1712
|
+
import { z as z41 } from "zod";
|
|
1713
|
+
var inputSchema41 = {
|
|
1714
|
+
type: z41.enum(BILLABLE_FEATURE_TYPES).optional().describe("Filter to a single billable feature type. Omit to return all types."),
|
|
1715
|
+
search: z41.string().min(1).optional().describe("Case-insensitive partial match on the user's name or email."),
|
|
1716
|
+
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."),
|
|
1717
|
+
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."),
|
|
1718
|
+
currentPage: z41.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
|
|
1719
|
+
pageSize: z41.number().int().min(1).max(200).optional().describe("Items per page (max 200). Defaults to 50.")
|
|
1514
1720
|
};
|
|
1515
1721
|
var listUsageTool = {
|
|
1516
1722
|
name: "list_usage",
|
|
1517
1723
|
title: "List Billable Usage Logs",
|
|
1518
1724
|
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).",
|
|
1519
|
-
inputSchema:
|
|
1725
|
+
inputSchema: inputSchema41,
|
|
1520
1726
|
annotations: { readOnlyHint: true },
|
|
1521
1727
|
handler: async (args, ctx) => {
|
|
1522
1728
|
return await httpGet(
|
|
@@ -1546,6 +1752,7 @@ var allTools = [
|
|
|
1546
1752
|
getRankRadarDataTool,
|
|
1547
1753
|
getRankRadarSqpDataTool,
|
|
1548
1754
|
getRankRadarPpcDataTool,
|
|
1755
|
+
listRankRadarTagsTool,
|
|
1549
1756
|
createRankRadarTool,
|
|
1550
1757
|
createNicheDiveTool,
|
|
1551
1758
|
createNicheDiveFromCompetitorsListTool,
|
|
@@ -1558,6 +1765,11 @@ var allTools = [
|
|
|
1558
1765
|
addRankRadarSearchTermsTool,
|
|
1559
1766
|
pauseRankRadarSearchTermsTool,
|
|
1560
1767
|
resumeRankRadarSearchTermsTool,
|
|
1768
|
+
createRankRadarTagTool,
|
|
1769
|
+
updateRankRadarTagTool,
|
|
1770
|
+
addRankRadarTagSearchTermsTool,
|
|
1771
|
+
removeRankRadarTagSearchTermsTool,
|
|
1772
|
+
deleteRankRadarTagTool,
|
|
1561
1773
|
pauseRankRadarTool,
|
|
1562
1774
|
resumeRankRadarTool,
|
|
1563
1775
|
deleteRankRadarTool,
|
|
@@ -1577,6 +1789,13 @@ var allTools = [
|
|
|
1577
1789
|
|
|
1578
1790
|
// src/whats-new.ts
|
|
1579
1791
|
var WHATS_NEW = [
|
|
1792
|
+
{
|
|
1793
|
+
version: "0.17.1",
|
|
1794
|
+
released: "2026-10-13",
|
|
1795
|
+
items: [
|
|
1796
|
+
"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."
|
|
1797
|
+
]
|
|
1798
|
+
},
|
|
1580
1799
|
{
|
|
1581
1800
|
version: "0.17.0",
|
|
1582
1801
|
released: "2026-10-12",
|