@nooticr/mcp 1.26.33 → 1.26.34

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.
@@ -414,4 +414,28 @@ export const TOOL_DEFINITIONS = [
414
414
  description: "Patch your own product's fields \u2014 omitted arguments leave their column unchanged, so this cannot blank a field by not mentioning it. Takes appId, optional when your workspace has exactly one product; every other field is snake_case, the same names create_product takes and read the same way. The result lists which fields were actually written, so a name you spelled wrong shows up as a field that did not change rather than as a silent no-op. Free \u2014 no AI call, just a row.",
415
415
  inputSchema: z.object({ appId: z.number().int().optional().describe("Your product's id. Omit only with a single-product workspace."), name: z.string().optional(), slug: z.string().optional(), description: z.string().optional(), website_url: z.string().optional(), niche: z.string().optional(), product_type: z.string().optional(), icon_url: z.string().optional(), primary_cta_label: z.string().optional(), primary_cta_url: z.string().optional(), external_listing_id: z.string().optional(), ios_bundle_id: z.string().optional(), android_package: z.string().optional() }).strict(),
416
416
  },
417
+ {
418
+ name: "scan_amazon_category",
419
+ title: "Scan Amazon Category",
420
+ description: "Collect an Amazon category and read it: listings with prices, star histograms, Amazon's own review-aspect counts and the review text itself, plus the arithmetic over them (price spread, rating spread, which aspects recur across how many brands, and the share of each listing's ratings sitting at 1-2 stars). Pass query to search the category, asins to pin named competitors, or both \u2014 named competitors keep their place at the front. You write the read: purchase drivers, barriers, what the incumbents do well, the gaps, and how a new entrant could position; show_amazon_category_insights draws it for free afterwards. Collection runs in the background, so this returns everything ready within waitSeconds plus a scanId to continue with amazon_scan_status. Consumes 3 nooticr credits per listing collected \u2014 a listing with reviews is a real browser render behind Amazon's bot defences.",
421
+ inputSchema: z.object({ query: z.string().optional().describe("Category or keyword to search on Amazon, e.g. 'ashwagandha gummies'."), asins: z.array(z.string()).optional().describe("Named competitors: ASINs or any Amazon product URL. Kept at the front of the set."), limit: z.number().int().optional().describe("Listings to collect (default 10, max 50)."), reviews: z.boolean().optional().describe("Collect review text too (default true)."), domain: z.string().optional().describe("Marketplace host, e.g. www.amazon.co.uk (default www.amazon.com)."), waitSeconds: z.number().int().optional().describe("How long to wait before returning partial results (default 90, max 240)."), focus: z.string().optional().describe("An extra question to answer from the reviews.") }).strict(),
422
+ },
423
+ {
424
+ name: "amazon_scan_status",
425
+ title: "Amazon Scan Status",
426
+ description: "Pick up a scan_amazon_category collection that was still running, by scanId \u2014 the listings and reviews collected since, with the same rollup and the same instructions for reading them. Free: it is the poll scan_amazon_category asked for, and charging for the second half of one answer would bill a wait this server chose. Call it when a scan came back incomplete, then write your read from the full set.",
427
+ inputSchema: z.object({ scanId: z.string().describe("The scanId scan_amazon_category returned."), waitSeconds: z.number().int().optional().describe("How long to wait for more listings before answering (default 30, max 240)."), focus: z.string().optional().describe("Same optional steer as scan_amazon_category.") }).strict(),
428
+ },
429
+ {
430
+ name: "get_amazon_product",
431
+ title: "Get Amazon Product",
432
+ description: "Fetch one Amazon listing by ASIN or URL: price, rating, the full star histogram, features, specs, Amazon's review digest and aspect breakdown, and the review text. Use for a single product; for a category or a competitive set, scan_amazon_category collects many in one job and rolls them up. Consumes 3 nooticr credits.",
433
+ inputSchema: z.object({ asin: z.string().optional().describe("ASIN, or a full Amazon product URL."), url: z.string().optional().describe("Full Amazon product URL, if you have that instead."), reviews: z.boolean().optional().describe("Collect review text too (default true)."), domain: z.string().optional().describe("Marketplace host (default www.amazon.com).") }).strict(),
434
+ },
435
+ {
436
+ name: "show_amazon_category_insights",
437
+ title: "Show Amazon Category Insights",
438
+ description: "Display the category read you produced from scan_amazon_category: purchase drivers, barriers, what each brand does well, the gaps, and the positioning angles \u2014 drawn beside the listings and their reviews, so a person can click a product and check any claim against the text it came from. Free, and makes no requests: it only draws what you pass it, attributed to you rather than presented as a nooticr rating of anyone's product. Call this after you have read the reviews, not instead of reading them.",
439
+ inputSchema: z.object({ category: z.string().describe("The category this is a read of."), summary: z.string().optional(), drivers: z.array(z.any()).optional().describe("What makes someone buy, each with the review evidence behind it."), barriers: z.array(z.any()).optional().describe("What stops them buying, or makes them return it."), strengths: z.array(z.any()).optional().describe("What each incumbent does well."), gaps: z.array(z.any()).optional().describe("What buyers keep asking for that nobody serves."), positioning: z.array(z.any()).optional().describe("Angles a new entrant could take."), products: z.array(z.any()).optional().describe("The listings from the scan, passed straight through."), rollup: z.record(z.unknown()).optional().describe("The rollup from the scan, passed straight through."), scanId: z.string().optional() }).passthrough(),
440
+ },
417
441
  ];
