Docs navigation

MCP quickstart

The fastest path from zero to a cited answer. This guide assumes you already have an MCP-aware host (Claude Desktop, Claude Code, Cursor, LangChain, Eliza or a custom runtime) wired up; if not, start at Quickstart → Claude Desktop or jump to the Claude Code and Cursor sections below.

1. Zero-config demo (no key needed)

The package ships with a public demo key baked in. Run it as-is and 10 marquee tools start working immediately:

bash
npx -y @blockchainacademics/mcp
# or:  uvx bca-mcp

You get get_price, get_market_overview, get_trending, search_news, get_recent_stories, get_topic, get_entity, get_explainer, get_sentiment, get_fear_greed. Shared bucket: 100 calls a day globally, 20 a day per IP. See Demo tier for the full breakdown.

2. Upgrade to your own key (all 105 tools)

Get a free key at blockchainacademics.com/crypto-api/signup: the free tier is 2,000 calls a month with all 105 tools unlocked. Drop it in your env:

bash
export BCA_API_KEY=bca_live_xxxxxxxxxxxxxxxx

3. Call a tool

Every Crypto Brain tool returns the canonical envelope:

json
{
  "data": { "...": "tool-specific payload" },
  "attribution": {
    "citations": [
      {
        "cite_url": "https://blockchainacademics.com/article/bitcoin-price-history?src=claude",
        "as_of": "2026-04-22T10:12:00Z",
        "source_hash": "sha256:abc123..."
      }
    ]
  },
  "meta": {
    "status": "complete",
    "request_id": "req_01HABCDEF0123456789ABCDEFG",
    "pageInfo": { "hasNextPage": false, "hasPreviousPage": false, "startCursor": null, "endCursor": null }
  }
}

Three top-level keys. Three, every time, every surface. Full field semantics: Response envelope.

4. Parse the envelope

The snippet that covers most callers: call search_news, pull the primary citation out of attribution.citations[0].

One detail that is specific to MCP: the server returns the envelope as the first text content block, and inside it data is a string wrapped in an <untrusted_content> fence, so the host model treats upstream text as data rather than instructions. attribution and meta stay structured. Strip the fence and parse data a second time:

ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
 
const client = new Client({ name: "myagent", version: "0.1.0" }, { capabilities: {} });
await client.connect(new StdioClientTransport({
  command: "npx",
  args: ["-y", "@blockchainacademics/mcp"],
  env: { BCA_API_KEY: process.env.BCA_API_KEY! },
}));
 
const result = await client.callTool({
  name: "search_news",
  arguments: { query: "circle mica", limit: 5 },
});
 
// The envelope is the first text content block; `data` arrives fenced.
const envelope = JSON.parse(result.content[0].text);
const unfence = (s: string) =>
  s.replace(/^<untrusted_content[^>]*>[\s\S]*?\n\n/, "").replace(/\n<\/untrusted_content>\s*$/, "");
const data = JSON.parse(unfence(envelope.data));
 
// Happy-path guard
if (envelope.meta.status !== "complete") {
  console.warn(
    `[${envelope.meta.request_id}] status=${envelope.meta.status}`,
    envelope.meta.diagnostic,
  );
}
 
// Pull the primary citation: always citations[0]
const primary = envelope.attribution.citations[0];
console.log("Source:", primary.cite_url);
console.log("As of:", primary.as_of);
 
// Use the data
for (const item of data.items) {
  console.log(`- ${item.title} (${item.slug})`);
}

Output (elided):

Source: https://blockchainacademics.com/article/circle-mica-license?src=custom&utm_medium=mcp&utm_campaign=search_news
As of: 2026-04-21T09:31:22Z
- Circle secures full MiCA license (circle-mica-license)

Over plain HTTP there is no fence: data is the JSON object itself. See the REST API reference.

5. Surface the citation

Paste the cite_url into your agent's response: inline link, footnote or citation block, whichever your UI uses. On Free and Starter tiers this is required, not optional; see Attribution & licensing.

