Cracked

One key for 63,577 agent tools: scrapers, search, data, AI models. Pay per call, failed runs free. MCP + REST.

Documentation

Updated September 2, 2026 · tested with MCP protocol 2025-06-18 · by Cracked Engineering

MCP server

Cracked exposes a remote MCP server over Streamable HTTP at https://cracked.ai/mcp. Two ways to authenticate: OAuth 2.1 (sign in with your Cracked account from Claude.ai, Claude Desktop, ChatGPT, Cursor) or a bearer API key header (Claude Code, Codex, OpenCode, scripts).

Tools exposed

The generic tools are always registered. On top of them, every smart-run capability is available as its own typed tool (capability id with underscores: instagram-profile becomes instagram_profile), so a client can call weather_forecast({latitude, longitude}) directly instead of discovering and inspecting first.

ToolArgumentsPurpose
discover_toolsquery, limit?, live_only?Natural-language search with price, health and availability.
inspect_toolprovider, endpointSchema, price, health, docs.
run_toolprovider, endpoint, input, wait?Execute and bill. wait:false for long scrapers.
run_capabilitycapability, input, wait?Smart run by capability id; falls back across providers.
list_capabilitiesid?Capability ids, input schemas, ranked candidates. Free.
get_runrun_id, wait_seconds?Poll an async run.
get_balanceWorkspace balance in USD.
create_checkout_linkamount_usd, ref?, promo?, success_url?Mint a card payment link to hand to your owner. Free until paid.
recruit_agentagent_name?, task?Onboarding prompt for another agent with your referral link embedded (register, first run, claim flow). Free.
<capability>the capability's input fieldsOne tool per capability, e.g. web_search, instagram_profile, weather_forecast. Returns the normalized output first, then a compact run summary (routedTo, status, cost, runId).

Tool sets

164 capability tools is more than some clients list comfortably, so the set is chosen with a tools query parameter on the server URL. Everything else (auth, OAuth metadata, billing) is identical.

URLToolsUse when
https://cracked.ai/mcp or ?tools=topgeneric + 40 most-used capabilitiesDefault. Instagram, TikTok, YouTube, X, LinkedIn, Google Maps, Amazon, web search and scrape, enrichment, weather, stocks, crypto, image and speech generation, transcription, LLM chat.
https://cracked.ai/mcp?tools=allgeneric + all 164 capabilitiesAgents that pick tools by name and schema and can hold a long tool list.
https://cracked.ai/mcp?tools=coregeneric onlyClients with small tool budgets; use run_capability and run_tool.

The OAuth protected-resource identifier is https://cracked.ai/mcp for all three; clients connecting to /mcp?tools=all discover the same metadata at /.well-known/oauth-protected-resource/mcp and sign in once.

Example tools/list entry for a capability tool:

{
  "name": "weather_forecast",
  "title": "Weather forecast",
  "description": "Current conditions plus daily forecast for coordinates. Use geocode first for a city name. Price: from $0.002/call via Open-Meteo Weather + $0.001 platform fee, billed to the workspace balance. Smart run: Cracked picks the best live tool for \"weather-forecast\", maps the input and falls back to the next provider on failure (1 live).",
  "inputSchema": { "type": "object", "properties": { "latitude": { "type": "number", "description": "Latitude" }, "longitude": { "type": "number", "description": "Longitude" }, "days": { "type": "number", "description": "Forecast days 1-16" }, "units": { "type": "string", "description": "celsius or fahrenheit" } }, "required": ["latitude", "longitude"] }
}

Calling it returns the output first, then a compact run summary:

{
  "output": { "timezone": "America/Chicago", "current": { "temperature_2m": 91.6, "relative_humidity_2m": 41, ... }, "daily": { ... } },
  "run": { "capability": "weather-forecast", "status": "COMPLETED", "routedTo": { "provider": "open-meteo", "endpoint": "/forecast" }, "httpStatus": 200, "runId": "b637d650-...", "totalUsd": 0.003, "durationMs": 1107, "attempts": 1, "fallbackUsed": false, "tried": [ ... ] },
  "hints": { "capability": "GET /v1/capabilities?id=weather-forecast" }
}

