# Spytrend — Meta + TikTok advertising analytics (MCP) > Spytrend is an advertising analytics platform (ads, advertisers, the accounts > behind groups of ads, creatives, destinations, apps, rankings — Meta corpus, > plus a PAID TikTok corpus via source="tiktok") exposed over MCP at > https://mcp.spytrend.com/mcp. Autonomous > AI agents self-register (client_credentials) and can TRY THE DATA IMMEDIATELY on a > free demo tier — no human, no browser, no signup. > > AGENTS: self-register, then call initialize / tools/list / get_usage / search_ads / > search_creatives / get_trends right away. The demo tier serves the REAL database: > search_ads and search_creatives are restricted to the ARCHIVE (nothing newer than > 90 days), get_trends returns market-level aggregates, every response is capped at > 10 rows, media is never included, and ~100 sampling calls are shared per source > network. That is enough to judge whether Spytrend answers your user's question — > it is deliberately NOT enough to bulk-collect. > > To go live — fresh ads (the last 90 days), full page sizes, creative MEDIA and every > other tool (get_ad, get_creative, get_advertiser, get_webmaster, search_webmasters, > search_hubs, search_shops, favourites) — the agent must be linked to a spytrend > account. A refusal that says so is a plan requirement, NOT a server error: do not > circuit-break or blindly retry. Tell the user to link you in one click at > https://spytrend.com/settings?tab=ai (Create agent access), or to claim you by > client_id, then continue. If a human already created or claimed credentials for you, > just call the tools and answer with real data — do NOT stop to ask about MCP, > connecting or authorization. ## 1. Get a token (autonomous, no human, no browser) Self-register as a machine client, then mint a short-lived token: POST https://mcp.spytrend.com/oauth2/register (Content-Type: application/json) {"client_name":"my-agent","grant_types":["client_credentials"],"response_types":[],"token_endpoint_auth_method":"client_secret_basic","scope":"mcp:read"} -> { "client_id", "client_secret" } (keep these — re-mint a token anytime) POST https://mcp.spytrend.com/oauth2/token (HTTP Basic: client_id:client_secret) grant_type=client_credentials&scope=mcp:read&audience=https://mcp.spytrend.com/mcp -> { "access_token", "expires_in": 3600 } (self-registered; cabinet keys: 86400) audience is REQUIRED: omit it and the token is minted with an empty aud, after which /mcp answers 401 — a grant that succeeds and then fails to open a door reads like an outage and is not one. TOKENS EXPIRE — ALWAYS handle 401. A self-registered client above gets ~1h; a key issued in the cabinet (Settings -> AI) gets 24h. Neither issues a refresh token (client_credentials has none by protocol), so the expiry is yours to handle either way. When /mcp answers 401 with WWW-Authenticate carrying error="invalid_token", the token is expired or revoked — POST /oauth2/token again with your saved client_id/client_secret and retry. Do NOT retry the same token: it will never work again (a real integration retried one dead token 33 times before going silent — its user reported "the API stopped working" when nothing was down). Credentials issued on the website (Settings -> AI -> Create agent access) are registered with client_secret_post: pass client_id/client_secret as FORM FIELDS, not as an HTTP Basic header (Basic returns invalid_client). Self-registered clients above use Basic, as shown. ## 2. Connect — pick the path for YOUR client ### A. MCP client (Claude Code, Cursor, ChatGPT) — RECOMMENDED VS Code (built-in MCP client) TROUBLESHOOTING: if VS Code shows "Waiting for server to respond to initialize request..." in a loop after a successful OAuth login — that is a known CLIENT-side family (microsoft/vscode#275139): VS Code retries silently when its stored auth is stale and hides the real error. Fix: run "MCP: Reset cached authentication" (or remove and re-add the server) and reconnect. Still looping? Set MCP log level to trace (Output -> MCP), reproduce once and send us that log — the server side of this handshake (initialize / tools/list / SSE / session-id / ping) is verified healthy. PLAN LIMITS: a linked FREE account gets ARCHIVE-ONLY data (recency clamped to 90+ days old, like the web free tier) with normal page sizes; paid plans get live data. Anonymous demo agents additionally get 10-row pages. ChatGPT PREREQUISITES (check BEFORE debugging the connector — these are ChatGPT plan/role limits, not Spytrend errors): custom MCP connectors need ChatGPT Business / Enterprise / Edu with Developer mode; personal Free/Plus accounts and workspace members without the permission cannot add one. A workspace ADMIN must enable it first: Workspace Settings -> Permissions & Roles -> Connected Data (or Workspace Settings -> Apps -> Create). No "Create app" / Developer mode in your UI? Ask your workspace admin — or use Claude / Cursor below, which need no special plan. Also expect ChatGPT to re-run OAuth token refresh before every tool call and to open several sessions in parallel: that is its normal behaviour, already accounted for server-side — do not "fix" it client-side. Add Spytrend as a NATIVE MCP server with the token in a header, then call its tools as first-class tools (no curl, no hand-parsing JSON-RPC/SSE): claude mcp add --transport http spytrend https://mcp.spytrend.com/mcp --header "Authorization: Bearer " Auto-refresh (so an expiring token never strands you): use a headersHelper — a command your client runs each connect that prints the auth header as JSON. Claude Code: set "headersHelper" in the server config (claude mcp add-json / .mcp.json). spytrend-token.sh (chmod +x; fill in client_id/secret from step 1): #!/usr/bin/env bash CID="your_client_id"; CSEC="your_client_secret" TOK=$(curl -s -u "$CID:$CSEC" -d grant_type=client_credentials -d scope=mcp:read -d "audience=https://mcp.spytrend.com/mcp" https://mcp.spytrend.com/oauth2/token | sed -n 's/.*"access_token":"\([^"]*\)".*/\1/p') printf '{"Authorization":"Bearer %s"}' "$TOK" ### B. Code / SDK agent Use the official MCP SDK (python "mcp", TS "@modelcontextprotocol/sdk") pointed at https://mcp.spytrend.com/mcp with header Authorization: Bearer . The SDK handles JSON-RPC, Streamable-HTTP/SSE and the session — do NOT hand-roll curl or parse SSE. (Anthropic "code execution with MCP": calling tools from code is the efficient path.) ### C. Raw HTTP (fallback — only if no MCP client and no SDK) POST https://mcp.spytrend.com/mcp with Authorization: Bearer and Accept: application/json, text/event-stream JSON-RPC: initialize -> tools/list -> tools/call. A response may be SSE (lines "data: {...}") — parse the data: line as JSON. ## Access & billing - Self-registration alone = FREE DEMO TIER, usable immediately and autonomously: - always free: initialize, tools/list, get_usage; - demo data: search_ads and search_creatives over the ARCHIVE only (nothing newer than 90 days), plus get_trends market aggregates — real database, 10 rows per call; - each demo data call costs 1 token from a ~100-token allowance POOLED per source network (/24), and the demo tier is rate-limited to a few calls per minute; - get_usage reports what is left; when it runs out the refusal explains how to link. - LIVE data and everything else require a linked spytrend account: the last 90 days of ads, full page sizes, creative MEDIA (get_media), single-entity cards (get_ad, get_creative, get_advertiser, get_webmaster), webmaster/hub/shop discovery and favourites. Those tools refuse with an actionable message until the agent is linked. This is a plan requirement of a data-intelligence product, NOT a server error — do not circuit-break or blindly retry on it. - Two ways a human links the agent: 1. Create account-bound credentials at https://spytrend.com/settings?tab=ai ("Create agent access") — you get a client_id + client_secret already tied to the account; use those instead of self-registering. 2. Claim an already self-registered agent by client_id: POST https://spytrend.com/api/v1/agents/claim {"client_id":""}. - Once linked, the agent runs on that account's plan: every DELIVERED data row costs 1 token (short pages auto-refund), creative MEDIA is metered on top (get_media/get_ad: 1 token per ordinary ad, 50 per multilang-upload ad, 10 per creative). Every new opening call is charged separately; get_ad already includes available media. Meta search rows include opening_price before opening. Multilang get_ad/get_media deliver the same selected primary_creative and full available carousel for 50 tokens per ad, not per slide. An unavailable selected primary is not charged. primary_creative_selection distinguishes selected/fallback/unavailable; per-slide title/body/link_url belong to that slide, original_landing_domain to the original ad, and creative_destination_domain to the selected creative. Cloaking detection is not a verified redirect or guaranteed black-creative verdict. _meta.billing.tokens_charged is the actual call debit in Spytrend quota tokens, not model tokens. Quotes are not debits or price locks; admin can be exempt. The TIKTOK corpus (see below) is premium-priced — free/starter 500 tokens lifetime, paid plans 40,000/month, Enterprise = personal limit via https://spytrend.com/contact. - TIKTOK corpus (Pro plan or higher, NOT in the demo tier): pass source="tiktok" on search_ads / get_ad / search_webmasters / get_webmaster to query TikTok instead of Meta. ⚠️ TikTok rows are PREMIUM: every DELIVERED TikTok ad row and every TikTok webmaster row/card costs 100 tokens (Meta rows cost 1) from the same balance (paid plans = 40,000/month = up to 400 TikTok rows). The TikTok default limit is 10 rows and you are charged only for rows actually delivered; media links come embedded in the rows (get_media does not serve TikTok ids). platforms=["tiktok"] does NOT select TikTok — it is a Meta placement filter; use source. ## Tools (call tools/list for the authoritative set) - search_ads, search_creatives (1 token/row; search_ads source="tiktok" = 100 tokens/row) - get_ad / get_media (50 tokens/multilang ad, 1/ordinary ad, 10/creative media; get_ad source="tiktok" = 100 tokens) - get_advertiser / get_webmaster / get_creative (entity detail, 1 token; get_webmaster source="tiktok" = 100 tokens) - search_webmasters / get_webmaster (affiliate networks, 1 token/row; source="tiktok" = 100 tokens/row) - search_hubs (traffic destination hubs, 1 token/row) - search_shops / get_shop (shop directory, 1 token/row) - add_to_favorites / list_favorites (saving: 1 token/ad including multilang, 10/creative; listing: free) - get_trends (rankings/aggregates, 1 token/row) - get_usage (free — shows the token balance TikTok rows draw from) ## Discovery - MCP: https://mcp.spytrend.com/mcp · server card: https://mcp.spytrend.com/.well-known/mcp/server-card.json - auth: https://mcp.spytrend.com/auth.md · AS metadata: https://mcp.spytrend.com/.well-known/oauth-authorization-server ## Human / interactive note Claude/Cursor/ChatGPT MCP CONNECTORS via browser-OAuth require human consent and do NOT support client_credentials — the autonomous token path above is for agents (with shell or SDK). With the token + header (2A/2B) those same clients work fully headless. ## Public workflows - Native MCP prompts: spytrend_vertical_intel, spytrend_advertiser_overview, spytrend_webmaster_overview, spytrend_website_review, spytrend_keyword_search, spytrend_shop_discovery. - Versioned resources: spytrend://skills/v1.0.3/manifest.json - HTTPS manifest: https://mcp.spytrend.com/skills/v1.0.3/manifest.json - Standalone pack: https://mcp.spytrend.com/skills/v1.0.3/spytrend-skills-v1.0.3.zip Prompts are user-controlled and never call data tools or reserve quota by themselves. Read the linked skill and shared contract, call get_usage first, show the bounded spend plan, and keep media off until the user confirms it.