@nooticr/mcp 1.26.31 → 1.26.33
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 +2 -2
- package/dist/shared/evidence-digest.js +14 -1
- package/dist/shared/evidence.js +4 -4
- package/dist/shared/jobs.js +55 -0
- package/dist/shared/loading-plans.js +2 -2
- package/dist/shared/output-schemas.js +2 -2
- package/dist/shared/tools-def.js +3 -3
- package/dist/shared/tools.js +17 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -80,9 +80,9 @@ them caps that fan-out with an argument.
|
|
|
80
80
|
| `understand_social_post` | 3 | The same two fetches, asked for a description of what physically happens on screen rather than why it works. Use when you need the events, not the strategy. |
|
|
81
81
|
| `analyze_comments` | 2 | The comment section, every comment with a stable id, and the taxonomy to label them with — sentiment, and whether each is praise, a complaint, a bug report, a question, a request, a comparison or spam. The same `get_post_comments` call, at the same price as reading them directly. |
|
|
82
82
|
| `show_comment_review` | free | Draws the classifications your model produced — every comment with its sentiment and category, filterable and selectable. Makes no requests; it only renders what you pass it. |
|
|
83
|
-
| `
|
|
83
|
+
| `show_post_analysis` | free | Draws the analysis your model wrote from `analyze_post`/`analyze_post_fast`/`understand_social_post` — hook strength, script structure, quotable lines, suggested hashtags and more, whichever fields you produced. Makes no requests; it only renders what you pass it. |
|
|
84
84
|
| `compare_posts` | 1 | The first of two to five posts, fetched with its stats, and the comparison left to you. Fetch the rest with `get_social_media` at 1 credit each. Use when performance differs and you need to know why. |
|
|
85
|
-
| `
|
|
85
|
+
| `show_compared_posts` | free | Draws the comparison your model wrote from `compare_posts` — each post scored, the winner marked, what differed and the next test worth running. Makes no requests; it only renders what you pass it. |
|
|
86
86
|
|
|
87
87
|
### Research a niche or a creator
|
|
88
88
|
|
|
@@ -94,7 +94,20 @@ function postLine(row) {
|
|
|
94
94
|
.join(" · ");
|
|
95
95
|
const text = clamp(str(row.caption) || str(row.title) || str(row.text));
|
|
96
96
|
const url = str(row.externalUrl) || str(row.url);
|
|
97
|
-
|
|
97
|
+
// Replies under the post, when something opened it. Nested one level down,
|
|
98
|
+
// which is exactly where #59 could come back without the chain-map gate
|
|
99
|
+
// noticing: `posts` is rendered, so the check is satisfied while the thing
|
|
100
|
+
// that was paid for — the comment that says "same here, this is my problem"
|
|
101
|
+
// — stays in the payload only.
|
|
102
|
+
const replies = Array.isArray(row.commentSample) ? row.commentSample : [];
|
|
103
|
+
const shown = replies.slice(0, 4).map((c) => ` - ${clamp(commentLine(c), 240)}`);
|
|
104
|
+
if (replies.length > shown.length) {
|
|
105
|
+
shown.push(` - (${replies.length - shown.length} more under this post)`);
|
|
106
|
+
}
|
|
107
|
+
const readNothing = row.commentsRead === 0 ? " - (this thread would not open — not that nobody replied)" : "";
|
|
108
|
+
return [head && `[${head}]`, text, url, ...shown, readNothing]
|
|
109
|
+
.filter(Boolean)
|
|
110
|
+
.join("\n ");
|
|
98
111
|
}
|
|
99
112
|
/**
|
|
100
113
|
* One comment, with its id.
|
package/dist/shared/evidence.js
CHANGED
|
@@ -204,7 +204,7 @@ export const EVIDENCE_PLANS = {
|
|
|
204
204
|
"what moved while it was there, so do not describe motion you have not",
|
|
205
205
|
"seen across two frames.",
|
|
206
206
|
"",
|
|
207
|
-
"When you are done, call
|
|
207
|
+
"When you are done, call show_post_analysis with the url and your analysis —",
|
|
208
208
|
"it draws what you found (hook strength, script structure, quotable",
|
|
209
209
|
"lines, suggested hashtags, target audience and whichever other fields",
|
|
210
210
|
"you produced) so it is visible, not only said in chat.",
|
|
@@ -239,7 +239,7 @@ export const EVIDENCE_PLANS = {
|
|
|
239
239
|
"not what moved during it, so describe stills unless two frames actually",
|
|
240
240
|
"show the change.",
|
|
241
241
|
"",
|
|
242
|
-
"When you are done, call
|
|
242
|
+
"When you are done, call show_post_analysis with the url and your analysis —",
|
|
243
243
|
"it draws what you found so it is visible, not only said in chat.",
|
|
244
244
|
ownIt,
|
|
245
245
|
].join("\n");
|
|
@@ -259,7 +259,7 @@ export const EVIDENCE_PLANS = {
|
|
|
259
259
|
"yourself and look at the frames — do not ask anyone else to fetch",
|
|
260
260
|
"them for you.",
|
|
261
261
|
"",
|
|
262
|
-
"When you are done, call
|
|
262
|
+
"When you are done, call show_post_analysis with the url and your analysis —",
|
|
263
263
|
"it draws what you found so it is visible, not only said in chat.",
|
|
264
264
|
ownIt,
|
|
265
265
|
].join("\n"),
|
|
@@ -274,7 +274,7 @@ export const EVIDENCE_PLANS = {
|
|
|
274
274
|
"which performed better, what actually differed, and the single test",
|
|
275
275
|
"worth running next. Ground every difference in a number or a quote.",
|
|
276
276
|
"",
|
|
277
|
-
"When you are done, call
|
|
277
|
+
"When you are done, call show_compared_posts with all the posts (same shape",
|
|
278
278
|
"get_social_media returned for each) and your comparison — it draws a",
|
|
279
279
|
"scoreboard with the winner marked, so the comparison is visible, not",
|
|
280
280
|
"only said in chat.",
|
package/dist/shared/jobs.js
CHANGED
|
@@ -2112,6 +2112,15 @@ export function registerJobTools(server, makeClient, store) {
|
|
|
2112
2112
|
.optional()
|
|
2113
2113
|
.describe("Where to look (default reddit). Each one is a separate paid search."),
|
|
2114
2114
|
limit: z.number().int().optional().describe("Posts per query shape (default 6, max 15)."),
|
|
2115
|
+
readComments: z
|
|
2116
|
+
.boolean()
|
|
2117
|
+
.optional()
|
|
2118
|
+
.describe("Open the most promising results and read their comments too (default false). " +
|
|
2119
|
+
"On Reddit especially, the person with the problem is at least as often replying " +
|
|
2120
|
+
"under someone else's thread as posting their own, and a post-only search cannot " +
|
|
2121
|
+
"see any of them. Costs 2 nooticr credits per post opened, up to 5 — and they are " +
|
|
2122
|
+
"opened on the MERGED, deduped results, so it is five extra calls in total rather " +
|
|
2123
|
+
"than five per query shape per platform."),
|
|
2115
2124
|
queries: z
|
|
2116
2125
|
.array(z.string())
|
|
2117
2126
|
.optional()
|
|
@@ -2181,6 +2190,41 @@ export function registerJobTools(server, makeClient, store) {
|
|
|
2181
2190
|
}
|
|
2182
2191
|
}
|
|
2183
2192
|
}
|
|
2193
|
+
// Read the comments under the most promising results, on the MERGED,
|
|
2194
|
+
// deduped list rather than per search.
|
|
2195
|
+
//
|
|
2196
|
+
// That distinction is the whole reason this lives here and not in the
|
|
2197
|
+
// backend's own `includeComments`: three query shapes across two
|
|
2198
|
+
// platforms is six searches, and opening five posts under each would be
|
|
2199
|
+
// thirty paid calls for a tool whose description promises a wide CHEAP
|
|
2200
|
+
// net. On the merged list it is five, once.
|
|
2201
|
+
//
|
|
2202
|
+
// Why at all: on Reddit the person with the problem is at least as often
|
|
2203
|
+
// replying under someone else's thread as posting their own, and a
|
|
2204
|
+
// post-only search cannot see any of them (Nooticr/nooticr-server#63).
|
|
2205
|
+
if (args.readComments && posts.length) {
|
|
2206
|
+
const OPEN = 5;
|
|
2207
|
+
for (const post of posts.slice(0, OPEN)) {
|
|
2208
|
+
const url = String(post.externalUrl ?? post.url ?? "");
|
|
2209
|
+
if (!url)
|
|
2210
|
+
continue;
|
|
2211
|
+
try {
|
|
2212
|
+
const res = await client.callTool("get_post_comments", { url, limit: 8 });
|
|
2213
|
+
const structured = (res.structured ?? {});
|
|
2214
|
+
spend.record("get_post_comments", structured);
|
|
2215
|
+
const comments = Array.isArray(structured.comments) ? structured.comments : [];
|
|
2216
|
+
post.commentsRead = comments.length;
|
|
2217
|
+
post.commentSample = comments;
|
|
2218
|
+
}
|
|
2219
|
+
catch {
|
|
2220
|
+
// A thread that will not open is not a failed sweep — the post's
|
|
2221
|
+
// own text may carry the complaint, and this is the cheap net.
|
|
2222
|
+
// Stated rather than left absent, so a reader can tell "no
|
|
2223
|
+
// comments" from "not looked at".
|
|
2224
|
+
post.commentsRead = 0;
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2184
2228
|
if (!posts.length) {
|
|
2185
2229
|
return evidence([
|
|
2186
2230
|
`Nothing came back for "${problem}" on ${platforms.join(", ")}.`,
|
|
@@ -2223,6 +2267,17 @@ export function registerJobTools(server, makeClient, store) {
|
|
|
2223
2267
|
"and say how many you rejected and why — a shortlist with no reject count reads as if " +
|
|
2224
2268
|
"the search was precise.",
|
|
2225
2269
|
"",
|
|
2270
|
+
args.readComments
|
|
2271
|
+
? "The first few posts carry `commentSample`: the replies underneath them. Judge those " +
|
|
2272
|
+
"the same way — a person saying \"same here, this is exactly my problem\" under " +
|
|
2273
|
+
"someone else's thread is a better find than the thread itself, and the permalink " +
|
|
2274
|
+
"to quote is the post's. `commentsRead: 0` means the thread would not open, not " +
|
|
2275
|
+
"that nobody replied."
|
|
2276
|
+
: "Only the posts themselves were searched. On Reddit the person with the problem is " +
|
|
2277
|
+
"at least as often replying under someone else's thread as posting their own — if " +
|
|
2278
|
+
"these results look thin, call again with `readComments: true` to open the top few " +
|
|
2279
|
+
"and read what is underneath.",
|
|
2280
|
+
"",
|
|
2226
2281
|
args.queries?.length
|
|
2227
2282
|
? "`foundBy` says which of your own phrasings surfaced each post, in the order you " +
|
|
2228
2283
|
"gave them."
|
|
@@ -320,8 +320,8 @@ export const LOADING_PLANS = {
|
|
|
320
320
|
// The show_* family renders the model's own output. A wait here is brief
|
|
321
321
|
// and free, but it still says which, because "nothing is happening" and
|
|
322
322
|
// "this is free and instant" look identical on a blank screen.
|
|
323
|
-
|
|
324
|
-
|
|
323
|
+
show_post_analysis: { label: "Drawing the reading", kind: "text", n: 1, steps: [], free: true },
|
|
324
|
+
show_compared_posts: { label: "Drawing the comparison", kind: "strip", n: 2, steps: [], free: true },
|
|
325
325
|
show_hooks: { label: "Laying out the hooks", kind: "list", n: 5, steps: [], free: true },
|
|
326
326
|
show_variants: { label: "Laying out the variants", kind: "list", n: 4, steps: [], free: true },
|
|
327
327
|
show_repurposed_post: { label: "Laying out the rewrites", kind: "text", n: 1, steps: [], free: true },
|
|
@@ -418,7 +418,7 @@ export const OUTPUT_SCHEMAS = {
|
|
|
418
418
|
// thinking" (README) — but until these existed, the thinking had nowhere
|
|
419
419
|
// to land except chat text. Free, and make no requests, same as
|
|
420
420
|
// show_comment_review: they only draw what they're handed.
|
|
421
|
-
|
|
421
|
+
show_compared_posts: open({
|
|
422
422
|
posts: listOf(post).describe("The 2-5 posts being compared, same shape as compare_posts returned."),
|
|
423
423
|
comparison: open({
|
|
424
424
|
winner: scalar().describe("1-indexed position of the post that won, matching the posts array."),
|
|
@@ -429,7 +429,7 @@ export const OUTPUT_SCHEMAS = {
|
|
|
429
429
|
}).nullish(),
|
|
430
430
|
mcpCredits,
|
|
431
431
|
}),
|
|
432
|
-
|
|
432
|
+
show_post_analysis: open({
|
|
433
433
|
url: scalar(),
|
|
434
434
|
post: post.nullish().describe("The post analyze_post/analyze_post_fast/understand_social_post handed back."),
|
|
435
435
|
analysis: open({}).passthrough().nullish().describe("Your own analysis, any of the fields analyze_post's guidance asked for — summary, " +
|
package/dist/shared/tools-def.js
CHANGED
|
@@ -157,13 +157,13 @@ export const TOOL_DEFINITIONS = [
|
|
|
157
157
|
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(),
|
|
158
158
|
},
|
|
159
159
|
{
|
|
160
|
-
name: "
|
|
160
|
+
name: "show_compared_posts",
|
|
161
161
|
title: "Show Comparison",
|
|
162
162
|
description: "Display a comparison you wrote after compare_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.",
|
|
163
163
|
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(),
|
|
164
164
|
},
|
|
165
165
|
{
|
|
166
|
-
name: "
|
|
166
|
+
name: "show_post_analysis",
|
|
167
167
|
title: "Show Analysis",
|
|
168
168
|
description: "Display an analysis you wrote after analyze_post, analyze_post_fast or understand_social_post handed you the material. Free, and makes no requests — it only draws what you pass it: hook strength, script structure, quotable lines, hashtags, target audience, viral triggers and more, whichever of these you actually produced. Call this after you have done the analysing, not instead of it.",
|
|
169
169
|
inputSchema: z.object({ url: z.string(), post: z.object({}).passthrough().optional(), analysis: z.object({}).passthrough() }).strict(),
|
|
@@ -394,7 +394,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
394
394
|
name: "find_people_with_problem",
|
|
395
395
|
title: "Find People With A Problem",
|
|
396
396
|
description: "Find people describing a problem in their own words — prospects, early users, anyone whose complaint your product answers. Say the problem the way a person would say it (\"I spend hours checking competitors by hand\") and this searches for posts shaped like that complaint, not for the topic it is about. That difference is the point: searching the TOPIC finds marketing about it, which is what discover_social_posts is for. Widens the query into the forms a complaint takes — the plain phrasing, the does-anyone-else question, the is-there-a-tool ask — and merges what each returns. It is a wide cheap net and NOT a filter: the posts come back for you to judge, and many will be off-target. Consumes 2 nooticr credits per platform searched. Defaults to reddit, where people describe workflow pain in sentences; add twitter for volume.",
|
|
397
|
-
inputSchema: z.object({ problem: z.string().describe("The problem in a person's own words, not a topic. \"I waste an hour a day checking what competitors posted\" finds people; \"competitor analysis\" finds marketing about competitor analysis."), platforms: z.array(z.enum(["reddit", "twitter", "youtube", "tiktok", "instagram", "linkedin"])).optional().describe("Where to look (default reddit). Each one is a separate paid search."), limit: z.number().int().optional().describe("Posts per query shape (default 6, max 15)."), queries: z.array(z.string()).optional().describe("Search these exact phrasings instead of the ones derived from `problem` (max 4). You are better at this than a string template is: write how a person would actually word the complaint on the network being searched \u2014 a Reddit title, an X post \u2014 and keep each one short, because this is a keyword search and a long sentence matches on its commonest words.") }).strict(),
|
|
397
|
+
inputSchema: z.object({ problem: z.string().describe("The problem in a person's own words, not a topic. \"I waste an hour a day checking what competitors posted\" finds people; \"competitor analysis\" finds marketing about competitor analysis."), platforms: z.array(z.enum(["reddit", "twitter", "youtube", "tiktok", "instagram", "linkedin"])).optional().describe("Where to look (default reddit). Each one is a separate paid search."), limit: z.number().int().optional().describe("Posts per query shape (default 6, max 15)."), readComments: z.boolean().optional().describe("Open the most promising results and read their comments too (default false). On Reddit especially, the person with the problem is at least as often replying under someone else's thread as posting their own, and a post-only search cannot see any of them. Costs 2 nooticr credits per post opened, up to 5 \u2014 and they are opened on the MERGED, deduped results, so it is five extra calls in total rather than five per query shape per platform."), queries: z.array(z.string()).optional().describe("Search these exact phrasings instead of the ones derived from `problem` (max 4). You are better at this than a string template is: write how a person would actually word the complaint on the network being searched \u2014 a Reddit title, an X post \u2014 and keep each one short, because this is a keyword search and a long sentence matches on its commonest words.") }).strict(),
|
|
398
398
|
},
|
|
399
399
|
{
|
|
400
400
|
name: "search_spoken_mentions",
|
package/dist/shared/tools.js
CHANGED
|
@@ -26,7 +26,7 @@ import { loadingPlansJson } from "./loading-plans.js";
|
|
|
26
26
|
import { registerHandoff } from "./handoff.js";
|
|
27
27
|
import { registerCollabTools } from "./collab.js";
|
|
28
28
|
/** Current MCP server version — bumped on every deploy for traceability. */
|
|
29
|
-
export const MCP_SERVER_VERSION = "1.26.
|
|
29
|
+
export const MCP_SERVER_VERSION = "1.26.33";
|
|
30
30
|
/** MCP Apps extension identifier */
|
|
31
31
|
const UI_EXTENSION = "io.modelcontextprotocol/ui";
|
|
32
32
|
/** MIME type for MCP Apps HTML resources */
|
|
@@ -407,9 +407,9 @@ async function runEvidence(tool, args, client) {
|
|
|
407
407
|
//
|
|
408
408
|
// Measured before changing it, over 59 real runs of the quest suite: 0
|
|
409
409
|
// guidance phrases across 175 tool results. `analyze_post` handed back frames,
|
|
410
|
-
// a transcript and 2,000 characters ending in "call
|
|
410
|
+
// a transcript and 2,000 characters ending in "call show_post_analysis when you are
|
|
411
411
|
// done"; the model wrote the analysis and delivered it in chat, and
|
|
412
|
-
//
|
|
412
|
+
// show_post_analysis was called in 1 run of 12.
|
|
413
413
|
//
|
|
414
414
|
// The text block stays for hosts that honour it (and for the images, which
|
|
415
415
|
// must sit in `content`). `guidance` on the payload is what reaches the rest.
|
|
@@ -561,8 +561,8 @@ export function createMcpServer(rawMakeClient, opts) {
|
|
|
561
561
|
// Close the loop the evidence-only tools open: your own analysis/hooks/
|
|
562
562
|
// variants/repurposing/comparison, drawn — same shape as
|
|
563
563
|
// show_comment_review, free and no requests.
|
|
564
|
-
"
|
|
565
|
-
"
|
|
564
|
+
"show_compared_posts",
|
|
565
|
+
"show_post_analysis",
|
|
566
566
|
"show_hooks",
|
|
567
567
|
"show_variants",
|
|
568
568
|
"show_repurposed_post",
|
|
@@ -1426,8 +1426,8 @@ export function createMcpServer(rawMakeClient, opts) {
|
|
|
1426
1426
|
// the plain post card it started on. Same shape as show_comment_review in
|
|
1427
1427
|
// every way that matters: free, no requests, draws only what it is
|
|
1428
1428
|
// handed. Each one's structuredContent is built to match an existing view
|
|
1429
|
-
// ui-template.ts already renders (
|
|
1430
|
-
// scoreboard,
|
|
1429
|
+
// ui-template.ts already renders (show_compared_posts → the comparison
|
|
1430
|
+
// scoreboard, show_post_analysis → analysisCard) or a new one added alongside
|
|
1431
1431
|
// it (show_hooks, show_variants, show_repurposed_post).
|
|
1432
1432
|
server.registerTool("show_trend", {
|
|
1433
1433
|
title: "Show Trend",
|
|
@@ -1547,7 +1547,7 @@ export function createMcpServer(rawMakeClient, opts) {
|
|
|
1547
1547
|
},
|
|
1548
1548
|
};
|
|
1549
1549
|
});
|
|
1550
|
-
server.registerTool("
|
|
1550
|
+
server.registerTool("show_compared_posts", {
|
|
1551
1551
|
title: "Show Comparison",
|
|
1552
1552
|
description: "Display a comparison you wrote after compare_posts fetched the first post and you fetched " +
|
|
1553
1553
|
"the rest yourself (get_social_media, 1 credit each). Free, and makes no requests — it only " +
|
|
@@ -1555,12 +1555,12 @@ export function createMcpServer(rawMakeClient, opts) {
|
|
|
1555
1555
|
"strengths and the next experiment worth running. Call this after you have done the " +
|
|
1556
1556
|
"comparing, not instead of it.",
|
|
1557
1557
|
_meta: {
|
|
1558
|
-
ui: { resourceUri: uiResource("
|
|
1559
|
-
"ui/resourceUri": uiResource("
|
|
1560
|
-
"openai/outputTemplate": appsSdkResource("
|
|
1558
|
+
ui: { resourceUri: uiResource("show_compared_posts") },
|
|
1559
|
+
"ui/resourceUri": uiResource("show_compared_posts"),
|
|
1560
|
+
"openai/outputTemplate": appsSdkResource("show_compared_posts"),
|
|
1561
1561
|
},
|
|
1562
1562
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
1563
|
-
outputSchema: OUTPUT_SCHEMAS.
|
|
1563
|
+
outputSchema: OUTPUT_SCHEMAS.show_compared_posts,
|
|
1564
1564
|
inputSchema: z
|
|
1565
1565
|
.object({
|
|
1566
1566
|
posts: z
|
|
@@ -1600,7 +1600,7 @@ export function createMcpServer(rawMakeClient, opts) {
|
|
|
1600
1600
|
},
|
|
1601
1601
|
};
|
|
1602
1602
|
});
|
|
1603
|
-
server.registerTool("
|
|
1603
|
+
server.registerTool("show_post_analysis", {
|
|
1604
1604
|
title: "Show Analysis",
|
|
1605
1605
|
description: "Display an analysis you wrote after analyze_post, analyze_post_fast or understand_social_post " +
|
|
1606
1606
|
"handed you the material. Free, and makes no requests — it only draws what you pass it: hook " +
|
|
@@ -1608,12 +1608,12 @@ export function createMcpServer(rawMakeClient, opts) {
|
|
|
1608
1608
|
"more, whichever of these you actually produced. Call this after you have done the analysing, " +
|
|
1609
1609
|
"not instead of it.",
|
|
1610
1610
|
_meta: {
|
|
1611
|
-
ui: { resourceUri: uiResource("
|
|
1612
|
-
"ui/resourceUri": uiResource("
|
|
1613
|
-
"openai/outputTemplate": appsSdkResource("
|
|
1611
|
+
ui: { resourceUri: uiResource("show_post_analysis") },
|
|
1612
|
+
"ui/resourceUri": uiResource("show_post_analysis"),
|
|
1613
|
+
"openai/outputTemplate": appsSdkResource("show_post_analysis"),
|
|
1614
1614
|
},
|
|
1615
1615
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
1616
|
-
outputSchema: OUTPUT_SCHEMAS.
|
|
1616
|
+
outputSchema: OUTPUT_SCHEMAS.show_post_analysis,
|
|
1617
1617
|
inputSchema: z
|
|
1618
1618
|
.object({
|
|
1619
1619
|
url: z.string().describe("The post you analyzed."),
|
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.
|
|
4
|
+
"version": "1.26.33",
|
|
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": {
|