New:Microsoft Teams Notifications Are Now Available in Socket.Learn more →
Get Started

@nooticr/mcp

Package Overview
Dependencies
Maintainers
1
Versions
33
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@nooticr/mcp

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)

latest
Source
npmnpm
Version
1.26.51
Version published
Weekly downloads
1.6K
168.6%
Maintainers
1
Weekly downloads
 
Created
Source

@nooticr/mcp

MCP (Model Context Protocol) server for nooticr.

Gives an AI assistant three things: it can read real social posts across ten networks (TikTok, Instagram, YouTube, X, Reddit, LinkedIn, Douyin, Xiaohongshu, Weibo, Bilibili), understand them — transcript, video frames, comments, the numbers — and make something from what it learned: hooks, variants to film, a scored draft, a repurposed thread.

The understanding is your model's, not ours. Every tool here fetches material and hands it over with an account of what to do with it; none of them ask a model of ours for an opinion first. You pay for the fetch and nothing else.

It also monitors a name: search_mentions sweeps nine of those networks for every comment that says your brand, inside a date window you choose, and search_spoken_mentions reads the words actually said out loud in TikTok, YouTube and Douyin videos for the mentions that were never typed anywhere.

Runs over stdio locally or as a hosted connector at https://mcp.nooticr.com/mcp. Billed against your nooticr credits; new accounts get 20 free.

Claude Code — register the marketplace, then install the plugin:

/plugin marketplace add Nooticr/nooticr-mcp
/plugin install nooticr@nooticr

Claude Code / CLI without the plugin:

claude mcp add nooticr --user -- npx -y @nooticr/mcp
npx @nooticr/mcp login   # one-time sign-in (Google)

Cursor / any stdio MCP client (claude_desktop_config.json, .mcp.json, …):

{
  "mcpServers": {
    "nooticr": {
      "command": "npx",
      "args": ["-y", "@nooticr/mcp"],
      "env": { "NOOTICR_BASE_URL": "https://api.nooticr.com" }
    }
  }
}

Tools

88 tools, grouped by what you are trying to do. Prices are in nooticr credits and match what the server actually charges.

The job tools under Answer a question you actually have are not endpoint wrappers. Each names a job, fans out over the calls that job needs, groups the evidence by whatever you are deciding about, gives every item an id a follow-up tool can act on, and hands the reading to your model rather than to ours. They fan out, so they cost the sum of what they fetched and every one of them caps that fan-out with an argument.

Read a post

ToolCreditsWhat it is for
get_social_media1The post's facts and media — contentType, title, caption, author, stats, direct media URLs, plus an inline thumbnail. Use when you want the post itself and nothing interpreted.
get_post_transcript1The words actually spoken. Where the platform publishes a caption track (TikTok, Douyin, YouTube) it is read as-is — exact rather than inferred, and far cheaper than watching the video; everywhere else the post's own audio is transcribed, which needs speech-to-text configured on the server. format: "srt" or "vtt" also returns a ready caption file built from the track's own timing, at no extra cost. Use before any analysis when the wording matters.
get_post_frames2Frames sampled evenly across a post's video, returned as images you can actually look at — not a description of them. ffmpeg opens the stream directly rather than downloading it, so HLS works and an expired link is re-resolved on the spot. Verified live at 3/3 on TikTok, YouTube, Instagram, Douyin and X; Reddit works on video posts. A carousel or slideshow returns its own images unchanged. Each frame costs roughly 1,200 tokens of your context.
get_post_comments2Top comments plus the themes the platform clusters them into, with which ones the creator pinned or liked. Use when you want to read what people wrote.

Understand a post

ToolCreditsWhat it is for
analyze_post_fast2The post's transcript, caption and stats — everything but the pictures, which is what makes it the cheap read. Two fetches: get_social_media (1) and get_post_transcript (1). The sensible default.
analyze_post3Frames sampled across the video, as images your model can actually look at, plus the transcript. Two fetches: get_post_frames (2) and get_post_transcript (1). Use when the visuals are the point — framing, editing, on-screen text.
understand_social_post3The 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.
analyze_comments2The 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. Pass verbatim: true to have every item rendered whole for quoting rather than clipped to fit; same price.
show_comment_reviewfreeDraws 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.
show_post_analysisfreeDraws 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.
compare_posts1The 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.
show_compared_postsfreeDraws 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.

Research a niche or a creator