Claude.ai and Claude Desktop (OAuth)

Settings → Connectors → Add custom connector. Name Cracked, URL https://cracked.ai/mcp (or https://cracked.ai/mcp?tools=all). Claude discovers our OAuth server, registers itself, sends you to the Cracked consent screen, and you pick the workspace to bill. Tokens last 30 days and refresh automatically. Revoke from API keys.

ChatGPT

Settings → Connectors → Create. Connection URL https://cracked.ai/mcp (or https://cracked.ai/mcp?tools=all to expose every capability), authentication OAuth. Same consent flow. ChatGPT lists each capability as a separate action, so the default set keeps the connector page readable.

Claude Code

# default: generic tools + 40 most-used capabilities as typed tools
claude mcp add --transport http cracked https://cracked.ai/mcp --header "Authorization: Bearer ck_live_..."
# every capability as a tool
claude mcp add --transport http cracked "https://cracked.ai/mcp?tools=all" --header "Authorization: Bearer ck_live_..."
# or let Claude Code run the OAuth flow:
claude mcp add --transport http cracked https://cracked.ai/mcp

Cursor

{ "mcpServers": { "cracked": { "url": "https://cracked.ai/mcp?tools=all", "headers": { "Authorization": "Bearer ck_live_..." } } } }

One-click: cracked.ai/install has a Cursor deep link for the default set and one for tools=all.

Codex

codex mcp add cracked --url https://cracked.ai/mcp --header "Authorization: Bearer ck_live_..."

OpenCode

{ "mcp": { "cracked": { "type": "remote", "url": "https://cracked.ai/mcp", "enabled": true, "headers": { "Authorization": "Bearer ck_live_..." } } } }

Native tools for the OpenAI and Anthropic SDKs (no MCP)

The same tool definitions are served as plain JSON at GET https://cracked.ai/v1/capabilities/tools (free, no auth, CORS *, cached one hour). Paste the array into tools=[...], then execute each call the model makes with POST https://cracked.ai/v1/run {"capability", "input"}. The tool name is the capability id with underscores; /v1/run accepts either spelling.

QueryReturns
?format=openai (default)[{ type: "function", function: { name, description, parameters } }]
?format=anthropic[{ name, description, input_schema }]
?format=mcp[{ name, title, description, inputSchema }], what /mcp lists
&set=top (default) / &set=all40 most-used capabilities / all 164

OpenAI SDK (Python)

import json, os, requests
from openai import OpenAI

CRACKED = "https://cracked.ai"
H = {"Authorization": f"Bearer {os.environ['CRACKED_API_KEY']}", "content-type": "application/json"}
tools = requests.get(f"{CRACKED}/v1/capabilities/tools?format=openai&set=top").json()

def run_capability(name, arguments):
    r = requests.post(f"{CRACKED}/v1/run", headers=H, json={"capability": name, "input": arguments}, timeout=300).json()
    return r.get("output") if r.get("status") == "COMPLETED" else {"error": r.get("status"), "detail": r.get("providerResponse"), "attempts": r.get("attempts")}

client = OpenAI()
messages = [{"role": "user", "content": "How many followers does @nike have on Instagram, and what is the weather in Austin?"}]
while True:
    resp = client.chat.completions.create(model="gpt-4.1", messages=messages, tools=tools)
    msg = resp.choices[0].message
    messages.append(msg)
    if not msg.tool_calls:
        print(msg.content); break
    for call in msg.tool_calls:
        out = run_capability(call.function.name, json.loads(call.function.arguments))
        messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(out)})

Anthropic SDK (Python)

import json, os, requests
import anthropic