@@ -25,8 +25,9 @@ import { registerConnectionTools } from "./connections.js";
25
25
  import { loadingPlansJson } from "./loading-plans.js";
26
26
  import { registerHandoff } from "./handoff.js";
27
27
  import { registerCollabTools } from "./collab.js";
28
+ import { registerAmazonTools } from "./amazon.js";
28
29
  /** Current MCP server version — bumped on every deploy for traceability. */
29
- export const MCP_SERVER_VERSION = "1.26.33";
30
+ export const MCP_SERVER_VERSION = "1.26.34";
30
31
  /** MCP Apps extension identifier */
31
32
  const UI_EXTENSION = "io.modelcontextprotocol/ui";
32
33
  /** MIME type for MCP Apps HTML resources */
@@ -627,6 +628,12 @@ export function createMcpServer(rawMakeClient, opts) {
627
628
  // grant each connection carries is a table, which is what a view is for.
628
629
  "list_social_connections",
629
630
  "connect_social_account",
631
+ // Marketplace. All four draw: the three collection tools render the
632
+ // listings and their reviews, and the view draws the read on top of them.
633
+ "scan_amazon_category",
634
+ "amazon_scan_status",
635
+ "get_amazon_product",
636
+ "show_amazon_category_insights",
630
637
  ];
631
638
  // Human-readable resource name per tool (used in resources/list + tools/list).
632
639
  function resourceName(tool) {
@@ -706,6 +713,12 @@ export function createMcpServer(rawMakeClient, opts) {
706
713
  // LinkedIn
707
714
  "https://*.licdn.com",
708
715
  "https://*.linkedin.com",
716
+ // Amazon product images. Listings serve from m.media-amazon.com and, on
717
+ // older listings, images-na.ssl-images-amazon.com — a listing whose picture
718
+ // is blocked draws as a brand initial, which is a worse comparison screen
719
+ // than the one the scan paid for.
720
+ "https://*.media-amazon.com",
721
+ "https://*.ssl-images-amazon.com",
709
722
  ];
710
723
  const apiUrl = process.env.NOOTICR_API_URL || process.env.NOOTICR_BASE_URL;
711
724
  if (apiUrl && apiUrl.trim()) {
@@ -2351,5 +2364,9 @@ export function createMcpServer(rawMakeClient, opts) {
2351
2364
  // classified for a tracker on another server, the other draws what it scored.
2352
2365
  registerHandoff(server);
2353
2366
  registerCollabTools(server);
2367
+ // Marketplace intelligence (amazon.ts): the category collection, the poll
2368
+ // that picks it back up, a single listing, and the free view for the read
2369
+ // the model writes out of them.
2370
+ registerAmazonTools(server, makeClient);
2354
2371
  return server;
2355
2372
  }