AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
MCP verified MIT Self-run

Stormy Cookbook

mcp-oneinterface-stormy-cookbook · by OneInterface

Open-source cookbook for the Stormy Social Data API and MCP server (Model Context Protocol) — one REST API for the TikTok API, YouTube API, Instagram API, LinkedIn API, X (Twitter) API and Reddit API. Search creators, resolve profiles, read posts and find verified emails from Claude, Cursor, Codex, ChatGPT or curl. One key, no scrapers.

No reviews yet
0 installs
6 views
0.0% view→install

Install

$ agentstack add mcp-oneinterface-stormy-cookbook

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/mcp-oneinterface-stormy-cookbook)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
16d ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Stormy Cookbook? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Stormy Cookbook — TikTok, YouTube, Instagram, LinkedIn, X and Reddit API recipes for AI agents

Open-source, copy-pasteable recipes for the Stormy Social Data API and the Stormy MCP server (Model Context Protocol, Streamable HTTP).

One HTTP contract — search, profile, emails, jobs — across six social networks. No proxy pool, no six vendor SDKs, no scraper to babysit. Point your agent at https://stormy.ai/mcp, or curl the REST base at https://stormy.ai/api/v1.

[](LICENSE) [](https://github.com/OneInterface/stormy-cookbook/actions/workflows/link-check.yml) [](https://modelcontextprotocol.io) [](#what-you-can-do-on-each-network) [](https://stormy.ai/docs)

Jump to: [Recipes](#recipes) · [MCP quickstart](#quickstart-a-connect-the-mcp-server) · [REST quickstart](#quickstart-b-call-the-rest-api-directly) · [Endpoints](#the-whole-api-on-one-screen) · [Pricing](#pricing) · [Errors](#errors-and-retries) · [FAQ](#faq)


Why this exists

Every "get social data" project starts the same way: six different APIs, six auth schemes, six rate limits, six response shapes, and a scraper that breaks on a Tuesday. Then you bolt an LLM on top and discover none of it is shaped for an agent — no cost signal, no idempotency, no durable jobs, no machine-readable capability list.

Stormy is that layer, already built. This cookbook is how you use it.


Quickstart A: connect the MCP server

The Stormy MCP server speaks Streamable HTTP at https://stormy.ai/mcp and authenticates with an HTTP bearer token. Get a key at stormy.ai/account and export it:

export STORMY_API_KEY="stm_live_..."   # never commit this

Claude Code

claude mcp add --transport http stormy https://stormy.ai/mcp \
  --header "Authorization: Bearer $STORMY_API_KEY"

Codex CLI (~/.codex/config.toml)

[mcp_servers.stormy]
url = "https://stormy.ai/mcp"
bearer_token_env_var = "STORMY_API_KEY"

Cursor / Windsurf / any mcp.json client

{
  "mcpServers": {
    "stormy": {
      "url": "https://stormy.ai/mcp",
      "headers": {
        "Authorization": "Bearer ${STORMY_API_KEY}"
      }
    }
  }
}

ChatGPT custom connector

Name: Stormy Social Data
MCP URL: https://stormy.ai/mcp
Authentication: OAuth

The ten MCP tools you get

| Tool | What it does | | --- | --- | | search_people(platform, query, limit=10, fresh=false) | Search one network from a natural-language query | | lookup_profile(target, platform=null, fresh=false, include_posts=false) | Resolve a URL / @handle / channel ID to a normalized profile | | find_emails(platform, targets) | Verified contact emails for 1–25 Instagram, TikTok or YouTube profiles | | estimate_price(quantity=100, include_email=false) | Rate card + a maximum estimate, spends nothing | | account_status() | Plan, remaining prepaid usage, top-up URL | | describe_social_data() | The machine-readable platform / field / pricing / workflow contract | | start_social_job(operation, arguments, idempotency_key, ...) | Queue fresh, bulk or email work durably | | get_social_job(job_id) | Status, progress, poll_after_seconds, result, full timeline | | list_social_jobs(status=null, limit=20) | Recover prior work instead of resubmitting | | cancel_social_job(job_id) | Cancel queued / scheduled / throttled / retrying work |

Then just ask:

> Find 25 TikTok creators posting about home espresso, pull their follower counts, and tell me what it cost.


Quickstart B: call the REST API directly

Base URL: https://stormy.ai/api/v1 (also reachable at https://api.stormy.ai/api/v1). Auth: Authorization: Bearer or X-API-Key: . Never put a key in a URL, a JSON body, a prompt, or an MCP tool argument.

curl

curl -X POST 'https://stormy.ai/api/v1/search' \
  -H "Authorization: Bearer $STORMY_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: espresso-tiktok-2026-07' \
  -d '{
    "platform": "tiktok",
    "query": "home espresso and coffee gear creators",
    "limit": 25,
    "fresh": true
  }'

Python

import os

import requests

response = requests.post(
    "https://stormy.ai/api/v1/search",
    headers={
        "Authorization": f"Bearer {os.environ['STORMY_API_KEY']}",
        "Idempotency-Key": "espresso-tiktok-2026-07",
    },
    json={
        "platform": "tiktok",
        "query": "home espresso and coffee gear creators",
        "limit": 25,
        "fresh": True,
    },
    timeout=90,
)
response.raise_for_status()
payload = response.json()

for creator in payload["results"]:
    print(creator["handle"], creator["follower_count"])

print("cost:", payload["usage"]["cost_usd"], "USD")

TypeScript

const response = await fetch("https://stormy.ai/api/v1/search", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.STORMY_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "espresso-tiktok-2026-07",
  },
  body: JSON.stringify({
    platform: "tiktok",
    query: "home espresso and coffee gear creators",
    limit: 25,
    fresh: true,
  }),
});

