Agents and MCP
One endpoint, https://intelclaw.org/api/mcp, stateless JSON-RPC 2.0 over HTTP. Any account can create a free API key. Samples and discovery need no key at all; paid data needs a subscription to that listing.
Want client config files instead of raw calls? See For agents.
Standard MCP handshake. Returns server info and the tools capability. No key.
curl: initialize
curl -s "https://intelclaw.org/api/mcp" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"my-agent","version":"1.0"}}}'Lists live listings that expose an MCP tool. Each tool carries its listing slug and niche in _meta, so your agent knows which listing to subscribe to. No key.
curl: tools/list (no key)
curl -s "https://intelclaw.org/api/mcp" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'TypeScript: tools/list
const res = await fetch("https://intelclaw.org/api/mcp", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ jsonrpc: "2.0", id: 2, method: "tools/list" }),
});
const { result } = await res.json();
for (const tool of result.tools) {
// _meta["intelclaw.dev/listing"] is the listing slug to subscribe to
console.log(tool.name, tool._meta?.["intelclaw.dev/listing"]);
}Same entitlement check as the REST API. A paid call without a key returns HTTP 401. A key whose account has no subscription to that listing returns HTTP 403. The result has the data as text in content and as JSON in structuredContent.
curl: tools/call (key + subscription)
curl -s "https://intelclaw.org/api/mcp" -H "Content-Type: application/json" \
-H "Authorization: Bearer $INTELCLAW_KEY" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"your_tool_name","arguments":{"query":"example"}}}'TypeScript: tools/call with error handling
async function callTool(name: string, args: Record<string, unknown>) {
const res = await fetch("https://intelclaw.org/api/mcp", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.INTELCLAW_KEY}`,
},
body: JSON.stringify({ jsonrpc: "2.0", id: 3, method: "tools/call", params: { name, arguments: args } }),
});
const msg = await res.json();
if (msg.error) {
const status = msg.error.data?.httpStatus;
if (msg.error.code === -32029) {
const wait = msg.error.data?.retryAfterSec ?? 60;
throw new Error(`Rate limited. Retry once after ${wait}s.`);
}
if (status === 401) throw new Error("Ask the human for an IntelClaw API key.");
if (status === 403) throw new Error("This listing needs a plan: /checkout?listing=<slug>");
throw new Error(msg.error.message);
}
return msg.result.structuredContent;
}- 401 No API key was sent, or the key was not recognised. Stop and ask the human for an IntelClaw API key (any account can create one free at /dashboard/keys). Retry with Authorization: Bearer im_…. Meanwhile the free sample and discovery reads still work.
- 403 The key is valid, but its account has no subscription to this listing, or a metered plan used its monthly cap. Do not retry. Tell the human which listing needs a plan and link /checkout?listing={slug}. Keep using ?sample=1 if a sample is enough.
- 429 Rate limited. Wait for the Retry-After header (seconds), then retry once. Don't hammer.
Over MCP, 401 and 403 arrive as JSON-RPC error -32001 with data.httpStatus. Rate limits arrive as -32029 with data.retryAfterSec.
Without a key: 60 requests per minute. With a key: 120 requests per minute per listing. Metered plans include 10,000 calls a month; calls past the cap return HTTP 403. The Live Price Feed plan has no monthly cap.