ToolCreditsWhat it is for
discover_social_posts2Recent posts for a niche across nine networks, with inline thumbnails and limit/offset pagination. Use to find posts to look at.
get_user_posts2One creator's recent posts with stats. Use to scan an account.
search_creators2People by what they make — designers, developers, photographers, anyone with an audience — found by craft, niche or keyword. Use when you know the kind of person but not their names. Searches TikTok, Instagram and Xiaohongshu; not YouTube, Douyin, X, Reddit or LinkedIn, which cannot be creator-searched upstream.
get_similar_creators2Lookalikes for a creator that already works.
suggest_creator_identity2 per network searched, plus 2 to find the handle (6 by default)The same person on the other networks, from one handle you already know — with the evidence for each: a link published in both bios, one bio naming the other account, an identical handle, a matching display name. Suggests, never merges: nothing is stored, a human confirms, and two accounts' follower counts are never added together. TikTok, Instagram and Xiaohongshu.
discover_sounds2Trending audio with playable previews. Sound is a major ranking signal on TikTok.
discover_hashtags2What to tag with. TikTok comes from the Creative Center trend board — volumes plus rising/cooling/steady. The other eight searchable networks have no trend board upstream, so tags are counted across a live sweep of a niche you name: real and current, but a single sample, so no rising/cooling signal. source says which you got. LinkedIn cannot be swept.
find_hook_pattern2A creator's recent posts, so their opening lines can be read as a set and turned into fill-in-the-blank templates. One get_user_posts call.
search_mentions2 per network (5 for Xiaohongshu)Brand monitoring. Every comment that names a term, across nine networks at once, grouped under the post it was left on. A brand is named far more often in the replies than in a caption, so the comment is the unit — not the post. Takes a since date to read a past window, and pages with offset/pageSize so a nine-network sweep does not arrive all at once. Does not read speech inside a video — search_spoken_mentions does, on TikTok, YouTube and Douyin.
watch_creatorfreeAdd a creator to your watchlist. Stores the handle only — nothing is fetched.
unwatch_creatorfreeDrop a creator from the watchlist.
list_watchlistfreeWho you are watching: handle, platform, note, and when you last caught up on each.
catch_up_watchlist2 per creatorWhat everyone you watch has posted since your last catch-up. Compares against the snapshot taken last time and moves it forward, so it answers "what is new" rather than "what exists".
create_brand_watchfree to callSchedule a recurring sweep and get emailed only what is new. kind: "mentions" (default) is a recurring search_mentions sweep for term/platforms; kind: "competitor" is a recurring get_user_posts check on one creator (handle/platform), mailing only what beats their own recent median; kind: "report" runs job: {tool, args} — niche_report (mailed as written every run) or discover_social_posts (only unseen posts) — on the schedule; kind: "portfolio" sweeps up to 25 terms (your brand, products, competitors) across the same networks under one budget and mails one digest with each term's share of voice. Two calls by design: the first returns the quote (cost per run, cadence, cost per day) and a confirmationToken; nothing is created or charged until you call it again with confirm: true and that token. Each run then bills the same as calling the matching tool yourself — 2 credits per network (5 for Xiaohongshu) for mentions, a flat 2 credits for competitor, the job tool's own price for a report (3 for niche_report), and a mentions sweep per term for a portfolio — whose budget is split evenly and trims networks, never terms, and which refunds any term whose sweep fails.
list_brand_watchesfreeEvery watch you have scheduled: term, networks, cadence, cost per run, credits spent so far, runs made, and when the next one is due.
mention_trendfreeWhat a watch has seen over time, which nothing else here answers — every other read is about now. One point per run: when it ran, how many mentions it found, how many were new, and both counts per network, so "which network is growing" and "did it go quiet or did we stop looking" come apart. On a competitor watch each point carries the median that run measured, which turns "they beat their own median" into "and that median has doubled". Plus the mentions more than one run has seen. Free because the sweeps were billed when they ran; charging again to read what was already paid for is the thing it fixes.
update_watch_portfoliofreeAdd or remove a portfolio watch's terms by watchId. No new confirmation, because the per-run budget you agreed to does not move — more terms split it more ways, and the reply names any network a run no longer reaches.
stop_brand_watchfreeStop a watch by watchId or term. Immediate — the next run does not happen and nothing more is charged.
niche_report2Recent posts in a niche with their stats, so the dominant formats, hook patterns and the gaps nobody fills can be read off them. One discover_social_posts call. Use when deciding what to make.
analyze_creator_profile2A creator's recent posts with their stats — the material of a teardown: niche, themes, hook formula, what over- and underperforms, who the audience is. One get_user_posts call.

Answer a question you actually have