if (!response.ok) throw new Error(await response.text());
const { results, usage } = await response.json();
console.log(results.length, "creators for", usage.cost_usd, "USD");

What comes back

{
  "ok": true,
  "platform": "tiktok",
  "query": "home espresso and coffee gear creators",
  "fresh": true,
  "results": [
    {
      "id": "6812...",
      "handle": "@homebarista",
      "nickname": "Home Barista",
      "url": "https://tiktok.com/@homebarista",
      "signature": "Espresso at home, no snobbery.",
      "verified": false,
      "follower_count": 184000,
      "following_count": 312,
      "likes_count": 4210000,
      "video_count": 612
    }
  ],
  "usage": {
    "operation": "fresh_discovery",
    "metered_results": 25,
    "billed_results": 25,
    "cost_usd": "2.00",
    "credits": 200,
    "plan": "paid",
    "remaining_usage_usd": "23.00"
  }
}

Every successful response carries a usage receipt. You are billed for outcomes, not requests.


What you can do on each network

| Network | POST /search | POST /profile | include_posts | POST /emails | Public fields | | --- | --- | --- | --- | --- | --- | | TikTok API | Creators by niche | @handle or URL | Videos, views, shares, saves, music, hashtags | ✅ verified email | 27 | | YouTube API | Channels by topic | Handle or channel ID | Videos, transcripts, captions | ✅ verified email | 25 | | Instagram API | Creators by niche | Username or URL | Posts, captions, engagement, location | ✅ verified email | 23 | | X (Twitter) API | Accounts and posts | @handle or URL | Posts, views, bookmarks, conversation ID | — | 26 | | LinkedIn API | People and companies | Profile URL | Posts, reaction breakdowns, cadence | — | 31 | | Reddit API | Threads by topic | Author karma and age | Score, upvote ratio, comment count | — | 17 |

Field lists are authoritative in GET /api/v1/capabilitiesfields_by_platform. Treat every platform-specific field as nullable — you get it when it is public and the source supplied it.

Per-network field lists (click to expand)

