@datadive-tools/mcp 0.8.0 → 0.10.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/dist/lib.js CHANGED
@@ -100,7 +100,7 @@ function extractMessage(body) {
100
100
  }
101
101
 
102
102
  // package.json
103
- var version = "0.8.0";
103
+ var version = "0.10.0";
104
104
 
105
105
  // src/http/client.ts
106
106
  var PKG_VERSION = version;
@@ -217,21 +217,37 @@ function isObject(v) {
217
217
  }
218
218
 
219
219
  // src/tools/list-niches.ts
220
+ var LIST_NICHES_MAX_PAGE_SIZE = 50;
220
221
  var inputSchema = {
221
- currentPage: z.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
222
- pageSize: z.number().int().min(1).max(100).optional().describe("Items per page (max 100). Defaults to 20.")
222
+ currentPage: z.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1. Keep requesting the next page while `hasNext` is true."),
223
+ pageSize: z.number().int().min(1).max(LIST_NICHES_MAX_PAGE_SIZE).optional().describe(`Items per page (max ${LIST_NICHES_MAX_PAGE_SIZE}). Defaults to 20.`),
224
+ searchText: z.string().trim().min(1).max(200).optional().describe(
225
+ "Case-insensitive partial match on the niche label or hero keyword. Prefer this over paging through everything when the user names a niche."
226
+ ),
227
+ searchAsin: z.string().trim().regex(/^[A-Za-z0-9]{10}$/, "must be a 10-character ASIN").optional().describe("Only niches whose competitor set contains this ASIN (10 characters, e.g. B08N5WRWNW)."),
228
+ orderBy: z.enum(["lastDived", "name"]).optional().describe(
229
+ "Sort field: `lastDived` (by latestResearchDate, newest first by default) or `name` (by nicheLabel, A\u2192Z by default). Defaults to `lastDived`."
230
+ ),
231
+ sortOrder: z.enum(["ASC", "DESC"]).optional().describe("Sort direction. Defaults to DESC for `lastDived` and ASC for `name`.")
223
232
  };
224
233
  var listNichesTool = {
225
234
  name: "list_niches",
226
235
  title: "List DataDive Niches",
227
- description: "Use this first when the user asks about their niches, or to find a `nicheId` for use with `get_niche_keywords`, `get_niche_competitors`, or `get_ranking_juice`. Retrieves a paginated list of Niches. Each Niche represents a market segment or product category being tracked. Returns nicheId, heroKeyword, nicheLabel, marketplace (com/uk/de/...), and latestResearchDate per niche, plus pagination metadata (currentPage, pageSize, total, lastPage, hasNext, hasPrev).",
236
+ description: `Use this first when the user asks about their niches, or to find a \`nicheId\` for use with \`get_niche_keywords\`, \`get_niche_competitors\`, or \`get_ranking_juice\`. Retrieves a paginated list of Niches, newest dive first. Each Niche represents a market segment or product category being tracked. Returns nicheId, heroKeyword, nicheLabel, marketplace (com/uk/de/...), and latestResearchDate per niche, plus pagination metadata (currentPage, pageSize, total, lastPage, hasNext, hasPrev). Narrow with \`searchText\` (label/keyword) or \`searchAsin\` (a competitor ASIN) instead of scanning pages; a page holds at most ${LIST_NICHES_MAX_PAGE_SIZE} niches, so the full list of a large account needs several calls.`,
228
237
  inputSchema,
229
238
  annotations: { readOnlyHint: true },
230
239
  handler: async (args, ctx) => {
231
240
  return await httpGet(
232
241
  { config: ctx.config, toolName: "list_niches" },
233
242
  "/v1/niches",
234
- { currentPage: args.currentPage, pageSize: args.pageSize }
243
+ {
244
+ currentPage: args.currentPage,
245
+ pageSize: args.pageSize,
246
+ searchText: args.searchText,
247
+ searchAsin: args.searchAsin,
248
+ orderBy: args.orderBy,
249
+ sortOrder: args.sortOrder
250
+ }
235
251
  );
236
252
  }
237
253
  };
