@nooticr/mcp 1.26.52 → 1.26.53

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.
@@ -353,7 +353,7 @@ export function registerAmazonTools(server, makeClient) {
353
353
  "the category is wrong. " +
354
354
  "Use for a category or a competitive set; for one listing, get_amazon_product is cheaper.",
355
355
  annotations: {
356
- readOnlyHint: true,
356
+ readOnlyHint: false,
357
357
  destructiveHint: false,
358
358
  idempotentHint: false,
359
359
  openWorldHint: true,
@@ -423,7 +423,7 @@ export function registerBrandWatch(server, makeClient) {
423
423
  "never widened. A run that turns up nothing new — or, for a competitor watch, nothing above " +
424
424
  "median — sends no mail. cadence is hourly, every_6_hours, every_12_hours, daily or weekly, " +
425
425
  "and defaults to daily. No cost to call.",
426
- annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
426
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
427
427
  inputSchema: z
428
428
  .object({
429
429
  kind: z
@@ -643,7 +643,7 @@ export function registerBrandWatch(server, makeClient) {
643
643
  "names any in platformsSkipped, tell the user those networks are no longer searched and " +
644
644
  "offer to remove a term or recreate the watch with a larger budget. A change the budget " +
645
645
  "cannot cover at all is refused and nothing changes. No cost to call: no credits are spent.",
646
- annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
646
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
647
647
  inputSchema: z
648
648
  .object({
649
649
  watchId: z.string().describe("The portfolio watch's id, from list_brand_watches."),
@@ -26,6 +26,8 @@ export const SERVER_INSTRUCTIONS = [
26
26
  "Prices are nooticr credits per fetch and every paid tool states its price in its description. Free: " +
27
27
  "nooticr_getting_started, check_nooticr_credits, list_social_connections, watch_creator, unwatch_creator " +
28
28
  "and every show_* view, which only draws what you pass it.",
29
+ "Before a paid call, explain its stated cost and get the user's consent; follow any tool's built-in " +
30
+ "confirmation flow before proceeding.",
29
31
  "Not sure where to start? Call nooticr_getting_started: it is free, reads this account's state, and names " +
30
32
  "the next calls worth making with their prices. Good first calls: get_social_media on a post URL " +
31
33
  "(1 credit), discover_social_posts on a niche (2), analyze_comments on a post (2).",
@@ -362,38 +362,19 @@ export function prepareItem(item, seenIds) {
362
362
  };
363
363
  }
364
364
  /** How to actually file it, named per destination so the model does not guess. */
365
- function nextStepFor(destination, count) {
365
+ function nextStepFor(_destination, count) {
366
366
  const n = `${count} item${count === 1 ? "" : "s"}`;
367
- switch (destination) {
368
- case "github":
369
- return (`Search the repository's issues for each \`searchFirst\` string first — an exact match ` +
370
- `means it is already filed and you should comment on that issue instead of opening a ` +
371
- `second one. For the rest, call the GitHub server's issue-creation tool with \`title\`, ` +
372
- `\`body\` and \`labels\` exactly as given. Do not rewrite the body: the quote is fenced ` +
373
- `and framed deliberately. ${n} prepared.`);
374
- case "jira":
375
- return (`Search the project for each \`searchFirst\` string first, then create an issue per item ` +
376
- `with \`title\` as the summary and \`body\` as the description. Jira renders its own ` +
377
- `markup — if the project is not markdown-enabled the fence may show literally, which is ` +
378
- `acceptable and better than an unfenced quote. Map \`labels\` to Jira labels. ${n} prepared.`);
379
- case "linear":
380
- return (`Search the team's issues for each \`searchFirst\` string first, then create an issue per ` +
381
- `item with \`title\` and \`body\` as given, and \`labels\` as Linear labels (create any ` +
382
- `that do not exist rather than dropping them). ${n} prepared.`);
383
- default:
384
- return (`Each item carries the exact \`title\`, \`body\` and \`labels\` to file, and a ` +
385
- `\`searchFirst\` string to look for first so the same report does not land twice. Pass ` +
386
- `them to whichever tracker tool this host has connected, unmodified. ${n} prepared.`);
387
- }
367
+ return (`Each item includes a title, body, labels and a search phrase for duplicate checking. ` +
368
+ `Review the prepared text, then copy it into your chosen issue tracker. No issue is created ` +
369
+ `by this tool. ${n} prepared.`);
388
370
  }
389
371
  export function registerHandoff(server) {
390
372
  server.registerTool("prepare_handoff", {
391
373
  title: "Prepare Handoff",
392
374
  description: "Turn items you classified — a bug report in a comment, a complaint said out loud in a " +
393
- "video, a feature request under a competitor's post — into the exact text to file in " +
394
- "GitHub, Jira or Linear through whichever tracker server this host also has connected. " +
395
- "This server files nothing itself and holds no tracker credential; it returns the " +
396
- "strings and you make the call. Free, and makes no requests. " +
375
+ "video, a feature request under a competitor's post — into structured, issue-ready text. " +
376
+ "This server files nothing; review the result and copy it to your chosen issue tracker. " +
377
+ "Free, and makes no requests. " +
397
378
  "Use it after analyze_comments, search_mentions, answer_my_audience or " +
398
379
  "search_spoken_mentions, passing the ids those tools issued. For each item you get a " +
399
380
  "title, a ready body with the quote fenced and framed as third-party evidence rather " +
@@ -837,7 +837,7 @@ export function registerJobTools(server, makeClient, store) {
837
837
  "you follow; analyze_creator_profile is the full teardown of one you do not.",
838
838
  annotations: {
839
839
  readOnlyHint: false,
840
- destructiveHint: false,
840
+ destructiveHint: true,
841
841
  // Moves the "last checked" marker for a watched creator, so the second
842
842
  // call in a row does not answer the same question as the first.
843
843
  idempotentHint: false,
@@ -257,7 +257,7 @@ export function registerMarketplaceTools(server, makeClient) {
257
257
  "For Amazon specifically, scan_amazon_category returns the same shape plus Amazon's own " +
258
258
  "review-aspect counts.",
259
259
  annotations: {
260
- readOnlyHint: true,
260
+ readOnlyHint: false,
261
261
  destructiveHint: false,
262
262
  idempotentHint: false,
263
263
  openWorldHint: true,
@@ -155,7 +155,7 @@ export function registerOwnAccountTools(server, makeClient) {
155
155
  "appId (optional when your workspace has only one product); every other field is " +
156
156
  "snake_case, the same names create_product takes and for the same reason — the backend " +
157
157
  "reads them by exact key. Free — no AI call, just a row.",
158
- annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
158
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
159
159
  inputSchema: z
160
160
  .object({
161
161
  appId: z
@@ -416,7 +416,7 @@ export function registerOwnAccountTools(server, makeClient) {
416
416
  // jobId and state: "pending", nothing to draw yet. analyze_product_status,
417
417
  // which returns the finished playbook, is where the view belongs — see
418
418
  // scripts/host-contract.py's NO_APP entry for this tool.
419
- annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
419
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
420
420
  inputSchema: z
421
421
  .object({
422
422
  appId: z
@@ -571,7 +571,7 @@ export function registerOwnAccountTools(server, makeClient) {
571
571
  "get_content_plan) but does not schedule or publish any post. Billed like the dashboard's " +
572
572
  "own Content Plan button: your workspace's plan AI credits, not your personal MCP credits.",
573
573
  _meta: viewMeta("generate_content_plan"),
574
- annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
574
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false },
575
575
  inputSchema: z
576
576
  .object({
577
577
  appId: z
@@ -30,7 +30,7 @@ import { registerCollabTools } from "./collab.js";
30
30
  import { registerAmazonTools } from "./amazon.js";
31
31
  import { registerMarketplaceTools } from "./marketplace.js";
32
32
  /** Current MCP server version — bumped on every deploy for traceability. */
33
- export const MCP_SERVER_VERSION = "1.26.52";
33
+ export const MCP_SERVER_VERSION = "1.26.53";
34
34
  /** MCP Apps extension identifier */
35
35
  const UI_EXTENSION = "io.modelcontextprotocol/ui";
36
36
  /** MIME type for MCP Apps HTML resources */
@@ -104,7 +104,9 @@ function appsSdkContents(uri, media, links, tool = "") {
104
104
  _meta: {
105
105
  "openai/widgetPrefersBorder": false,
106
106
  "openai/widgetCSP": {
107
- connect_domains: media,
107
+ // The widget communicates through the host bridge and needs no direct
108
+ // network connections. Remote origins are limited to rendered resources.
109
+ connect_domains: [],
108
110
  resource_domains: media,
109
111
  redirect_domains: links,
110
112
  },
@@ -852,7 +854,7 @@ export function createMcpServer(rawMakeClient, opts) {
852
854
  // Thumbnails and video come from our own origin and the platform CDNs.
853
855
  // Without these the widget loads and then paints nothing at all.
854
856
  "openai/widgetCSP": {
855
- connect_domains: domains,
857
+ connect_domains: [],
856
858
  resource_domains: domains,
857
859
  redirect_domains: PLATFORM_LINK_DOMAINS,
858
860
  },
@@ -564,7 +564,7 @@ export function registerWatchlist(server, makeClient, store) {
564
564
  "snapshot forward — so this answers 'what is new' rather than 'what exists'. The first run " +
565
565
  "for a creator has nothing to compare against and just records the baseline. " +
566
566
  "Consumes 2 nooticr credits per creator checked.",
567
- annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
567
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
568
568
  inputSchema: z
569
569
  .object({
570
570
  limit: z.number().int().optional().describe("Posts to check per creator (default 6)."),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nooticr/mcp",
3
3
  "mcpName": "com.nooticr/mcp",
4
- "version": "1.26.52",
4
+ "version": "1.26.53",
5
5
  "description": "MCP server for nooticr - fetch, discover and understand TikTok/Instagram/YouTube/X/Reddit/LinkedIn/Weibo posts with AI (media metadata, niche discovery, brand monitoring, hook & viral analysis)",
6
6
  "homepage": "https://mcp.nooticr.com",
7
7
  "repository": {