TikTok — profile: id, sec_uid, handle, nickname, url, signature, avatar_url, verified, follower_count, following_count, likes_count, video_count · posts: video_id, url, description, create_time, duration, views, likes, comments, shares, saves, image_url, is_pinned, music, hashtags, caption_url

YouTube — profile: channel_id, handle, name, url, subscribers, description, videos_count, total_views, profile_image_url, banner_image_url, country, keywords, links · posts: video_id, url, title, description, published_at, duration, views, likes, comments, thumbnail_url, transcript, caption_url

Instagram — profile: username, full_name, biography, profile_pic_url, follower_count, following_count, posts_count, avg_engagement_rate, biolinks, country, is_verified, is_business_account, business_category_name · posts: media_id, post_url, caption, taken_at, like_count, comment_count, image_url, location, location_data, comments

X (Twitter) — profile: id, handle, name, url, description, profile_image_url, verified, location, website, followers, following, posts_count, joined_at · posts: id, url, text, created_at, language, likes, replies, reposts, quotes, views, bookmarks, conversation_id, author

LinkedIn — profile: id, name, linkedin_url, headline, country, country_iso_2, followers, total_posts, posts_last_6_months, posting_frequency, avg_likes, avg_comments, avg_reposts, avg_total_interactions, top_post_text, top_post_interactions, last_post_date, ai_summary, is_suitable_for_promotion, relevant_posts · posts: post_url, text, headline, posted_datetime, total_interactions, num_likes, num_comments, num_reposts, num_reactions_breakdown, poster_name, poster_linkedin_url

Reddit — profile: author, author_url, karma, account_created_at · posts: id, url, permalink, subreddit, author, title, text, created_at, score, upvote_ratio, comments_count, is_self, over_18


Recipes

Every recipe is a single runnable markdown file with real code and a real cost estimate. Full index with difficulty and pricing: [recipes/README.md](recipes/README.md).

| # | Recipe | Networks | What you get | | --- | --- | --- | --- | | 01 | [Find influencers by niche](recipes/01-find-influencers-by-niche.md) | TikTok, YouTube, Instagram | A ranked shortlist of creators with follower counts and engagement | | 02 | [Build an outreach list with verified emails](recipes/02-build-an-outreach-list-with-verified-emails.md) | TikTok, YouTube, Instagram | Search → filter → /emails → CSV, paying only for hits | | 03 | [Enrich a CRM from handles](recipes/03-enrich-a-crm-from-handles.md) | All six | Handles in, normalized profile rows out | | 04 | [Competitor content analysis](recipes/04-competitor-content-analysis.md) | TikTok, YouTube, Instagram | Which of a rival's posts actually worked, and why | | 05 | [Monitor a creator over time](recipes/05-monitor-a-creator-over-time.md) | Any | A daily snapshot job and a growth delta | | 06 | [Cross-platform audience research](recipes/06-cross-platform-audience-research.md) | All six | One query fanned out across six networks, merged | | 07 | [Reddit topic listening](recipes/07-reddit-topic-listening.md) | Reddit, X | Which threads are moving on a topic you care about | | 08 | [Durable jobs for large collections](recipes/08-durable-jobs-for-large-collections.md) | All six | 1,000+ results without holding an HTTP connection | | 09 | [Use Stormy from an MCP agent](recipes/09-agent-workflows-with-mcp.md) | All six | Prompts + tool policy for Claude Code, Cursor, Codex | | 10 | [Handle errors, rate limits and billing](recipes/10-errors-rate-limits-and-billing.md) | — | 402 / 429 / 503 handling, headless top-up, idempotency |


The whole API on one screen

Paid calls

