How to Use Social Fetch with Cursor & Claude (MCP + llms.txt) (2026)
Connect Cursor, VS Code, or Claude to Social Fetch via MCP — OAuth tools for every endpoint, llms.txt for agent orientation, and the same credit billing as the REST API.
Coding agents ship faster when they can call live APIs as tools and read your docs without you pasting OpenAPI fragments into chat. Social Fetch provides a hosted MCP server with OAuth, plus /llms.txt and /llms.json written for agent orientation.
This guide walks through setup in Cursor and Claude, example prompts that work, how to prototype with nl_ask_post (the MCP wrapper for POST /v1/ask), and how to teach your agent loop to handle Social Fetch errors without burning credits on retries.
The short version
Add https://api.socialfetch.dev/mcp to Cursor or Claude, complete OAuth in the browser, and tell the agent to read llms.txt before writing integration code. Use nl_ask_post to explore; pin typed tools once you know the route. Endpoint tools bill like REST; docs tools are free.
You'll need a Social Fetch account, credits for metered routes (Pricing), and an MCP client that supports remote Streamable HTTP with OAuth — Cursor, VS Code, Claude Code, or Claude Desktop. Reference docs: MCP integration.
Who this is for
- Developers using Cursor or Claude to scaffold social-data features while coding.
- Teams building agent workflows that need live TikTok, YouTube, Reddit, or Instagram JSON — not HTML to parse.
- Anyone who wants the agent to pick the right endpoint instead of guessing field names from training data.
If you are wiring a custom orchestrator (LangChain, Vercel AI SDK, your own runtime), the function-calling and error-handling sections apply even without MCP — register REST routes as tools and use the same response envelope.
MCP vs REST vs llms.txt
| Surface | Purpose | Auth | Credits |
|---|---|---|---|
| REST / SDK | Production integrations | x-api-key | Per endpoint |
| MCP tools | Agent-driven lookups while building | OAuth | Same as REST for endpoint tools |
| llms.txt | Orientation — what to read, in what order | None (public) | Free |
| llms.json | Full structured operation inventory | None (public) | Free |
The MCP server exposes 87+ endpoint tools (one per public API route) plus docs_search and docs_read. Tool names mirror OpenAPI operation IDs with dots replaced by underscores — tiktok.profile.get becomes tiktok_profile_get, reddit.search.get becomes reddit_search_get.
| MCP tool | REST equivalent | Notes |
|---|---|---|
tiktok_profile_get | GET /v1/tiktok/profiles/{handle} | 1 credit on completed lookup |
nl_ask_post | POST /v1/ask | 0 credits to route; nested lookup bills normally |
billing_balance_get | GET /v1/balance | Free — check before large batches |
docs_search | — | Free — search live docs |
auth_whoami | GET /v1/whoami | Free — confirm OAuth session |
MCP is for building. Production traffic should use @socialfetch/sdk or fetch with an API key — same JSON shapes, different auth surface.
Phase 1: Connect MCP in Cursor
Step 1 — Add the server config
Create or edit ~/.cursor/mcp.json for global access, or .cursor/mcp.json in a project repo so teammates share the same config:
{
"mcpServers": {
"socialfetch": {
"url": "https://api.socialfetch.dev/mcp"
}
}
}No API key goes in this file. The URL is the entire config for remote HTTP MCP.
Step 2 — Restart and open MCP settings
Restart Cursor (or reload the window). Open Settings → MCP and confirm socialfetch appears. Status should show "needs authentication" until you complete OAuth.
One-click install links for Cursor, VS Code, and others: MCP docs.
Step 3 — Complete OAuth
Click Connect or trigger a tool call. Cursor opens your browser to the Social Fetch sign-in page:
- Sign in or create an account.
- Approve MCP access for your client.
- Return to Cursor — the server status should flip to connected.
Credits charge to the account you signed in with, same as REST.
Step 4 — Verify tools load
In Agent chat, ask:
List the Social Fetch MCP tools you have access to. Then call auth_whoami and show the result.You should see endpoint tools (tiktok_profile_get, reddit_search_get, …) plus docs_search, docs_read, nl_ask_post, and billing_balance_get. If the list is empty, see Troubleshooting.
Step 5 — Optional project rules
Add a Cursor rule (.cursor/rules/social-fetch.mdc or project instructions) so every session starts oriented:
Before implementing Social Fetch API calls:
1. Read https://www.socialfetch.dev/llms.txt
2. Use docs_search / docs_read MCP tools for parameter details
3. Prefer typed MCP tools over nl_ask_post once the route is known
4. Log meta.requestId on every response
5. Check data.lookupStatus before assuming a profile was foundPhase 2: Connect MCP in Claude
Claude Code (terminal agent)
claude mcp add --transport http socialfetch https://api.socialfetch.dev/mcpThen inside a Claude Code session:
/mcpSelect Social Fetch and complete the browser OAuth flow. Test with:
Use the socialfetch MCP server. Call billing_balance_get and report my credit balance.Claude Desktop
- Open Settings → Connectors (or Developer → Edit Config depending on version).
- Add a custom remote MCP connector.
- Set URL to
https://api.socialfetch.dev/mcp. - Save, restart Claude Desktop if prompted.
- Authorize when Claude first calls a Social Fetch tool.
In a new conversation, enable the Social Fetch connector in the tools panel before sending prompts that need live data.
stdio-only clients
Some older MCP clients only speak stdio. Bridge to the hosted server:
npx mcp-remote https://api.socialfetch.dev/mcpPoint your client at the stdio process mcp-remote spawns. OAuth still runs through the browser when the bridge connects.
VS Code
Add to settings.json:
{
"mcp": {
"servers": {
"socialfetch": {
"url": "https://api.socialfetch.dev/mcp"
}
}
}
}Restart VS Code and complete OAuth when Copilot or your MCP extension prompts you.
OAuth — what actually happens
Social Fetch MCP uses OAuth 2.1. Your client never stores an API key in config.
| Step | What happens |
|---|---|
| 1 | Client discovers the MCP server at https://api.socialfetch.dev/mcp |
| 2 | Client redirects you to Social Fetch sign-in in the browser |
| 3 | You approve access; client receives a short-lived access token |
| 4 | Every tool call sends Authorization: Bearer <token> |
| 5 | Metered lookups debit credits on your signed-in account |
Token expiry: if every call returns 401, reconnect — open MCP settings and re-authenticate. Do not paste a dashboard API key into mcp.json; that is for REST/SDK only.
Team note: OAuth ties to a personal account. For CI or server-side agents, use x-api-key with REST function calling instead of MCP.
Point agents at llms.txt
llms.txt is a ~100-line orientation file: platform coverage, recommended reading order, workflow hints, and links to Quickstart, Credits, and Errors. llms.json lists every operation with method, path, and operation ID — useful when you are registering dozens of function schemas.
Paste this into your first message or system prompt:
Read https://www.socialfetch.dev/llms.txt before implementing Social Fetch API calls.
Use https://www.socialfetch.dev/llms.json when you need the full operation inventory.
For parameter details, use the docs_search and docs_read MCP tools — not training data.The MCP server also returns workflow instructions in its initialize handshake (docs first, check lookupStatus, call billing_balance_get before batches). Your agent sees this automatically when connected — but llms.txt in Cursor rules catches sessions before the first MCP call.
Example agent prompts
These prompts work in Cursor Agent or Claude with the connector enabled. They assume Social Fetch MCP is connected.
Scaffold a feature with live JSON
I need TikTok profile lookup in this Express app.
1. Read llms.txt and docs_search for "tiktok profile"
2. Call tiktok_profile_get with handle "nike" and show me the response shape
3. Add a GET /creators/:handle route using @socialfetch/sdk with the same fields
4. Handle lookupStatus found, private, and not_found explicitlyMulti-platform creator check
Compare @mrbeast across TikTok, YouTube, and Instagram.
Call the profile tools for each platform in parallel. Build a markdown table:
platform, handle, followers/subscribers, lookupStatus, creditsCharged per call.
If any call returns not_found, say so — do not retry.Reddit research while coding
I'm building a competitor research script. Use reddit_search_get with
query "switching from notion", sortBy top, timeframe year. Paginate one page.
Show the top 5 posts by score with title, subreddit, url.
Then scaffold a TypeScript function that does the same via the SDK.See the Reddit product research guide for a full research sprint.
Docs-driven SDK integration
Use docs_search to find how Instagram post lookup handles restricted content.
Read the full page with docs_read. Then add client.instagram.getPost to this
service with proper lookupStatus handling for found, not_found, and restricted.Pre-flight credit check
I need follower counts for these 20 TikTok handles: [list].
First call billing_balance_get. If balance < 20, stop and tell me.
Otherwise fetch profiles sequentially and log requestId + creditsCharged per handle.Explore with nl_ask_post
When you do not know which typed tool to call, use nl_ask_post — the MCP mirror of POST /v1/ask. Routing costs 0 credits; only the nested lookup bills.
MCP call:
{ "query": "How many TikTok followers does MrBeast have?" }REST equivalent:
curl -sS \
-H "x-api-key: $SOCIALFETCH_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "How many TikTok followers does MrBeast have?"}' \
"https://api.socialfetch.dev/v1/ask"TypeScript SDK:
const result = await client.ask({
query: "How many TikTok followers does MrBeast have?",
});
if (!result.ok) {
console.error(result.error.code, result.error.requestId);
} else {
const { routedOperation, lookup } = result.value.data;
console.log(routedOperation.path, routedOperation.params);
console.log(lookup.data.lookupStatus, result.value.meta.creditsCharged);
}Example response shape:
{
"data": {
"query": "How many TikTok followers does MrBeast have?",
"routedOperation": {
"operationId": "tiktok.profile.get",
"method": "GET",
"path": "/v1/tiktok/profiles/{handle}",
"params": { "handle": "MrBeast" }
},
"lookup": {
"data": { "lookupStatus": "found", "profile": { "...": "..." } },
"meta": { "requestId": "req_01example", "creditsCharged": 1 }
}
},
"meta": { "requestId": "req_01example", "creditsCharged": 1 }
}Pin the typed tool after exploration. Once routedOperation tells you tiktok.profile.get, switch to tiktok_profile_get for repeat calls. Typed tools are faster, more deterministic, and easier to budget.
Use nl_ask_post | Use typed tools |
|---|---|
| First time exploring a question | Production agent loops |
| User speaks in plain English | You know platform + resource |
| Prototyping in chat | Cron jobs, CI, server runtimes |
Discovering routedOperation | Paginated search with cursors |
nl_ask_post is one-shot routing, not a chat endpoint. For Q&A about a single public URL's content, use web_ask_get (GET /v1/web/ask) instead.
Try routing in the Playground or the free Ask tool before wiring it into an agent.
Function calling patterns
Whether you use MCP or register REST routes in a custom runtime, these patterns keep agent loops predictable.
One tool per route
Register tiktok_profile_get, reddit_search_get, and youtube_videos_transcript_get as separate functions. Do not build one mega-tool with a free-text platform field — models pick wrong values and you lose schema validation.
Map OpenAPI operation IDs to tool names the same way MCP does: dots to underscores.
Schema from OpenAPI, not prose
Generate JSON Schema from the OpenAPI spec or copy parameter definitions from llms.json. Required fields (handle, url, query) should be in the schema's required array so the runtime rejects bad calls before they hit the API (pre-send validation is free).
Explore, then pin
User question → nl_ask_post → read routedOperation → add typed tool to manifest → drop nl_ask for that workflowFree guardrail tools
| Tool | When to call |
|---|---|
docs_search | Before choosing an endpoint |
docs_read | For full parameter docs on one page |
billing_balance_get | Before parallel batches |
auth_whoami | Confirm OAuth session in a new chat |
Parallel fan-out
Agents often fire ten profile lookups at once. That is fine if you have ten credits — there is no published per-route rate cap; your prepaid balance is the ceiling. Stay under ~500 concurrent requests for reliability. Sequential pagination with modest concurrency is cheaper and easier to debug.
Pagination in tool loops
Search and list tools return data.page.nextCursor and data.page.hasMore. Teach the agent:
Paginate until hasMore is false or I say stop. Pass cursor verbatim — do not construct cursors manually.curl -sS \
-H "x-api-key: $SOCIALFETCH_API_KEY" \
"https://api.socialfetch.dev/v1/tiktok/profiles/charlidamelio"Error handling in agent loops
Most agent failures around social data are integration mistakes, not model mistakes. Encode these rules in your system prompt or orchestrator.
HTTP 200 is not always "found"
Profile and post routes return data.lookupStatus on HTTP 200:
lookupStatus | Meaning | Retry? | Charged? |
|---|---|---|---|
found | Data returned | — | Yes |
not_found | Target does not exist | No | Yes |
private | Account exists but is private | No | Yes |
restricted | Post not publicly scrapable (Instagram) | No | Yes |
hidden | List hidden (e.g. TikTok followers) | No | Yes |
if (result.ok && result.value.data.lookupStatus === "not_found") {
// Valid outcome — do not retry
return { status: "missing", requestId: result.value.meta.requestId };
}Transport and billing errors
| HTTP | error.code | Agent action | Charged? |
|---|---|---|---|
| 400 | bad_request | Fix parameters; do not retry same payload | No |
| 401 | unauthorized | Reconnect OAuth or check API key | No |
| 402 | insufficient_credits | Stop loop; surface to user | No |
| 502 | lookup_failed | Retry with backoff (up to 3×) | No |
| 503 | temporarily_unavailable | Retry with backoff | No |
async function callWithRetry<T>(fn: () => Promise<Result<T>>, requestId?: string) {
for (let attempt = 0; attempt < 3; attempt++) {
const result = await fn();
if (result.ok) return result;
const retryable =
result.error.code === "lookup_failed" ||
result.error.code === "temporarily_unavailable";
if (!retryable) return result;
await sleep(500 * 2 ** attempt);
}
return fn();
}Always log meta.requestId (or error.requestId) — support can trace the exact lookup.
MCP-specific: read meta at the top level
MCP tool results put meta beside data, not nested under structuredContent. After each call, parse meta.creditsCharged and meta.requestId from the tool JSON your client returns.
Stop conditions for loops
Add explicit guardrails:
- 402 — halt immediately; do not retry.
not_found— record and continue to next item; do not retry the same handle.- Same
requestIdtwice — orchestrator bug; halt. - Credit budget — call
billing_balance_getfirst; stop whencreditsChargedcumulative exceeds your limit.
End-to-end workflow
A typical session building a creator dashboard:
- Orient — agent reads
llms.txtand runsdocs_searchfor "tiktok profile" + "youtube channel". - Explore —
nl_ask_postwith "YouTube subscribers for @mrbeast" → learnsyoutube.channel.get. - Prototype — parallel MCP calls:
tiktok_profile_get,youtube_channel_get,instagram_profile_getwith handlemrbeast. Agent inspects real JSON. - Implement — you merge SDK code the agent scaffolds:
import { SocialFetchClient } from "@socialfetch/sdk";
const client = new SocialFetchClient({
apiKey: process.env.SOCIALFETCH_API_KEY!,
});
const handle = "mrbeast";
const [tiktok, youtube, instagram] = await Promise.all([
client.tiktok.getProfile({ handle }),
client.youtube.getChannel({ handle }),
client.instagram.getProfile({ handle }),
]);
for (const result of [tiktok, youtube, instagram]) {
if (!result.ok) {
console.error(result.error.code, result.error.requestId);
continue;
}
console.log(result.value.data.lookupStatus, result.value.meta.creditsCharged);
}- Validate — run the same handles in the Playground and compare
requestIdif numbers disagree. - Ship — production uses API key; MCP stays in dev.
import { SocialFetchClient } from "@socialfetch/sdk";
const client = new SocialFetchClient({
apiKey: process.env.SOCIALFETCH_API_KEY!,
});
const handle = "mrbeast";
const [tiktok, youtube, instagram] = await Promise.all([
client.tiktok.getProfile({ handle }),
client.youtube.getChannel({ handle }),
client.instagram.getProfile({ handle }),
]);
for (const result of [tiktok, youtube, instagram]) {
if (!result.ok) {
console.error(result.error.code, result.error.requestId);
continue;
}
console.log(result.value.data.lookupStatus, result.value.meta.creditsCharged);
}Move from MCP to production SDK
| Concern | MCP (dev) | SDK (prod) |
|---|---|---|
| Auth | OAuth browser flow | x-api-key env var |
| Where it runs | Cursor, Claude Desktop | Your server, CI, cron |
| Tool discovery | Automatic | You import typed methods |
| Billing account | Developer who OAuth'd | API key owner |
Copy field paths verbatim from MCP responses into your types. data.profile.metrics.followers in MCP is the same path in SDK result.value.data.
Do not deploy MCP inside a server runtime — use REST. For no-code workflows with API keys, see n8n integration.
Billing and credits
- Endpoint tools (MCP or REST): billed per completed lookup — see Credits.
nl_ask_postrouting: 0 credits;meta.creditsChargedreflects the nested lookup only.not_found/privateon HTTP 200: still charged — the lookup completed.- Pre-send validation errors,
lookup_failed,503: not charged. docs_search,docs_read,auth_whoami,billing_balance_get: no lookup credits.- 100 free credits on signup — Pricing.
Agent loop math: 5 creators × 3 platforms = 15 credits if every lookup completes. Add pagination credits per page. Call billing_balance_get before fan-out.
Troubleshooting
401 on every MCP call
Token expired or OAuth incomplete. Open MCP settings → reconnect → finish browser sign-in.
OAuth redirect loop
Complete sign-in at app.socialfetch.dev, then click Approve to return to your client. Disable aggressive popup blockers for the OAuth window.
402 insufficient_credits
Top up in Credits & billing. Teach the agent to stop on 402 instead of retrying.
Empty tool list after connect
Restart the client. Check mcp.json URL is exactly https://api.socialfetch.dev/mcp (no trailing path).
Agent keeps retrying not_found
Add a rule: "lookupStatus: not_found is a valid outcome — never retry." See Errors.
Wrong platform routed from nl_ask_post
Be specific: "TikTok followers for @handle" not "followers for handle". Pin the typed tool once you know the route.
MCP works but SDK returns different numbers
Point-in-time snapshots differ. Compare requestId in Playground vs your logs.
stdio client cannot connect
Use npx mcp-remote https://api.socialfetch.dev/mcp as a bridge.
FAQ
Do MCP tool calls cost credits?
Yes for endpoint tools, same as REST. docs_search, docs_read, auth_whoami, and billing_balance_get are free.
Do I paste an API key into MCP config?
No — OAuth for MCP; API keys for REST/SDK from API keys.
What should my agent read first?
llms.txt, then Quickstart and endpoint reference pages. Use MCP docs tools for parameters.
When should I use nl_ask_post instead of a typed tool?
When you do not know the route yet. After you have routedOperation, switch to the explicit tool.
Why did my agent retry not_found five times?
not_found is HTTP 200 with a completed lookup. Add explicit stop conditions in your prompt or orchestrator.
Can I use MCP in production?
No — MCP targets dev agents. Ship with the SDK or REST and an API key.
Next steps: MCP integration · AI agents use case · llms.txt · Playground · Pricing