ToolCreditsWhat it is for
answer_my_audience2 + 2 per post opened (14 by default)The mirror of search_mentions. The questions waiting under your own posts: recent posts fetched, comments read on each, grouped under the post they were left on, every comment with a stable id, and the ones that read like questions or requests flagged and sorted to the top. It finds and drafts — it cannot post a reply: nooticr does not post comments on any network, even where a connection's grant allows managing them. limit caps how many posts are opened, which is the price.
prepare_handofffreeThe hand-off to your tracker. Turns items you classified — a bug report in a comment, a complaint said out loud in a video — into the exact title, body and labels to file through whichever GitHub, Jira or Linear MCP server the host also has connected. nooticr files nothing and holds no tracker credential. The body carries the quote fenced and framed as a third-party report rather than as instructions, because the issue is read next by a coding agent; contact details are redacted, @handles and #numbers are defanged so filing notifies nobody by accident, and a searchFirst string dedupes a second sweep against the first. Makes no requests.
show_audience_repliesfreeLays your drafts out for a person to work through, grouped under the post, each with what you decided to do about it. Sends nothing; fetches nothing.
show_standingsfreeDraws the standings your model read out of compare_creators or watchlist_standings — one row per creator, with the window and the median it was scored against. ranking records which axis you ordered on, and tooThin draws a creator with too short a window as unranked rather than last: missing from a comparison is not the same as losing it. Makes no requests.
show_trendfreeDraws the trend your model read out of mention_trend. tooShort marks a series with too few points to call a direction, and edgeIsRecordStart marks a left edge that is where the record begins rather than where the conversation did — a chart hiding either is the mistake this view could otherwise make on your behalf. Makes no requests.
track_creator2What a creator shipped, and which of it beat their own median rather than a raw view count that mostly measures follower count. One post list, whatever the window. If they are on your watchlist it also marks what is new since your last check and moves that marker forward — its own marker, not the one catch_up_watchlist keeps.
compare_creators2 per creator (4-10)Two to five creators side by side on the one axis that compares: each post's ratio to that creator's own median. Per creator you get the window that was scored, their median, the share of it that beat that median, how hard they beat it when they did, every ratio, and their best and worst post. It does not rank them — "how often they land one" and "how big it is when they do" usually disagree, and a hit rate over a short window is one post either way, so the window travels with every number and the read is yours.
watchlist_standings2 per watched creatorThe same, across everyone on your watchlist: "who moved" in one call instead of one per creator. Reading the watchlist is free; the fetches are not, so it confirms the total before spending. catch_up_watchlist answers what is new; this answers how it did.
who_should_i_work_with2, or 4 with a seedA collaboration shortlist: a keyword search merged with the lookalikes of a creator who already fits, marked by which search found each one. Every candidate also carries the links pulled out of their bio, typed and sorted by how much opening one will tell you — a repository to read the code in, their own site, a link hub that holds the real links — so vetting is reading the work rather than re-reading the follower count. Those links are never fetched here: they came out of a field the person being evaluated controls, so the host opens them, and the result says so. It does not measure audience overlap — that costs about nine credits a candidate, so the result says so and shows how to check a finalist rather than faking the signal.
find_people_with_problem6 per platformFind 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 and it searches for posts shaped like that complaint rather than for the topic it is about: 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 marks which one surfaced each post. A wide cheap net and not a filter: the posts come back for you to judge, and plenty will be off-target. Defaults to reddit, where people describe workflow pain in sentences. Each platform is searched once per query shape — three by default, at 2 credits a search. Not searchable here: linkedin, which has no keyword post search upstream. Pass verbatim: true to have every item rendered whole for quoting rather than clipped to fit; same price.
show_collab_shortlistfreeDraws the candidates you scored, ranked, and asks the user which to approach. The scores are attributed to your model, not presented as a nooticr rating, and a candidate scored without anything having been opened is marked unverified. Makes no requests.
why_did_this_underperform3One post against the creator's own recent distribution, with the post taken back out of its own baseline. Returns median, quartiles, ratio and percentile, so the answer can be "this is an ordinary result, not a failure". Different question from compare_posts, which weighs two URLs you already picked.
what_should_i_make_next2 + 2 per post read + 2 (12 by default)Demand against supply: what your commenters explicitly ask for, set beside what a niche sweep shows is already being made. A gap nobody asked for is noise; a request nobody serves is the opportunity. Falls back to your most-used hashtag when you name no niche.
detect_spoken_mentions2Every brand named out loud in one video. The spoken transcript and the written caption, side by side, for your model to list each brand with its verbatim sentence, the creator's framing and whether it was said, written or both. Works where the creator never enabled captions, because the audio is transcribed. 1 credit for get_post_transcript plus 1 for get_social_media; nothing when no transcript can be made.
search_spoken_mentions2 per platform narrowed by niche + 2 per creator handle + 1 per transcript, up to maxTranscriptsThe mirror of search_mentions, for what was said rather than typed. Narrows to candidate posts (a niche sweep, named handles, and/or your watchlist), transcribes only the most-viewed survivors up to a hard ceiling, and searches the words for the term — TikTok, YouTube and Douyin, and only where the creator actually enabled captions. Reports how many candidates were found, transcribed and matched, so the spend is legible.

Study a market on Amazon

Everything above reads social content. These read a marketplace — the place where the same audience says what it actually bought and why it sent it back. The question they exist for is a category decision: we are considering ashwagandha — what makes people buy, what stops them, what are the incumbents good at, and where is the gap? Every one of those answers lives in review text, so the unit of work is a scan of the category rather than a lookup of a product.

Collection is genuinely slow, and honestly so: each listing is a real browser render behind Amazon's bot defences, and the pace between them is set by what Amazon tolerates rather than by what the machine can do. Ten listings with their reviews is minutes, not seconds — so a scan returns what is ready and hands back a scanId for the rest.