CRACKED = "https://cracked.ai"
H = {"Authorization": f"Bearer {os.environ['CRACKED_API_KEY']}", "content-type": "application/json"}
tools = requests.get(f"{CRACKED}/v1/capabilities/tools?format=anthropic&set=top").json()

def run_capability(name, arguments):
    r = requests.post(f"{CRACKED}/v1/run", headers=H, json={"capability": name, "input": arguments}, timeout=300).json()
    return r.get("output") if r.get("status") == "COMPLETED" else {"error": r.get("status"), "detail": r.get("providerResponse"), "attempts": r.get("attempts")}

client = anthropic.Anthropic()
messages = [{"role": "user", "content": "How many followers does @nike have on Instagram, and what is the weather in Austin?"}]
while True:
    resp = client.messages.create(model="claude-opus-5", max_tokens=16000, tools=tools, messages=messages)
    messages.append({"role": "assistant", "content": resp.content})
    if resp.stop_reason != "tool_use":
        print(next(b.text for b in resp.content if b.type == "text")); break
    results = []
    for block in resp.content:
        if block.type == "tool_use":
            out = run_capability(block.name, block.input)
            results.append({"type": "tool_result", "tool_use_id": block.id, "content": json.dumps(out)})
    messages.append({"role": "user", "content": results})

Anthropic SDK (TypeScript)

import Anthropic from "@anthropic-ai/sdk";

const CRACKED = "https://cracked.ai";
const H = { Authorization: \`Bearer ${process.env.CRACKED_API_KEY}\`, "content-type": "application/json" };
const tools = (await (await fetch(\`${CRACKED}/v1/capabilities/tools?format=anthropic&set=top\`)).json()) as Anthropic.Tool[];

async function runCapability(name: string, input: unknown) {
  const r = await (await fetch(\`${CRACKED}/v1/run\`, { method: "POST", headers: H, body: JSON.stringify({ capability: name, input }) })).json();
  return r.status === "COMPLETED" ? r.output : { error: r.status, detail: r.providerResponse, attempts: r.attempts };
}

const client = new Anthropic();
const messages: Anthropic.MessageParam[] = [{ role: "user", content: "Top 5 news stories about peptides this week, with URLs." }];
for (;;) {
  const resp = await client.messages.create({ model: "claude-opus-5", max_tokens: 16000, tools, messages });
  messages.push({ role: "assistant", content: resp.content });
  if (resp.stop_reason !== "tool_use") { console.log(resp.content.find((b) => b.type === "text")?.text); break; }
  const results: Anthropic.ToolResultBlockParam[] = [];
  for (const block of resp.content) if (block.type === "tool_use") results.push({ type: "tool_result", tool_use_id: block.id, content: JSON.stringify(await runCapability(block.name, block.input)) });
  messages.push({ role: "user", content: results });
}

Long scrapers: send "wait": false to /v1/run, get HTTP 202 with a runId, then poll GET /v1/runs/{runId}?wait=30. Non-2xx runs are never billed. See Smart run for the routing rules and the API reference for every field.

OAuth details

  • Discovery: https://cracked.ai/.well-known/oauth-authorization-server and https://cracked.ai/.well-known/oauth-protected-resource/mcp.
  • Dynamic client registration (RFC 7591) at /oauth/register; no manual client setup.
  • Authorization code with PKCE (S256), refresh tokens, revocation at /oauth/revoke.
  • Scopes: tools:discover, tools:run, wallet:read, offline_access.
  • An access token is a workspace-scoped key (ck_oauth_…) that also works on the HTTP API.

Verify from the shell

curl -s "https://cracked.ai/mcp?tools=all" -H "Authorization: Bearer ck_live_..." -H "content-type: application/json" -H "accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# call a capability tool directly
curl -s https://cracked.ai/mcp -H "Authorization: Bearer ck_live_..." -H "content-type: application/json" -H "accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"weather_forecast","arguments":{"latitude":30.27,"longitude":-97.74}}}'