@@ -421,7 +437,7 @@ var inputSchema8 = {
421
437
  var createRankRadarTool = {
422
438
  name: "create_rank_radar",
423
439
  title: "Create a Rank Radar",
424
- description: "Use this to start tracking organic and sponsored keyword rankings for an ASIN within a niche. \u26A0\uFE0F Spends Search Term tokens (cost scales with `numberOfKeywords`) and cannot be undone \u2014 set `confirm: true` only after the user approves the cost. Returns the new `rankRadarId`; read its data later with `get_rank_radar_data`. Requires `asin`, `numberOfKeywords` (min 1), and a `nicheId` from `list_niches`.",
440
+ description: "Use this to start tracking organic and sponsored keyword rankings for an ASIN within a niche. \u26A0\uFE0F Spends Search Term tokens (cost scales with `numberOfKeywords`) and cannot be undone \u2014 set `confirm: true` only after the user approves the cost. Not safe to retry: each call spends tokens again and creates a separate Rank Radar \u2014 if a call errors or times out, check `list_rank_radars` instead of re-calling. Returns the new `rankRadarId`; read its data later with `get_rank_radar_data`. Requires `asin`, `numberOfKeywords` (min 1), and a `nicheId` from `list_niches`.",
425
441
  inputSchema: inputSchema8,
426
442
  // destructiveHint is technically "additive" here (this creates a new Rank Radar, it
427
443
  // doesn't destroy data), but we flag it destructive so clients prompt before the
@@ -459,7 +475,7 @@ var inputSchema9 = {
459
475
  var createNicheDiveTool = {
460
476
  name: "create_niche_dive",
461
477
  title: "Create a Niche Dive",
462
- description: "Use this to start new niche research from a seed ASIN. \u26A0\uFE0F Spends dive tokens (cost scales with `numberOfCompetitors`) and cannot be undone \u2014 set `confirm: true` only after the user approves the cost. The dive runs asynchronously: this returns immediately with a `diveId` and an `estimatedCompletionDate`. Poll `get_dive_status` with that `diveId` until it reports `success` (which carries the new `nicheId` for use with `list_niches`, `get_niche_keywords`, etc.). Requires `marketplace`, `asin`, and `numberOfCompetitors` (min 2).",
478
+ description: "Use this to start new niche research from a seed ASIN. \u26A0\uFE0F Spends dive tokens (cost scales with `numberOfCompetitors`) and cannot be undone \u2014 set `confirm: true` only after the user approves the cost. Not safe to retry: each call spends tokens again and starts a separate dive \u2014 if a call errors or times out, poll `get_dive_status` (or check `list_niches`) instead of re-calling. The dive runs asynchronously: this returns immediately with a `diveId` and an `estimatedCompletionDate`. Poll `get_dive_status` with that `diveId` until it reports `success` (which carries the new `nicheId` for use with `list_niches`, `get_niche_keywords`, etc.). Requires `marketplace`, `asin`, and `numberOfCompetitors` (min 2).",
463
479
  inputSchema: inputSchema9,
464
480
  // destructiveHint is technically "additive" here (a dive creates a new niche, it
465
481
  // doesn't destroy data), but we flag it destructive so clients prompt before the
@@ -484,16 +500,73 @@ var createNicheDiveTool = {
484
500
  }
485
501
  };
486
502
 
487
- // src/tools/get-dive-status.ts
503
+ // src/tools/redive-niche.ts
488
504
  import { z as z10 } from "zod";
489
505
  var inputSchema10 = {
490
- diveId: z10.string().min(1).describe("The dive identifier returned by `create_niche_dive`.")
506
+ nicheId: z10.string().min(1).describe("The niche to re-dive. Get one from `list_niches`."),
507
+ mode: z10.enum(["same_competitors", "discover"]).describe(
508
+ "How to pick the competitors for the refreshed dive. `same_competitors` re-runs the niche's current competitor set and takes no other argument \u2014 use it to refresh stale data. `discover` searches for a fresh competitor set, which is what you want when the niche has changed."
509
+ ),
510
+ numberOfCompetitors: z10.number().int().min(2).optional().describe(
511
+ "Total ASINs the refreshed dive should contain, including `lockedAsins`. Required in `discover` mode and rejected in `same_competitors` mode. Dive tokens are spent per ASIN."
512
+ ),
513
+ heroAsin: z10.string().min(1).optional().describe(
514
+ "`discover` mode only. Seed product the competitor discovery starts from. Defaults to the niche's highest-selling competitor, preferring one the user's own connected seller account owns."
515
+ ),
516
+ lockedAsins: z10.array(z10.string().min(1)).optional().describe(
517
+ "`discover` mode only. ASINs that must stay in the competitor set regardless of what discovery finds. Cannot exceed `numberOfCompetitors`, and cannot overlap `excludedAsins`."
518
+ ),
519
+ excludedAsins: z10.array(z10.string().min(1)).optional().describe("`discover` mode only. ASINs discovery must never select."),
520
+ confirm: z10.boolean().optional().describe(
521
+ "Must be true to proceed \u2014 a re-dive spends dive tokens. Confirm the cost with the user first."
522
+ )
523
+ };
524
+ var rediveNicheTool = {
525
+ name: "redive_niche",
526
+ title: "Re-dive an Existing Niche",
527
+ description: "Use this to refresh an existing niche's research with current Amazon data, instead of creating a new niche with `create_niche_dive`. \u26A0\uFE0F Spends dive tokens (one batch per ASIN dived) and cannot be undone \u2014 set `confirm: true` only after the user approves the cost. Not safe to retry: each call spends tokens again and starts a separate re-dive \u2014 if a call errors or times out, poll `get_dive_status` instead of re-calling. Two modes: `same_competitors` re-dives the niche's current competitor set (no other argument needed) and `discover` finds a fresh set, sized by `numberOfCompetitors` and steerable with `heroAsin` / `lockedAsins` / `excludedAsins`. Runs asynchronously: returns a `diveId` and an `estimatedCompletionDate` \u2014 poll `get_dive_status` with that `diveId` until it reports `success`. The niche keeps its `nicheId`, so existing rank radars and reports follow the refreshed data.",
528
+ inputSchema: inputSchema10,
529
+ // Same reasoning as create_niche_dive: a re-dive is additive rather than destructive, but the
530
+ // irreversible token spend is what clients need to prompt on. The confirm gate enforces it regardless.
531
+ annotations: { readOnlyHint: false, destructiveHint: true },
532
+ handler: async (args, ctx) => {
533
+ if (args.mode === "discover" && args.numberOfCompetitors === void 0) {
534
+ throw new ApiError(
535
+ "bad_request",
536
+ 400,
537
+ 'numberOfCompetitors is required in `discover` mode \u2014 it is how many ASINs the refreshed dive will contain, and therefore what it costs. Ask the user how many competitors they want (minimum 2), or use mode "same_competitors" to re-dive the niche\'s current set.'
538
+ );
539
+ }
540
+ const pending = requireConfirmation(
541
+ args.confirm,
542
+ ctx,
543
+ args.mode === "discover" ? `Re-diving this niche consumes dive tokens \u2014 one batch per ASIN analyzed (${args.numberOfCompetitors} requested).` : "Re-diving this niche consumes dive tokens \u2014 one batch per competitor currently in the niche. Use `get_niche_competitors` first if the user needs the exact count."
544
+ );
545
+ if (pending) return pending;
546
+ return await httpPost(
547
+ { config: ctx.config, toolName: "redive_niche" },
548
+ `/v1/niches/${encodeURIComponent(args.nicheId)}/redive`,
549
+ {
550
+ mode: args.mode,
551
+ numberOfCompetitors: args.numberOfCompetitors,
552
+ heroAsin: args.heroAsin,
553
+ lockedAsins: args.lockedAsins,
554
+ excludedAsins: args.excludedAsins
555
+ }
556
+ );
557
+ }
558
+ };
559
+
560
+ // src/tools/get-dive-status.ts
561
+ import { z as z11 } from "zod";
562
+ var inputSchema11 = {
563
+ diveId: z11.string().min(1).describe("The dive identifier returned by `create_niche_dive` or `redive_niche`.")
491
564
  };
492
565
  var getDiveStatusTool = {
493
566
  name: "get_dive_status",
494
567
  title: "Get Niche Dive Status",
495
- description: "Use this to poll a niche dive started with `create_niche_dive` until it finishes. Returns one of three shapes keyed by `status`: `in_progress` (with `estimatedCompletionDate`), `success` (with the new `nicheId` plus `tokensUsed`/`tokensLeft`), or `error` (with an `error` message). On `success`, use the `nicheId` with `list_niches`, `get_niche_keywords`, `get_niche_competitors`, etc. Re-poll periodically \u2014 dives can take minutes; the `estimatedCompletionDate` hints at when to check.",
496
- inputSchema: inputSchema10,
568
+ description: "Use this to poll a niche dive started with `create_niche_dive` or `redive_niche` until it finishes. Returns one of three shapes keyed by `status`: `in_progress` (with `estimatedCompletionDate`), `success` (with the `nicheId` plus `tokensUsed`/`tokensLeft`), or `error` (with an `error` message). On `success`, use the `nicheId` with `list_niches`, `get_niche_keywords`, `get_niche_competitors`, etc. (for a re-dive it is the same niche you passed in, now carrying refreshed data). Re-poll periodically \u2014 dives can take minutes; the `estimatedCompletionDate` hints at when to check.",
569
+ inputSchema: inputSchema11,
497
570
  annotations: { readOnlyHint: true },
498
571
  handler: async (args, ctx) => {
499
572
  return await httpGet(
@@ -504,16 +577,16 @@ var getDiveStatusTool = {
504
577
  };
505
578
 
506
579
  // src/tools/list-seller-profiles.ts
507
- import { z as z11 } from "zod";
508
- var inputSchema11 = {
509
- currentPage: z11.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
510
- pageSize: z11.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
580
+ import { z as z12 } from "zod";
581
+ var inputSchema12 = {
582
+ currentPage: z12.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
583
+ pageSize: z12.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
511
584
  };
512
585
  var listSellerProfilesTool = {
513
586
  name: "list_seller_profiles",
514
587
  title: "List Connected Amazon Seller Profiles",
515
588
  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).',
516
- inputSchema: inputSchema11,
589
+ inputSchema: inputSchema12,
517
590
  annotations: { readOnlyHint: true },
518
591
  handler: async (args, ctx) => {
519
592
  return await httpGet(
@@ -528,15 +601,15 @@ var listSellerProfilesTool = {
528
601
  };
529
602
 
530
603
  // src/tools/get-seller-catalog.ts
531
- import { z as z13 } from "zod";
604
+ import { z as z14 } from "zod";
532
605
 
533
606
  // src/tools/seller-scoped.ts
534
- import { z as z12 } from "zod";
607
+ import { z as z13 } from "zod";
535
608
  var sellerScopedInputSchema = {
536
- sellerId: z12.string().min(1).describe(
609
+ sellerId: z13.string().min(1).describe(
537
610
  "Amazon seller account ID. Get it from `list_seller_profiles`, or find it on the Connections page at https://2.datadive.tools."
538
611
  ),
539
- marketplace: z12.enum(SUPPORTED_MARKETPLACES).describe('Amazon marketplace code, e.g. "com" for amazon.com or "co.uk" for amazon.co.uk.')
612
+ marketplace: z13.enum(SUPPORTED_MARKETPLACES).describe('Amazon marketplace code, e.g. "com" for amazon.com or "co.uk" for amazon.co.uk.')
540
613
  };
541
614
  function sellerMarketplacePath(sellerId, marketplace, suffix) {
542
615
  return `/v1/seller_profiles/${encodeURIComponent(sellerId)}/marketplaces/${encodeURIComponent(
@@ -545,19 +618,19 @@ function sellerMarketplacePath(sellerId, marketplace, suffix) {
545
618
  }
546
619
 
547
620
  // src/tools/get-seller-catalog.ts
548
- var inputSchema12 = {
621
+ var inputSchema13 = {
549
622
  ...sellerScopedInputSchema,
550
- search: z13.string().min(1).optional().describe("Case-insensitive partial match on product title or brand."),
551
- brand: z13.string().min(1).optional().describe("Case-insensitive partial match on brand name."),
552
- status: z13.enum(CATALOG_STATUSES).optional().describe('Listing status filter. "Active" (default) or "all".'),
553
- currentPage: z13.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
554
- pageSize: z13.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
623
+ search: z14.string().min(1).optional().describe("Case-insensitive partial match on product title or brand."),
624
+ brand: z14.string().min(1).optional().describe("Case-insensitive partial match on brand name."),
625
+ status: z14.enum(CATALOG_STATUSES).optional().describe('Listing status filter. "Active" (default) or "all".'),
626
+ currentPage: z14.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
627
+ pageSize: z14.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
555
628
  };
556
629
  var getSellerCatalogTool = {
557
630
  name: "get_seller_catalog",
558
631
  title: "List Catalog ASINs for a Seller",
559
632
  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).",
560
- inputSchema: inputSchema12,
633
+ inputSchema: inputSchema13,
561
634
  annotations: { readOnlyHint: true },
562
635
  handler: async (args, ctx) => {
563
636
  return await httpGet(
@@ -575,28 +648,28 @@ var getSellerCatalogTool = {
575
648
  };
576
649
 
577
650
  // src/tools/get-seller-listing-changes.ts
578
- import { z as z14 } from "zod";
579
- var inputSchema13 = {
651
+ import { z as z15 } from "zod";
652
+ var inputSchema14 = {
580
653
  ...sellerScopedInputSchema,
581
- types: z14.array(z14.enum(LISTING_CHANGE_TYPES)).min(1).optional().describe('Filter to specific change types. Omit for all. Any of "Price", "Content", "Image".'),
582
- asin: z14.string().min(1).optional().describe("Filter to an exact ASIN or parent ASIN."),
583
- brand: z14.string().min(1).optional().describe("Case-insensitive partial match on brand name."),
584
- search: z14.string().min(1).optional().describe("Case-insensitive partial match on product title or brand."),
585
- startDate: z14.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."),
586
- endDate: z14.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."),
587
- sortBy: z14.enum(LISTING_CHANGE_SORT_BY).optional().describe('Sort field. "date" (default) or "type".'),
588
- sortOrder: z14.enum(SORT_ORDER).optional().describe('Sort direction. "DESC" (default) or "ASC".'),
589
- includeCorrelations: z14.boolean().optional().describe(
654
+ types: z15.array(z15.enum(LISTING_CHANGE_TYPES)).min(1).optional().describe('Filter to specific change types. Omit for all. Any of "Price", "Content", "Image".'),
655
+ asin: z15.string().min(1).optional().describe("Filter to an exact ASIN or parent ASIN."),
656
+ brand: z15.string().min(1).optional().describe("Case-insensitive partial match on brand name."),
657
+ search: z15.string().min(1).optional().describe("Case-insensitive partial match on product title or brand."),
658
+ startDate: z15.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."),
659
+ endDate: z15.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."),
660
+ sortBy: z15.enum(LISTING_CHANGE_SORT_BY).optional().describe('Sort field. "date" (default) or "type".'),
661
+ sortOrder: z15.enum(SORT_ORDER).optional().describe('Sort direction. "DESC" (default) or "ASC".'),
662
+ includeCorrelations: z15.boolean().optional().describe(
590
663
  "When true, include the ranking/conversion `correlation` object per change (CVR and search-term movement before vs after). Defaults to false."
591
664
  ),
592
- currentPage: z14.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
593
- pageSize: z14.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
665
+ currentPage: z15.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
666
+ pageSize: z15.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
594
667
  };
595
668
  var getSellerListingChangesTool = {
596
669
  name: "get_seller_listing_changes",
597
670
  title: "List Listing Changes for a Seller",
598
671
  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).",
599
- inputSchema: inputSchema13,
672
+ inputSchema: inputSchema14,
600
673
  annotations: { readOnlyHint: true },
601
674
  handler: async (args, ctx) => {
602
675
  return await httpGet(
@@ -621,13 +694,13 @@ var getSellerListingChangesTool = {
621
694
  };
622
695
 
623
696
  // src/tools/get-asin-inventory-distribution.ts
624
- import { z as z15 } from "zod";
625
- var inputSchema14 = {
626
- sellerId: z15.string().min(1).describe(
697
+ import { z as z16 } from "zod";
698
+ var inputSchema15 = {
699
+ sellerId: z16.string().min(1).describe(
627
700
  "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."
628
701
  ),
629
- marketplace: z15.enum(SUPPORTED_MARKETPLACES).describe('Amazon marketplace code, e.g. "com" for amazon.com or "co.uk" for amazon.co.uk.'),
630
- asin: z15.string().regex(/^[A-Z0-9]{10}$/, "ASIN must be 10 uppercase alphanumeric characters (e.g. B08XYZ1234).").describe(
702
+ marketplace: z16.enum(SUPPORTED_MARKETPLACES).describe('Amazon marketplace code, e.g. "com" for amazon.com or "co.uk" for amazon.co.uk.'),
703
+ asin: z16.string().regex(/^[A-Z0-9]{10}$/, "ASIN must be 10 uppercase alphanumeric characters (e.g. B08XYZ1234).").describe(
631
704
  "Amazon Standard Identification Number (10 uppercase alphanumeric characters, e.g. B08XYZ1234)."
632
705
  )
633
706
  };
@@ -635,7 +708,7 @@ var getAsinInventoryDistributionTool = {
635
708
  name: "get_asin_inventory_distribution",
636
709
  title: "Get Per-Fulfillment-Center Inventory Distribution for an ASIN",
637
710
  description: "Use this when the user asks about inventory levels, stock by fulfillment center, or where their units are sitting across Amazon's fulfillment network for a specific ASIN. Requires the Amazon sellerId (from `list_seller_profiles` or the user's DataDive Connections page at https://2.datadive.tools), the marketplace code, and the ASIN. Returns totalSellableUnits and a per-FC `distribution` array (fc, state, availableStock, availableStockPercentage). `lastUpdatedAt` may be null when no successful inventory ingestion has occurred in the last 30 days.",
638
- inputSchema: inputSchema14,
711
+ inputSchema: inputSchema15,
639
712
  annotations: { readOnlyHint: true },
640
713
  handler: async (args, ctx) => {
641
714
  return await httpGet(
@@ -648,18 +721,18 @@ var getAsinInventoryDistributionTool = {
648
721
  };
649
722
 
650
723
  // src/tools/alert-query.ts
651
- import { z as z16 } from "zod";
724
+ import { z as z17 } from "zod";
652
725
  var alertsQueryInputSchema = {
653
- sellerId: z16.string().min(1).max(50).optional().describe('Filter to a single connected Amazon seller account ID, e.g. "A1B2C3D4E5".'),
654
- marketplace: z16.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.'),
655
- status: z16.enum(ALERT_STATUSES).optional().describe(
726
+ sellerId: z17.string().min(1).max(50).optional().describe('Filter to a single connected Amazon seller account ID, e.g. "A1B2C3D4E5".'),
727
+ marketplace: z17.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.'),
728
+ status: z17.enum(ALERT_STATUSES).optional().describe(
656
729
  "Lifecycle filter. `active` (default) returns unresolved alerts, `resolved` returns resolved alerts, `all` returns both. Dismissed alerts are never returned."
657
730
  ),
658
- updatedSince: z16.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(
731
+ updatedSince: z17.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(
659
732
  "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."
660
733
  ),
661
- currentPage: z16.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
662
- pageSize: z16.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
734
+ currentPage: z17.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
735
+ pageSize: z17.number().int().min(1).max(50).optional().describe("Items per page (max 50). Defaults to 20.")
663
736
  };
664
737
 
665
738
  // src/tools/list-indexing-issue-alerts.ts
@@ -709,12 +782,12 @@ var listBlindSpendAlertsTool = {
709
782
  };
710
783
 
711
784
  // src/tools/get-quota.ts
712
- var inputSchema15 = {};
785
+ var inputSchema16 = {};
713
786
  var getQuotaTool = {
714
787
  name: "get_quota",
715
788
  title: "Get Quota Usage",
716
789
  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.",
717
- inputSchema: inputSchema15,
790
+ inputSchema: inputSchema16,
718
791
  annotations: { readOnlyHint: true },
719
792
  handler: async (_args, ctx) => {
720
793
  return await httpGet({ config: ctx.config, toolName: "get_quota" }, "/v1/quota");
@@ -722,20 +795,20 @@ var getQuotaTool = {
722
795
  };
723
796
 
724
797
  // src/tools/list-usage.ts
725
- import { z as z17 } from "zod";
726
- var inputSchema16 = {
727
- type: z17.enum(BILLABLE_FEATURE_TYPES).optional().describe("Filter to a single billable feature type. Omit to return all types."),
728
- search: z17.string().min(1).optional().describe("Case-insensitive partial match on the user's name or email."),
729
- startDate: z17.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."),
730
- endDate: z17.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."),
731
- currentPage: z17.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
732
- pageSize: z17.number().int().min(1).max(200).optional().describe("Items per page (max 200). Defaults to 50.")
798
+ import { z as z18 } from "zod";
799
+ var inputSchema17 = {
800
+ type: z18.enum(BILLABLE_FEATURE_TYPES).optional().describe("Filter to a single billable feature type. Omit to return all types."),
801
+ search: z18.string().min(1).optional().describe("Case-insensitive partial match on the user's name or email."),
802
+ startDate: z18.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."),
803
+ endDate: z18.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."),
804
+ currentPage: z18.number().int().min(1).optional().describe("Page number, 1-indexed. Defaults to 1."),
805
+ pageSize: z18.number().int().min(1).max(200).optional().describe("Items per page (max 200). Defaults to 50.")
733
806
  };
734
807
  var listUsageTool = {
735
808
  name: "list_usage",
736
809
  title: "List Billable Usage Logs",
737
810
  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).",
738
- inputSchema: inputSchema16,
811
+ inputSchema: inputSchema17,
739
812
  annotations: { readOnlyHint: true },
740
813
  handler: async (args, ctx) => {
741
814
  return await httpGet(
@@ -764,6 +837,7 @@ var allTools = [
764
837
  getRankRadarDataTool,
765
838
  createRankRadarTool,
766
839
  createNicheDiveTool,
840
+ rediveNicheTool,
767
841
  getDiveStatusTool,
768
842
  listSellerProfilesTool,
769
843
  getSellerCatalogTool,