@nooticr/mcp 1.26.54 → 1.26.56
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 +18 -16
- package/dist/shared/amazon.js +1 -1
- package/dist/shared/comment-review.js +2 -2
- package/dist/shared/evidence-digest.js +1 -1
- package/dist/shared/evidence.js +7 -7
- package/dist/shared/getting-started.js +2 -2
- package/dist/shared/handoff.js +2 -2
- package/dist/shared/hashtags.js +1 -1
- package/dist/shared/jobs.js +3 -3
- package/dist/shared/loading-plans.js +12 -10
- package/dist/shared/output-schemas.js +8 -8
- package/dist/shared/own-account.js +1 -1
- package/dist/shared/prompts.js +7 -7
- package/dist/shared/settings.js +69 -0
- package/dist/shared/tasks.js +1 -1
- package/dist/shared/tools-def.js +26 -14
- package/dist/shared/tools.js +217 -76
- package/dist/shared/ui-template.js +26 -26
- package/package.json +1 -1
package/dist/shared/tools-def.js
CHANGED
|
@@ -33,7 +33,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
33
33
|
{
|
|
34
34
|
name: "get_post_comments",
|
|
35
35
|
title: "Get Post Comments",
|
|
36
|
-
description: "Fetch top comments for a post URL on TikTok, Instagram, YouTube, Reddit, Douyin, X, Weibo, Bilibili or LinkedIn (plus keyword clusters from TikTok Analytics when available) — audience sentiment/audience-signal analysis. (20 free credits for new users). Use when you want to read what people actually wrote; use
|
|
36
|
+
description: "Fetch top comments for a post URL on TikTok, Instagram, YouTube, Reddit, Douyin, X, Weibo, Bilibili or LinkedIn (plus keyword clusters from TikTok Analytics when available) — audience sentiment/audience-signal analysis. (20 free credits for new users). Use when you want to read what people actually wrote; use summarize_post_comments when you want it synthesised into what to do next. Consumes 2 nooticr credits.",
|
|
37
37
|
inputSchema: z.object({ url: z.string().describe("Full public post URL (TikTok/Instagram/YouTube/X/Reddit/Douyin/Weibo/Bilibili/LinkedIn). Not searchable here: xiaohongshu — it publishes no comment endpoint."), limit: z.number().int().optional().describe("Max comments (default 20).") }).strict(),
|
|
38
38
|
},
|
|
39
39
|
{
|
|
@@ -79,13 +79,13 @@ export const TOOL_DEFINITIONS = [
|
|
|
79
79
|
inputSchema: z.object({ url: z.string().describe("Post URL (TikTok or YouTube)."), language: z.string().optional().describe("Preferred language code, e.g. 'en'."), format: z.enum(["text", "srt", "vtt"]).optional().describe("Also return a caption file ('srt' or 'vtt'). Default 'text'.") }).strict(),
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
|
-
name: "
|
|
82
|
+
name: "summarize_post_comments",
|
|
83
83
|
title: "Summarize Post Comments",
|
|
84
84
|
description: "A post's comment section, fetched and laid out for you to classify: every comment with a stable id, plus whatever themes the platform clustered them into. Label each one's sentiment and what it is doing — praise, complaint, bug report, question, request, comparison, spam — then summarise the themes, the questions worth answering, the objections, and what to make next. The result names the exact labels, and show_comment_review draws them for free afterwards. Use when the goal is 'what should I make next' rather than 'what did people write'. Costs 2 nooticr credits, for the one get_post_comments call it makes.",
|
|
85
85
|
inputSchema: z.object({ url: z.string().describe("Full public post URL."), limit: z.number().int().optional().describe("Comments to read (default 50, max 100)."), verbatim: z.boolean().optional().describe("Render every comment whole in the text you read (default false).") }).strict(),
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
|
-
name: "
|
|
88
|
+
name: "compare_social_posts",
|
|
89
89
|
title: "Compare Social Post Performance",
|
|
90
90
|
description: "The first of 2-5 posts you want compared, fetched with its stats — and the comparison left to you. Call get_social_media on each remaining URL yourself (1 credit each), and get_post_transcript where the wording matters, then say which won, what actually differed (hook, format, length, caption, hashtags), what they share worth keeping, and the one experiment that would test your explanation. Use for 'why did this one work and that one not'. Costs 1 nooticr credit for this call, plus 1 per further post you fetch.",
|
|
91
91
|
inputSchema: z.object({ urls: z.array(z.string()).describe("2-5 post URLs to compare.") }).strict(),
|
|
@@ -103,25 +103,25 @@ export const TOOL_DEFINITIONS = [
|
|
|
103
103
|
inputSchema: z.object({ url: z.string().describe("Full public post URL.") }).strict(),
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
|
-
name: "
|
|
106
|
+
name: "generate_hook_ideas",
|
|
107
107
|
title: "Generate Hooks from a Post",
|
|
108
108
|
description: "The source post, its transcript and its stats, so you can write the opening lines yourself — the first line said or shown on screen. Name the device each hook uses and who it stops; one that could open any video in the niche is not grounded in this one. Use when you know the subject and need openings to choose between. With a url it fetches get_social_media and get_post_transcript for 2 nooticr credits; with only a topic there is nothing to fetch and it costs nothing.",
|
|
109
109
|
inputSchema: z.object({ url: z.string().optional().describe("Post to riff on (optional if topic given)."), topic: z.string().optional().describe("Subject to write hooks about (optional if url given)."), count: z.number().int().optional().describe("How many hooks (default 10, max 20)."), tone: z.string().optional().describe("Optional tone, e.g. 'blunt', 'contrarian'.") }).strict(),
|
|
110
110
|
},
|
|
111
111
|
{
|
|
112
|
-
name: "
|
|
112
|
+
name: "generate_post_variants",
|
|
113
113
|
title: "Generate Post Variants",
|
|
114
114
|
description: "The post that worked, with its transcript and stats, so you can propose what to film next — same underlying mechanism, different execution. For each variant give the hook, the one angle that changes, the shot beats in order and the CTA, and say what made the original work. Use after reading a post to move from 'why it worked' to 'what to make'. Fans out to get_social_media and get_post_transcript: 2 nooticr credits, 1 each.",
|
|
115
115
|
inputSchema: z.object({ url: z.string().describe("The post to make variants of."), count: z.number().int().optional().describe("How many variants (default 3, max 6)."), angle: z.string().optional().describe("Optional steer, e.g. 'for a beginner audience'.") }).strict(),
|
|
116
116
|
},
|
|
117
117
|
{
|
|
118
|
-
name: "
|
|
118
|
+
name: "evaluate_social_draft",
|
|
119
119
|
title: "Score a Social Media Draft",
|
|
120
120
|
description: "Score your own draft BEFORE you film or post it. Returns the draft with the rubric to hold it to — hook, clarity, payoff, specificity and fit, each scored 1-10 — and asks you for the three fixes that would move it most, one rewritten opening line and a tightened version. The only tool that runs before the content exists. Use before filming, while changing it is still cheap. Free: it fetches nothing, so it costs no credits.",
|
|
121
121
|
inputSchema: z.object({ draft: z.string().describe("Your script, caption or hook."), platform: z.string().optional().describe("Target platform (default tiktok).") }).strict(),
|
|
122
122
|
},
|
|
123
123
|
{
|
|
124
|
-
name: "
|
|
124
|
+
name: "adapt_post_for_platform",
|
|
125
125
|
title: "Adapt a Post for Another Platform",
|
|
126
126
|
description: "The source post, its transcript and its stats, for you to rewrite for other surfaces — X thread, LinkedIn post, carousel slides, YouTube title/description, newsletter — keeping the argument and changing the shape to suit how each is read. The same paragraph with different line breaks is not a repurposing. Use when a post already worked and you want it on other surfaces. Fans out to get_social_media and get_post_transcript: 2 nooticr credits, 1 each.",
|
|
127
127
|
inputSchema: z.object({ url: z.string().describe("The post to repurpose."), targets: z.array(z.string()).optional().describe("Which formats to produce (default all).") }).strict(),
|
|
@@ -165,13 +165,13 @@ export const TOOL_DEFINITIONS = [
|
|
|
165
165
|
{
|
|
166
166
|
name: "show_comment_review",
|
|
167
167
|
title: "Show Comment Review",
|
|
168
|
-
description: "Display comment classifications you produced from
|
|
168
|
+
description: "Display comment classifications you produced from summarize_post_comments. Free, and makes no requests — it only draws what you pass it. Renders each comment with its sentiment and category so a person can sort and act on them. Call this after you have classified the comments, not instead of classifying them.",
|
|
169
169
|
inputSchema: z.object({ url: z.string().describe("The post the comments came from."), summary: z.string().optional(), title: z.string().optional(), comments: z.array(z.object({ id: z.string(), text: z.string(), author: z.string().optional(), likes: z.number().optional(), sentiment: z.string().optional(), category: z.string().optional(), note: z.string().optional() })), themes: z.array(z.string()).optional(), nextSteps: z.array(z.string()).optional() }).strict(),
|
|
170
170
|
},
|
|
171
171
|
{
|
|
172
172
|
name: "show_compared_posts",
|
|
173
173
|
title: "Show Comparison",
|
|
174
|
-
description: "Display a comparison you wrote after
|
|
174
|
+
description: "Display a comparison you wrote after compare_social_posts fetched the first post and you fetched the rest yourself. Free, and makes no requests — it only draws what you pass it: each post with a BEST badge on the winner, what differed, shared strengths and the next experiment worth running. Call this after you have done the comparing, not instead of it.",
|
|
175
175
|
inputSchema: z.object({ posts: z.array(z.object({}).passthrough()).min(2).max(5), winner: z.number().int(), winnerReason: z.string().optional(), differences: z.array(z.object({ factor: z.string(), detail: z.string() })).optional(), lessons: z.array(z.string()).optional(), nextTest: z.string().optional() }).strict(),
|
|
176
176
|
},
|
|
177
177
|
{
|
|
@@ -183,19 +183,19 @@ export const TOOL_DEFINITIONS = [
|
|
|
183
183
|
{
|
|
184
184
|
name: "show_hooks",
|
|
185
185
|
title: "Show Hooks",
|
|
186
|
-
description: "Display the alternative opening hooks you wrote after
|
|
186
|
+
description: "Display the alternative opening hooks you wrote after generate_hook_ideas handed you a post's material (or just a topic). Free, and makes no requests — it only draws what you pass it: each hook with the device it uses and who it stops. Call this after you have written the hooks, not instead of writing them.",
|
|
187
187
|
inputSchema: z.object({ url: z.string().optional(), topic: z.string().optional(), hooks: z.array(z.object({ hook: z.string(), mechanism: z.string().optional(), why: z.string().optional() })).min(1) }).strict(),
|
|
188
188
|
},
|
|
189
189
|
{
|
|
190
190
|
name: "show_variants",
|
|
191
191
|
title: "Show Variants",
|
|
192
|
-
description: "Display the post variants you wrote after
|
|
192
|
+
description: "Display the post variants you wrote after generate_post_variants handed you the original post's material. Free, and makes no requests — it only draws what you pass it: each variant's hook, the angle that changes, its shot beats and its call to action. Call this after you have written the variants, not instead of writing them.",
|
|
193
193
|
inputSchema: z.object({ sourceUrl: z.string(), post: z.object({}).passthrough().optional(), variants: z.array(z.object({ title: z.string(), hook: z.string(), angle: z.string().optional(), beats: z.array(z.string()).optional(), cta: z.string().optional(), whyItCouldWork: z.string().optional() })).min(1) }).strict(),
|
|
194
194
|
},
|
|
195
195
|
{
|
|
196
196
|
name: "show_repurposed_post",
|
|
197
197
|
title: "Show Repurposed Post",
|
|
198
|
-
description: "Display the rewritten copy you produced after
|
|
198
|
+
description: "Display the rewritten copy you produced after adapt_post_for_platform handed you the source post's material. Free, and makes no requests — it only draws what you pass it: one entry per surface you rewrote it for. Call this after you have done the rewriting, not instead of it.",
|
|
199
199
|
inputSchema: z.object({ sourceUrl: z.string(), versions: z.array(z.object({ surface: z.string(), content: z.string() })).min(1) }).strict(),
|
|
200
200
|
},
|
|
201
201
|
{
|
|
@@ -337,7 +337,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
337
337
|
inputSchema: z.object({ appId: z.number().int().optional().describe("Your product's id. Omit only with a single-app workspace."), limit: z.number().int().optional().describe("Max videos (default 20, capped at 50).") }).strict(),
|
|
338
338
|
},
|
|
339
339
|
{
|
|
340
|
-
name: "
|
|
340
|
+
name: "get_google_analytics_data",
|
|
341
341
|
title: "Read Google Analytics Data",
|
|
342
342
|
description: "Your own product's Google Analytics (GA4) sync, as of its last sync into nooticr — not a live GA4 call: the property, the date range synced and how many daily rows came in. Connect GA4 in API Connections first. No cost to call.",
|
|
343
343
|
inputSchema: z.object({ appId: z.number().int().optional().describe("Your product's id. Omit only with a single-app workspace.") }).strict(),
|
|
@@ -447,7 +447,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
447
447
|
{
|
|
448
448
|
name: "why_did_this_underperform",
|
|
449
449
|
title: "Why Did This Underperform",
|
|
450
|
-
description: "One post measured against the creator's own recent median rather than against another post. Fetches the post and that creator's recent window, takes the post back out of its own baseline, and returns where it actually sits in the distribution \u2014 median, quartiles, ratio and percentile \u2014 so the answer can be 'this is an ordinary result, not a failure'. Use when you have one post and nothing to compare it with;
|
|
450
|
+
description: "One post measured against the creator's own recent median rather than against another post. Fetches the post and that creator's recent window, takes the post back out of its own baseline, and returns where it actually sits in the distribution \u2014 median, quartiles, ratio and percentile \u2014 so the answer can be 'this is an ordinary result, not a failure'. Use when you have one post and nothing to compare it with; compare_social_posts is for two URLs you already picked. Consumes 3 nooticr credits.",
|
|
451
451
|
inputSchema: z.object({ url: z.string().describe("The post to explain."), username: z.string().optional().describe("Whose baseline to use, when the post does not name its creator."), platform: z.string().optional().describe("Platform of the creator's feed."), window: z.number().int().optional().describe("Posts in the comparison window (default 12, max 30)."), metric: z.enum(["views", "likes", "comments", "shares", "engagementRate"]).optional().describe("Which stat to compare (default views).") }).strict(),
|
|
452
452
|
},
|
|
453
453
|
{
|
|
@@ -528,4 +528,16 @@ export const TOOL_DEFINITIONS = [
|
|
|
528
528
|
description: "Display the category read you produced from scan_marketplace_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. Pass the scanId: the listings are then re-read from the scan itself (free) rather than taken from you, and any ASIN you cite that the scan does not contain is flagged. Without a scanId, listings you pass are drawn marked as not checked against a scan. Free. Your read is 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.",
|
|
529
529
|
inputSchema: z.object({ marketplace: z.string().describe("The site the scan ran on, e.g. lazada."), 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(),
|
|
530
530
|
},
|
|
531
|
+
{
|
|
532
|
+
name: "nooticr_settings_read",
|
|
533
|
+
title: "Read Nooticr Settings",
|
|
534
|
+
description: "Read the current default social platform and result count for this Nooticr account. Free; no credits are used.",
|
|
535
|
+
inputSchema: z.object({}).strict(),
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
name: "nooticr_settings_update",
|
|
539
|
+
title: "Update Nooticr Settings",
|
|
540
|
+
description: "Save changed default social platform or result count preferences for this Nooticr account. Free; no credits are used.",
|
|
541
|
+
inputSchema: z.object({ set: z.object({ defaultSocialPlatform: z.enum(["tiktok", "instagram", "youtube", "twitter", "reddit", "douyin", "xiaohongshu", "weibo", "bilibili"]).optional(), defaultResultCount: z.number().int().min(3).max(12).optional() }).strict() }).strict(),
|
|
542
|
+
},
|
|
531
543
|
];
|