| Method | Path | Body | Notes | | --- | --- | --- | --- | | POST | /search | platform, query, limit (1–100, default 10), fresh (default false) | Cache-first. fresh=true calls a live provider | | POST | /profile | target, platform?, fresh, include_posts | Returns data, not results. platform is optional when target is a URL | | POST | /emails | platform (instagram \| tiktok \| youtube), targets (1–25) | The only endpoint that returns contact data | | POST | /jobs | operation, arguments, delay_seconds (0–604800), priority (−10…10), max_attempts (1–10) | 202 Accepted. operationsearch_people, lookup_profile, find_emails | | GET | /jobs/{job_id} | ?include_events=true | Status, progress and the event timeline | | GET | /jobs | ?status=running&limit=20 | List recent jobs | | DELETE | /jobs/{job_id} | — | Cancel non-terminal work |

Free calls

| Method | Path | Notes | | --- | --- | --- | | GET | /pricing?quantity=100&include_email=true | Authoritative rate card + a maximum estimate | | GET | /capabilities | Platforms, per-platform fields, endpoints, job statuses, agent policy | | GET | /account | Plan, usage_balance, scopes, top-up URL | | POST | /account/top-up | amount_usd, note? → an instant Stripe checkout_url | | GET POST DELETE | /keys, /keys/{id} | List, mint and revoke API keys |

Legacy aliases /social/search, /social/profile and /social/emails still work; new clients should use the short paths.

Send an Idempotency-Key header on any paid call. Retrying with the same key never duplicates work or charges.

Machine-readable contract

| Resource | URL | | --- | --- | | Capabilities JSON | | | OpenAPI | | | llms.txt | | | Human docs | |


Pricing

One credit is one US cent. You are charged for successful outcomes only — a verified-email lookup that finds nothing costs $0.00.

| Operation | Price | When it applies | | --- | --- | --- | | Cached result | $0.01 | fresh=false on /search or /profile | | Fresh profile | $0.05 | /profile with fresh=true | | Fresh discovery | $0.08 | Per matching person returned by /search with fresh=true | | Verified email | $0.15 | Per email actually found by /emails |

  • Free preview: 50 cached results per rolling 30 days. No fresh data, no emails.
  • Paid: $50 / month, including $25 (2,500 credits) of usage. Overage is metered at the rates above.

Worked examples (straight from GET /pricing):

| Workload | Cost | | --- | --- | | 100 cached profiles | $1.00 | | 100 fresh profiles | $5.00 | | 100 fresh matching people | $8.00 | | 100 verified emails | $15.00 | | 100 fresh people + their verified emails | $23.00 |

Ask before you spend — estimate_price / GET /pricing is free:

curl 'https://stormy.ai/api/v1/pricing?quantity=250&include_email=true'

Errors and retries

| Status | Code | What to do | | --- | --- | --- | | 400 | invalid_request | Fix the body. Unsupported platform, empty query, limit out of 1–100, more than 25 email targets | | 401 | invalid_token | Key missing, expired, revoked or wrong | | 402 | upgrade_required | Return the upgrade_url to the user | | 402 | insufficient_balance | POST /account/top-up with error.recommended_topup_usd, hand back checkout_url, poll GET /account, retry | | 404 | job_not_found | Job missing or owned by another account | | 429 | rate_limit | Wait Retry-After seconds. Do not retry immediately | | 429 | provider cooldown | The shared upstream pool is cooling down — switch to a durable job | | 503 | provider_not_configured | Our deployment problem, not your request. Retry later |

Durable jobs never fail on a rate limit: they move to throttled without consuming an attempt and resume after the cooldown. Job statuses are queued, scheduled, running, throttled, retrying, succeeded, failed, cancelled. Poll only after poll_after_seconds, and stop when terminal is true.

Full worked handling in [recipe 10](recipes/10-errors-rate-limits-and-billing.md).


Privacy and scope

  • Stormy returns public social data only.
  • search and profile responses have email, business_email, contact_email, phone and phone_number recursively stripped at the API boundary. This is enforced server-side, not by convention.
  • POST /emails is the only path to contact data, it is opt-in, it is limited to Instagram / TikTok / YouTube, and it is billed only when a verifi

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.