ToolCreditsWhat it is for
scan_amazon_category3 per listing collected (30 by default)The category, collected: 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, read from the histogram rather than from the handful of reviews a scrape returns. Pass query to search the category, asins to pin the competitors a customer named, or both; named competitors keep their place at the front. Because the price is set by an argument, it confirms the total before spending it.
amazon_scan_statusfreePicks a running collection back up by scanId — the listings collected since, with the same rollup. Free: it is the poll scan_amazon_category asked for, and billing the second half of one answer would charge for a wait the server chose.
get_amazon_product3One listing by ASIN or URL: price, rating, the full star histogram, features, specs, Amazon's review digest and aspect breakdown, and the reviews.
scan_marketplace_category3 per product collected (30 by default)The same category read on eleven more sites — AliExpress, Cdiscount, Flipkart, Mercado Libre, Lazada, Otto, Rakuten, Trendyol, Jumia, Vinted and Temu. Vinted is resale rather than retail, so its rating describes the seller and the scan says so in ratingScope — do not read it as a product's reviews. marketplace picks the site; market picks the storefront for the sites that have several, and the argument names the real set per site so a model cannot send Otto a Lazada region. Same rollup, same confirmation before spending.
marketplace_scan_statusfreePicks a running marketplace collection back up by scanId and the same marketplace. Free, for the same reason amazon_scan_status is.
get_marketplace_product3One product from any of the twelve sites, by id or URL: price, rating, the full star histogram, specs and the reviews.
show_amazon_category_insightsfreeDraws the read your model wrote — purchase drivers, barriers, what each brand does well, the gaps, the positioning angles — beside the listings and their reviews, so a person can click a product and check any claim against the text it came from. The conclusions are attributed to your model, never presented as a nooticr rating of anyone's product. Given the scanId, it re-reads the listings from the scan itself (free) instead of drawing whatever the model re-sends, and flags any ASIN the read cites that the scan does not contain; without one, the card says its listings were not checked.
show_marketplace_category_insightsfreeThe same card for the other eleven marketplaces: your read beside that site's listings and reviews, labelled with the right site, re-read from the scan by scanId and marketplace so nothing is re-typed.

Make something

ToolCreditsWhat it is for
write_hooks2, or freeThe source post and its transcript, to write openings against. Give a topic instead of a url and it fetches nothing and costs nothing.
show_hooksfreeDraws the hooks your model wrote from write_hooks — each one with the device it uses and who it stops. Makes no requests; it only renders what you pass it.
score_draftfreeYour draft back with the rubric to hold it to — hook, clarity, payoff, specificity and fit, each scored 1-10, plus the three fixes worth making and a rewritten opening. Fetches nothing: the text is already yours. The only tool that runs before the content exists.
repurpose_post2The source post and its transcript, to rewrite for other surfaces — X thread, LinkedIn post, carousel slides, YouTube metadata, newsletter.
show_repurposed_postfreeDraws the rewritten copy your model produced from repurpose_post — one entry per surface. Makes no requests; it only renders what you pass it.
create_variants2The post that worked, with its transcript, to build variants from: hook, the angle that changes, ordered shot beats and a CTA.
show_variantsfreeDraws the variants your model wrote from create_variants — each one's hook, angle, beats and CTA. Makes no requests; it only renders what you pass it.

Account

ToolCreditsWhat it is for
nooticr_getting_startedfreeStart here. Where this account stands — balance, connected accounts, watchlist — and the next calls worth making, each with its price and an example. The server's instructions point every host at it.
check_nooticr_creditsfreeBalance and billing URL.
list_tool_runsfreeYour tool-call history: what ran, whether it worked, and the credits each call actually took (0 for a free, refunded, cached or replayed call). scope: "workspace" shows every member's runs to owners and admins.
get_tool_runfreeOne run from that history by id, with its full error.
get_usage_reportfreeThe run ledger added up over a window: total calls, failures and credits actually taken, per tool, per day and the most recent failures. scope: "workspace" adds one row per seat, for the workspace's owners and admins.
nooticr_loginfreeRe-link the account when a call fails with an authentication error.
list_social_connectionsfreeWhat you have connected and what each connection is actually allowed to do — read the account, publish a post, manage comments — as yes, no or unknown. "Manage comments" reports the platform's grant; no nooticr tool posts or replies to a comment. Unknown means the grant predates scope recording: treat it as "try it", not as a refusal. Also says which platforms can be linked at all, which is a smaller set than the networks nooticr reads.
connect_social_accountfreeA link the user opens to connect one account. They approve at the provider in their own browser; nothing is connected until they do, and no credential passes through the tool or the model's context. Each call mints a fresh link — an old one does not work twice.
create_productfreeCreate a product in your own workspace — the row every other own-account tool needs before it has anything to work with. Always creates in the calling session's workspace, never one you could name. name and slug are required; every other field is snake_case and read by exact key, so a camelCase websiteUrl lands nowhere. Writes no brand playbook.
update_productfreePatch a product's fields. An omitted argument leaves its column unchanged, so this cannot blank a field by not mentioning it, and the result lists what was actually written — a misspelled field shows up as one that did not change rather than as a silent no-op.

Your own product

Everything above reads someone else's content. These read and generate for your own — a different product, a different balance (your workspace's plan AI credits, not the personal MCP credits above), billed exactly like the matching dashboard button.

