# MCP server

> Give Claude Desktop, Claude Code or any MCP client read-only access to the API, with your key kept in an environment variable.

The Belfort Data MCP server gives an AI agent the API's routes as tools. It runs on your machine over stdio, calls the public API with your key, and never touches a database. Every tool is read-only.

:::caution[Not on npm yet]
The server isn't published as a package yet. The steps below run it from a copy of the Belfort Data API source, which needs Node.js 22 or later and pnpm. During the pilot, ask Belfort for access.
:::

## 1. Install

In your copy of the source:

```bash
pnpm install
```

The server reads two environment variables:

| Variable | Needed | Default |
|---|---|---|
| `BELFORT_API_KEY` | For every tool except `status` | |
| `BELFORT_API_URL` | No | `https://belfort-data-api.vercel.app`. Must be `https`, except for `localhost`. |

The key is sent as `X-API-Key`. The server never logs it and never puts it in a tool's output.

## 2. Add it to your client

Replace `/absolute/path/to/belfort-data-api` with where your copy lives.

**Claude Code**

```bash
claude mcp add --transport stdio belfort-data \
  --env BELFORT_API_KEY="$BELFORT_API_KEY" \
  -- pnpm --dir /absolute/path/to/belfort-data-api exec tsx mcp/index.ts
```

Then run `claude mcp list` to check it connected.

**Claude Desktop**

Open Claude Desktop's settings, choose **Developer**, then **Edit Config**, and add the server to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "belfort-data": {
      "command": "pnpm",
      "args": ["--dir", "/absolute/path/to/belfort-data-api", "exec", "tsx", "mcp/index.ts"],
      "env": {
        "BELFORT_API_KEY": "bda_..."
      }
    }
  }
}
```

Restart Claude Desktop. The tools appear under the server's name.

**Other clients**

Any MCP client that runs a local stdio server can use it. Run this command with `BELFORT_API_KEY` set in its environment:

```bash
pnpm --dir /absolute/path/to/belfort-data-api exec tsx mcp/index.ts
```

## Tools

| Tool | Route | Key | Inputs |
|---|---|---|---|
| `status` | `GET /v1/status` | No | None |
| `get_company` | `GET /v1/companies/{id}` | Yes | `id` |
| `get_metrics` | `GET /v1/companies/{id}/metrics` | Yes | `id`, optional `metric` and `frequency` |
| `get_statements` | `GET /v1/companies/{id}/statements` | Yes | `id`, optional `statement`, `form`, `limit`, `cursor` |
| `get_financials` | `GET /v1/companies/{id}/financials` | Yes | `id`, optional `field`, `period`, `limit`, `cursor` |
| `get_segments` | `GET /v1/companies/{id}/segments` | Yes | `id`, optional `axis`, `period_end`, `limit`, `cursor` |
| `get_insider_trades` | `GET /v1/companies/{id}/insider-trades` | Yes | `id`, optional `limit`, `cursor` |
| `get_form13f` | `GET /v1/companies/{id}/form13f` | Yes | `id` (a manager's CIK), optional `limit`, `cursor` |
| `get_holders` | `GET /v1/companies/{id}/holders` | Yes | `id`, optional `period`, `limit`, `cursor` |
| `get_ownership` | `GET /v1/companies/{id}/ownership` | Yes | `id`, optional `form`, `limit` |
| `get_filings` | `GET /v1/companies/{id}/filings` | Yes | `id`, optional `limit`, `cursor` |
| `list_earnings_releases` | `GET /v1/companies/{id}/earnings-releases` | Yes | `id`, optional `limit`, `cursor`, `from`, `to` |
| `get_earnings_release` | `GET /v1/companies/{id}/earnings-releases/{accession}` | Yes | `id`, `accession` |
| `get_macro` | `GET /v1/macro/{series}` | Yes | `series` |

The inputs follow the API's parameters exactly; see each [dataset](/datasets/) for the values. An unknown or invalid input is refused before any API call.

## What to expect

- **One call, one page.** A tool returns one page of the API's answer. To read further, call it again with `meta.next_cursor` as `cursor`. A default statements page of four documents is about 45 KB, so ask for what you need.
- **Errors come back as tool errors**, with the API's code and message, including `Retry-After` on a 429 or 503.
- **The caveats travel with the tools.** Each tool's description tells the model that a figure can be withheld, that it can change when a later filing arrives, that `adjustments` explain what we changed, and that this is data, not investment advice.
- **No caching and no guessing.** The server adds nothing to the API's answers. Its rate limits and data gaps are the API's: see [Requests and responses](/requests-and-responses/) and [Known limits](/known-limits/).

---
Source: https://docs.belfortagent.xyz/mcp/