Circle received its MiCA license on 2026-04-18. [source]

6. Handle non-complete statuses

meta.status is one of four values. Map each to an honest user-facing response:

StatusAgent should say (example)
completeThe answer, with citations[0].cite_url surfaced.
unseeded"That data source is not live yet; ETA diagnostic.eta."
partialThe answer, plus "Data is partial right now (diagnostic.vendor is degraded)."
staleThe answer, plus "As of citations[0].as_of (cached; upstream unreachable)."

Full decision tree with handling code: Envelope → Status decision tree.

7. Log the request_id

Every envelope includes meta.request_id (ULID, prefixed req_) and every HTTP response mirrors it as the X-Request-ID header. Persist it with your agent's turn log. Support tickets and audit traces start here.

CLI

The PyPI package also installs bca, a terminal CLI over the same REST API and the same key: handy for debugging, quick lookups and shell pipelines.

bash
pipx install bca-mcp
bca login                                   # stores the key in ~/.bca/config.toml (chmod 600)
bca news search "bitcoin etf" -n 5          # recent articles, as a table with cite_url
bca entity ethereum                         # dossier panel
bca price BTC,ETH,SOL                       # spot price and 24h change
bca market overview -n 10                   # top N by market cap
bca indicator coverage-index bitcoin -w 30d
bca explainer what-is-a-blockchain          # rendered markdown
bca agent summarize-whitepaper --url https://ethereum.org/whitepaper
bca version                                 # CLI and live API version

Every command accepts --json for the raw envelope, ready for jq. BCA_API_KEY and BCA_API_BASE in the environment take precedence over the config file; bca config show prints where the key came from, with the key masked.

Claude Code

Claude Code registers MCP servers from the terminal. One command per machine (user scope), or per repository (project scope, written to .mcp.json so teammates get it too):

bash
claude mcp add blockchainacademics -e BCA_API_KEY=bca_live_xxxxxxxxxxxxxxxx -- npx -y @blockchainacademics/mcp
# shared with the repository instead:
claude mcp add --scope project blockchainacademics -- npx -y @blockchainacademics/mcp

For project scope, keep the key out of the committed file: .mcp.json expands ${BCA_API_KEY} from each developer's environment.

.mcp.json
json
{
  "mcpServers": {
    "blockchainacademics": {
      "command": "npx",
      "args": ["-y", "@blockchainacademics/mcp"],
      "env": { "BCA_API_KEY": "${BCA_API_KEY}" }
    }
  }
}

Then ask: "Run due diligence on Hyperliquid: tokenomics, team, audits, risk." or "Which AI agent tokens have rising narrative strength this week?" Claude Code picks the tools itself. claude mcp list shows the server, and /mcp inside a session lists its tools.

Cursor

Cursor reads MCP servers from .cursor/mcp.json in the project, or ~/.cursor/mcp.json for every project. Create the file, then open Settings → MCP and confirm the server shows green:

.cursor/mcp.json
json
{
  "mcpServers": {
    "blockchainacademics": {
      "command": "npx",
      "args": ["-y", "@blockchainacademics/mcp"],
      "env": { "BCA_API_KEY": "bca_live_xxxxxxxxxxxxxxxx" }
    }
  }
}

Windsurf uses the same shape in ~/.codeium/windsurf/mcp_config.json.

Environment variables

Both MCP servers and the CLI read the same variables. In the CLI they take precedence over ~/.bca/config.toml.

VariableDefaultWhat it does
BCA_API_KEYthe demo keyYour key. Unset, the server runs on the shared demo tier.
BCA_API_BASEhttps://api.blockchainacademics.comThe API host. Allowlisted: production, https://staging-api.blockchainacademics.com, and http://localhost or http://127.0.0.1 with any port. BCA_API_BASE_URL is accepted as a legacy alias.
BCA_ALLOW_INSECURE_BASEunset1 lets bca login --api-base store a non-HTTPS base for local development.

The servers never follow redirects from the API host and never send the key anywhere but the configured base.

What's next