ToolCreditsWhat it is for
list_own_appsfreeEvery product in your workspace — call this first when you have more than one and another tool below asks for appId.
create_productfreeCreate a new product in your workspace — name/slug required, plus optional description, website_url, niche, product_type and store-listing fields (snake_case — see note below). Takes no workspace id; always creates in your own. Does not generate a brand playbook — call analyze_product for that.
update_productfreePatch a product's fields — omitted arguments leave their column unchanged. Same snake_case field names as create_product.
get_scheduled_postsfreeYour own scheduled and draft posts in the content pipeline — title, status, scheduled time, approval status. What is queued to publish.
get_post_performancefreeYour own already-published posts with their engagement counters — views, likes, comments, shares, platform, post date. The raw performance history, not an interpretation of it; pair with growth_brief for that.
get_video_statsfreeYour own most recently synced video performance stats across every connected creator — views, likes, comments, shares, plus a running total. Reads the last sync; does not trigger a new one.
get_google_analyticsfreeYour product's GA4 sync as of its last sync into nooticr, not live — property, date range, rows synced. The metrics feed get_post_performance and growth_brief.
get_search_console_datafreeSearch Console clicks, impressions and top queries, as of the last sync — whether people search for what your content is about.
get_posthog_analyticsfreeYour PostHog pageview trend, as of the last sync — line a post's date up against traffic to your site.
get_content_planfreeThe saved weekly content plan for a product, if one has been generated. plan: null when none has.
get_brand_playbookfreeYour product's brand playbook — name, description and the playbook text — if one has been configured, in the dashboard or by analyze_product. Read-only; available: false when none exists.
review_postfreeScore a draft before you publish it — hook strength, an A/B hook comparison, aesthetic and storytelling notes, rewritten hooks/captions. Never billed, same as the dashboard's own pre-publish review.
draft_postplan AI creditsA ready-to-use draft (title, caption, hashtags, per-slide script) for a topic, grounded in your product's name. Returns text only — saves nothing.
growth_briefplan AI creditsA plain-language brief — the one insight that matters, wins, risks, next actions — grounded in your real post history and synced analytics.
generate_content_planplan AI creditsA one-week, day-by-day content plan for your creators, grounded in what already worked. Saved — fetch it later with get_content_plan.
generate_captionsplan AI creditsTimed on-screen caption cues for a video — a transcript plus start/end-timed lines. Returns cue data only.
analyze_productplan AI creditsStart an AI analysis of your product: fetches an excerpt of its own website (a real outbound fetch, not just nooticr's own data), reads its posts and fleet performance, and writes the result as its brand playbook. Runs in the background — returns a jobId, poll it with analyze_product_status. 10 plan AI credits, first analysis free per workspace.
analyze_product_statusfreePoll a job analyze_product started. Returns state (pending/thinking/done/error) and, once done, the analysis. Free — the cost was already charged when the job started.
list_social_connectionsfreeThe social accounts you've connected and what each is allowed to do — read, publish, manage comments. Also lists which platforms can be connected at all.
connect_social_accountfreeA link to open to connect one account. You approve at the provider; nothing connects until you do, and no credential ever passes through this tool.

How billing works

  • New accounts get 20 free credits.
  • Every tool is priced at what it fetches upstream, and bills from the first call. A tool that fans out to two fetches costs both — analyze_post is 2 for the frames plus 1 for the transcript — and its description says so. There is no free first use: that grant belonged to the AI calls, and there are none.
  • A call that fails is refunded automatically, and a call interrupted mid-flight is billed once at most — retries are idempotent.
  • Platform admins bypass credit debiting entirely.

Interactive cards in Claude / ChatGPT chat

Every tool that returns posts also renders inline interactive cards directly in the chat (MCP Apps ui://nooticr/view resource rendered in a sandboxed iframe):

  • Video posts (TikTok/IG/YouTube/Douyin/LinkedIn) — an inline <video> player with the thumbnail as poster, playing the re-hosted permanent MP4 (no expiring CDN tokens).
  • Carousels / slideshows — a horizontally scrollable strip of every slide with an image count chip.
  • Single images — inline thumbnail.
  • Text-only posts (LinkedIn / X) — a styled quote block of the post text.
  • Official brand marks — each card shows the platform's real logo (simple-icons) in its brand color instead of an emoji.

search_mentions renders a different view, because monitoring is triage rather than browsing:

  • Each row is a person saying something. Their picture, with the network's mark on it, then the handle and when they wrote it — "today at 7:25 PM", not a timestamp — then the comment with the term highlighted everywhere it appears, then what it earned in likes and replies. A ×N badge marks a comment that names the brand more than once.
  • Each post carries its reach. The same sentence under a 25K-upvote thread and under a post nobody saw are not the same problem, and nothing else on screen tells you which one you are reading.
  • The per-network counts are filters. Click one to narrow to it; a network that answered with nothing is shown but is not clickable, because filtering to it is a dead end. Filtering and sorting redraw from what you already paid for — the view never re-queries.
  • A burst collapses. One post with a run of near-identical replies (a coordinated fan campaign, say) shows the first few and offers the rest, so it cannot push four other networks off the screen.
  • Comments are selectable, and the selection is agentic. Tick any comments, or select a whole thread at once, and send them — the view hands the host the comment ids the tool issued, so the model can reply to, escalate or analyse exactly those. Selections survive filtering and sorting.
  • Load more pages from the nextOffset the tool returned.

Also inline thumbnails render for the model / plain-text clients:

  • get_social_media / understand_social_post / analyze_post — up to 4 frames inline (poster + carousel slides). The full mediaItems[].preview_url + thumbnailUrl stay in structuredContent for the model to reason over.
  • discover_social_posts / get_user_posts / analyze_creator_profile — each returned post shows its thumbnail inline (up to 4 at once) together with its title/caption + views/likes/comments. Say "next" or "show more" — Claude will re-call with offset/limit pagination. Say "analyze the 2nd one" — Claude calls analyze_post or understand_social_post on that URL.
  • Batch analysis — ask "analyze all 4" or "understand these 3 in batch" and Claude will call analyze_post/understand_social_post once per URL in parallel and summarize. For large batches, discover_social_posts + a follow-up analyze_post per URL is the recommended flow.

Your own model does the thinking

There is no other mode. Every tool returns the material an analysis would have been built from, at the price of the fetch, and asks your model to reason over it. Nothing here calls a model of ours, so nothing here sells you a judgement.

For the visual tools that means actual frames — real image content blocks, not a description of them — paired with the transcript. Measured on Claude Code: ~1,200 tokens per 1280×720 frame, eight frames read back correctly and in order. Twenty frames is about 2.4% of a million-token context.

ToolWhat comes backCredits
analyze_postframes as images, plus the transcript and stats3 (2 + 1)
analyze_commentsthe comments, each with an id, and the labels to use2
analyze_creator_profilethe creator's recent posts and their numbers2
score_draftyour own draft, and the rubric to score it againstfree

The prices above are derived from the fetches each tool makes rather than written down twice — see EVIDENCE_PLANS and planCost in src/shared/evidence.ts. score_draft has no plan at all: it reviews text you already have, so there is nothing to fetch and nothing to charge for.

show_comment_review closes the loop: hand back your classifications and it draws them — every comment with its sentiment and category, filterable and selectable. Free, and it makes no requests.

Before an expensive call, it asks

Most tools print their price in their own description, so a call costs what you already read. Six do not, because their price is set by an argument — or by a list the request never mentions:

  • search_mentions bills per network swept, so a bare "monitor my brand" sweeps all nine for 21 credits.
  • catch_up_watchlist bills per creator, so the price is the length of your watchlist.
  • answer_my_audience and what_should_i_make_next bill per post opened (14 and 12 credits at their defaults), so they ask once the real post count is known rather than on a worst case.
  • search_spoken_mentions bills per network, per handle and per transcript, so it asks on the worst case it could reach.
  • create_brand_watch asks however small the number is, because what is being agreed to is a recurring charge rather than one run.

Above 6 credits those first five ask first, over MCP elicitation — the client shows the number and you accept or decline. Declining spends nothing and is not an error. A client that does not support elicitation is not blocked; the call runs as it always did.

Two rules go further than the threshold. A scheduled watch always asks, because the standing arrangement is the thing being approved. And a watch that emails a digest refuses to accept a deliverTo address unless a person actually saw the dialog and said yes — "nobody could be asked" is a fine answer for a spend and the wrong one for an address.

Prerequisites

  • Node.js >= 18 (tested on Node 22)
  • An nooticr account (created automatically on first sign-in — Google sign-in via npx @nooticr/mcp login; the dashboard is not required: the server auto-creates a default workspace + app for new accounts)
  • Access to an nooticr server — defaults to the cloud API (https://api.nooticr.com); point NOOTICR_BASE_URL at your own deployment for local development

Quick start

# 1. Sign in with your nooticr account (Google sign-in opens in your browser)
npx @nooticr/mcp login
#    or with email/password:
npx @nooticr/mcp login --email you@example.com --password '...'

# 2. Add it to your MCP client (see install section above) — or run it manually:
npx @nooticr/mcp            # stdio (default; for Claude Desktop / Cursor)
npx @nooticr/mcp --http     # remote HTTP with OAuth (for OpenAI Agents SDK)

login stores your nooticr tokens in ~/.config/nooticr-mcp/credentials.json (mode 0600). If your browser cannot be opened automatically, copy the URL it prints into a browser manually.

Running on a server (no browser)

login and the OAuth flow both need a browser once, and both leave behind a 15-minute access token kept alive by a refresh token. That is the wrong shape for an integration running server-side: nothing there can complete a consent screen, and a refresh chain that breaks has to be repaired by hand.

An API key is the other way in. Mint one from a browser at mcp.nooticr.com/dashboard — sign in, name the key, copy it — or from a machine you can sign in on, once:

npx @nooticr/mcp login                                  # the one interactive step
npx @nooticr/mcp api-key create --name "aybee-prod"     # prints the key, once

Then give it to the deployment. There is nothing else to configure and nothing to refresh — the key stays valid until you revoke it.

# stdio, as a subprocess of your own service
NOOTICR_API_KEY=nk_... npx @nooticr/mcp

On a server, prefer the environment variable: it is what every container runtime and secret manager already injects, and it leaves nothing on a disk that a redeploy is going to throw away. Where setting one is the awkward part — a laptop, or a client like Claude Desktop that does not inherit your shell — store the key in the credentials file instead:

npx @nooticr/mcp login --api-key nk_...

That checks the key against the server before writing it, so a typo fails while you are still there to fix it, and then behaves exactly like the environment variable: no browser, no refresh, valid until revoked. The file holds one credential, so this replaces any session an earlier login left behind (and NOOTICR_API_KEY still overrides it).

# or against the remote endpoint, as an ordinary bearer token —
# no /authorize, no PKCE, no redirect URI
POST https://mcp.nooticr.com/mcp
Authorization: Bearer nk_...

Managing them, from the dashboard's API keys card or the CLI:

npx @nooticr/mcp api-key create --name "staging" --expires-in-days 90
npx @nooticr/mcp api-key list
npx @nooticr/mcp api-key revoke <id>

Every command takes --json for scripting. A few things worth knowing:

  • The key is shown once, by api-key create. nooticr stores only a hash of it and cannot show it again; list shows the head (nk_1a2b3c4d…) so you can tell keys apart.
  • A key carries the scope of whoever created it — their account, and the workspace they were in (--workspace-id picks another one you belong to).
  • A key cannot create or revoke keys. That is deliberate: it means a leaked key cannot mint a replacement that outlives revoking the original.
  • --expires-in-days is optional. Without it a key does not expire on its own.
  • Revoking takes effect immediately at the API. The hosted remote endpoint caches the "this key is real" answer for up to five minutes, which only ever lets a revoked key see the tool list — every call that touches your account is checked against nooticr-server on the spot.

Usage in Claude Desktop

After npx @nooticr/mcp login, add to claude_desktop_config.json:

{
  "mcpServers": {
    "nooticr": {
      "command": "npx",
      "args": ["-y", "@nooticr/mcp"]
    }
  }
}

Tokens are resolved from the credentials file written by login (or from NOOTICR_ACCESS_TOKEN). If your client does not inherit your shell environment, set the env vars explicitly:

{
  "mcpServers": {
    "nooticr": {
      "command": "npx",
      "args": ["-y", "@nooticr/mcp"],
      "env": {
        "NOOTICR_BASE_URL": "http://localhost:8080"
      }
    }
  }
}

Usage in Cursor

In .mcp.json (project root) or ~/.cursor/mcp.json:

{
  "mcpServers": {
    "nooticr": {
      "command": "npx",
      "args": ["-y", "@nooticr/mcp"]
    }
  }
}

After adding the server, run npx @nooticr/mcp login in your terminal — Cursor spawns the server with your environment, so it picks up the stored credentials.

For remote/HTTP usage, Cursor can connect to the OAuth-enabled HTTP mode with npx @nooticr/mcp --http running, pointing the server URL at http://localhost:3457/mcp. Remote clients (including Cursor) discover the OAuth endpoints from http://localhost:3457/.well-known/oauth-authorization-server, open the "Sign in with Google" page, and store the resulting access token.

Usage with OpenAI Agents SDK

Start the HTTP transport:

npx @nooticr/mcp --http --port 3457

Python:

from agents import Agent, Runner
from agents.mcp import RemoteMCPClient

async def main():
    async with RemoteMCPClient(
        url="http://localhost:3457/mcp",
        auth_provider="oidc",  # OAuth flow opens your browser once
    ) as client:
        agent = Agent(name="nooticr", mcp_servers=[client])
        result = await Runner.run(
            agent,
            "Analyze this video: https://www.youtube.com/watch?v=dQw4w9WgXcQ",
        )
        print(result.final_output)

TypeScript (Agents SDK):

import { Agent } from "agents";
import { RemoteMCPClient } from "agents/mcp/client";

const client = new RemoteMCPClient({
  url: "http://localhost:3457/mcp",
  authProvider: "oidc", // opens the browser for the OAuth flow
});

const agent = new Agent({
  name: "nooticr",
  mcpServers: [client],
});

const result = await agent.run(
  "Analyze this video: https://vm.tiktok.com/abc123/",
);
console.log(result.output);

For a local stdio process with the Agents SDK, use StdioMCPClient (Python: StdioMCPClient(command="npx", args=["@nooticr/mcp"])).

Command line

nooticr-mcp                    Start in stdio mode (default transport)
nooticr-mcp --stdio            Same as above
nooticr-mcp --http [--port N]  Start the remote HTTP transport with OAuth (default port 3457)
nooticr-mcp login              Sign in to nooticr via Google in your browser
nooticr-mcp login --email ... --password ...   Password login
nooticr-mcp login --api-key nk_...             Sign in with an API key, no browser
nooticr-mcp api-key create [--name N] [--expires-in-days D] [--workspace-id W] [--json]
                               Mint a key for a server with no browser
nooticr-mcp api-key list [--json]         List this account's keys
nooticr-mcp api-key revoke <id> [--json]  Revoke one
nooticr-mcp --help             Show help

Environment variables

VariableDefaultDescription
NOOTICR_BASE_URLhttps://api.nooticr.comnooticr server base URL (trailing slash stripped)
NOOTICR_ACCESS_TOKEN—nooticr JWT access token; takes priority over everything below
NOOTICR_API_KEY—nooticr API key from api-key create — no browser, no refresh, valid until revoked; takes priority over the credentials file (including a key login --api-key put there)
NOOTICR_CREDENTIALS_FILE~/.config/nooticr-mcp/credentials.jsontoken store path
NOOTICR_PUBLIC_URLhttp://localhost:3457public base URL advertised in OAuth metadata (HTTP mode)
NOOTICR_PORT3457port for --http and login
NOOTICR_TRANSPORTstdiostdio or http (same as --http)

How authentication works

stdio mode (Claude Desktop, Cursor): the server uses the first credential it finds — NOOTICR_ACCESS_TOKEN, then NOOTICR_API_KEY, then the credentials file written by login. That file holds one credential, whichever login last wrote: an API key (login --api-key) or a session. A session token that has expired is refreshed with the stored refresh token, and a 401 from the nooticr API is retried once after a refresh. An API key is never refreshed wherever it came from: it does not expire, so a 401 on one means revoked or mistyped, and retrying would only hide that.

API key (any transport, no browser): send it as the bearer token, or set NOOTICR_API_KEY. nooticr-server resolves the key to its owner and the workspace it was scoped to, and every authorization check downstream sees exactly what it would have seen for a signed-in session. See Running on a server.

HTTP mode (OpenAI Agents SDK, remote clients): the server runs its own OAuth 2.0 authorization server (Authorization Code + PKCE S256, public client, per the MCP 2025-03-26 spec):

  • GET /.well-known/oauth-authorization-server — metadata
  • GET /authorize — validates the request (loopback or https redirect URIs) and forwards the browser to nooticr's Google sign-in
  • GET /oauth/callback — our own loopback callback; exchanges nooticr's completion code for nooticr JWTs and redirects back to the MCP client with a one-time code
  • POST /token — verifies PKCE and issues an opaque Bearer token bound to the nooticr session (valid 1 hour)
  • every MCP RPC validates the Bearer token against the session map — or, when the bearer is an API key, forwards it to nooticr-server as the caller's own credential, which is what makes this endpoint usable with no browser at all

Supported URLs

  • TikTok: tiktok.com/*, vm.tiktok.com/* (and www./m. subdomains)
  • Instagram: instagram.com/* (reels, posts, carousels), instagr.am/*
  • YouTube: youtube.com/* (including /shorts/), youtu.be/*, m.youtube.com/*
  • X: x.com/*, twitter.com/*
  • Reddit: reddit.com/*, redd.it/*
  • Weibo: weibo.com/*, weibo.cn/*
  • Douyin: douyin.com/*
  • Xiaohongshu: xiaohongshu.com/*, xhslink.com/*
  • Bilibili: bilibili.com/*, b23.tv/*
  • LinkedIn: linkedin.com/* (posts, profile URLs)

All tools accept these hosts and handle video, image, carousel, slideshow and text posts.

Troubleshooting

  • Not authenticated with nooticr / 401: run npx @nooticr/mcp login, or set NOOTICR_API_KEY (see Running on a server).
  • unknown, revoked or expired nooticr API key: the key is not one this account has live. npx @nooticr/mcp api-key list shows every key and its state, revoked ones included.
  • API keys cannot manage API keys: api-key create/list/revoke need a signed-in session, which is why they ignore a key in NOOTICR_API_KEY and one stored by login --api-key. Run npx @nooticr/mcp login first.
  • 402 paywall / insufficient MCP credits: your nooticr account is out of credits. Prices are listed per tool in Tools — 1 credit for a post lookup or transcript, 2 for discovery and for a tool that makes one fetch, 3 for the two that fetch frames and transcript. Every tool bills from the first call. Top up via check_nooticr_credits, or the nooticr dashboard at https://nooticr.com/settings?tab=billing.
  • Expired refresh token: the stored refresh token was rejected by the nooticr server. Run npx @nooticr/mcp login again to re-authenticate.
  • Could not reach the nooticr server: NOOTICR_BASE_URL is unreachable or wrong.
  • Client shows "Bad Request" or connection errors in HTTP mode: make sure the port matches NOOTICR_PUBLIC_URL and that the client fetched a token first (the OAuth flow must complete once in your browser).

Platform submissions

See docs/SUBMISSION.md for ready-to-paste configs and the submission package for Claude Desktop, Cursor, and OpenAI Agents SDK.

Security notes

  • The credentials file is written with mode 0600 and the directory with 0700.
  • OAuth redirect URIs are restricted to loopback (http://localhost, http://127.0.0.1, http://[::1]) or https:// URLs; the /authorize endpoint requires PKCE (S256).
  • Authorization codes and PKCE challenges are one-time use and short-lived (in-memory).
  • Access tokens are opaque, random, and bound to the in-memory session map; they expire after 1 hour. Restarting the server invalidates all sessions.
  • API keys are stored as a sha256 hash, never in the clear, so a database dump cannot be replayed against the API. They are scoped to one account and one workspace, carry their owner's role as it is now rather than as it was when the key was minted, and cannot be used to create or revoke keys.
  • Never share your credentials file, NOOTICR_ACCESS_TOKEN or NOOTICR_API_KEY.

Development

npm install
npm run build    # tsc
npm test         # vitest (66 unit tests, mocked fetch — no network)

Those are unit tests against a stub backend. For real MCP-protocol end-to-end tests — no Rust, no Postgres, no API key — npm run test:e2e-smoke:fixture spawns this repo's real built CLI and drives it over stdio against a pure-Node stand-in for nooticr-server. See docs/testing/agentic-e2e-testing.md for that plus the tier above it (npm run test:e2e-smoke against a real nooticr-server). For a real model driving the server through whole journeys — asserting on the chain of tools it walks, not on one call — see npm run test:quests and docs/testing/tool-chaining-quests.md. And for tests/e2e/agentic-visual*.e2e.ts — every reachable widget view, driven by a real tool-call result, rendered in a real browser with every host-facing button actually clicked (npx playwright test tests/e2e/agentic-visual.e2e.ts tests/e2e/agentic-visual-full-app.e2e.ts). That exercise found six real product bugs, documented in the same doc.

License

MIT

Keywords

mcp

FAQs

Package last updated on 25 Sep 2026

Related posts