Skip to main content

cvm-mcp

Python License MCP

An MCP server for the CVM open-data repository (dados.cvm.gov.br) — the Brazilian securities regulator and the source behind the R packages GetDFPData2 and GetFREData.

It gives Claude Code, OpenCode, Cursor, VS Code, Codex, Gemini CLI and any other MCP client one interface to:

  • annual and quarterly financial statements (DFP / ITR)
  • the Formulário de Referência (FRE, 36 corporate tables)
  • fund NAVs, flows, portfolios and credit-fund reports
  • insider trading, governance, public offerings and sanctioning proceedings
  • ad-hoc SQL over everything, via DuckDB

15 datasets, 111 tables, 34 tools. Everything runs locally and read-only; data is downloaded on demand and cached on disk.

This server consolidates the earlier cvm-dfp-mcp and cvm-fre-mcp servers and is a strict superset of both.

Contents

Requirements

  • Python 3.10+ — uv installs and manages it for you.
  • uv — the only prerequisite.
  • Network access to dados.cvm.gov.br.
  • Disk space for the cache. It is lazy: nothing is downloaded until you ask for it. A full DFP + FRE history is a few GB; fi_cda is the heavy one (~270 MB uncompressed per month).

Install uv:

# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

Verify with uv --version.

Quick start

The package is not on PyPI yet, so install it from the GitHub repository.

Run without installing (best for trying it out and for client configs):

uvx --from git+https://github.com/msperlin/cvm-mcp.git cvm-mcp

This starts a stdio MCP server and waits for a client. Seeing no output is expected; press Ctrl+C to stop it.

Install a persistent cvm-mcp command (optional):

uv tool install git+https://github.com/msperlin/cvm-mcp.git
cvm-mcp

If cvm-mcp is not found after installing, run uv tool update-shell and restart your terminal.

From source (for development):

git clone https://github.com/msperlin/cvm-mcp.git
cd cvm-mcp
uv sync
uv run cvm-mcp

Client setup

All configurations below run the server over stdio. They use uvx, which resolves and caches the package on first use.

GUI clients and PATH: Claude Desktop, Cursor and VS Code often do not inherit your shell PATH. If the server fails to start with “command not found”, run which uvx (macOS/Linux) or where uvx (Windows) and use that absolute path as command — commonly ~/.local/bin/uvx. Alternatively, uv tool install and use the absolute path to cvm-mcp.

Claude Code

Add it from the CLI, scoped to your user (available in every project):

claude mcp add --transport stdio --scope user cvm-mcp -- \
  uvx --from git+https://github.com/msperlin/cvm-mcp.git cvm-mcp

Check the connection:

claude mcp list

Or commit a project-scoped .mcp.json to the repository root:

{
  "mcpServers": {
    "cvm-mcp": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/msperlin/cvm-mcp.git",
        "cvm-mcp"
      ],
      "timeout": 600000
    }
  }
}

timeout is in milliseconds and applies per tool call. The first CVM download can take a while; 10 minutes is a safe ceiling.

OpenCode

OpenCode V2 configures servers under mcp.servers. Add it globally with the CLI:

opencode mcp add cvm-mcp --global -- \
  uvx --from git+https://github.com/msperlin/cvm-mcp.git cvm-mcp

Check it with opencode mcp list (or /mcps inside OpenCode).

Or edit ~/.config/opencode/opencode.json (global) or opencode.json (project):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "servers": {
      "cvm-mcp": {
        "type": "local",
        "command": [
          "uvx",
          "--from",
          "git+https://github.com/msperlin/cvm-mcp.git",
          "cvm-mcp"
        ]
      }
    }
  }
}

The repository also ships a ready-to-copy opencode.example.json.

OpenCode V1 used server names directly under mcp; V2 uses mcp.servers.

Claude Desktop

Edit the Claude Desktop config file:

OS Path
macOS ~/Library/Application Support/Claude/claude_desktop_config.json
Windows %APPDATA%\Claude\claude_desktop_config.json
Linux ~/.config/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "cvm-mcp": {
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/msperlin/cvm-mcp.git",
        "cvm-mcp"
      ]
    }
  }
}

Quit Claude Desktop completely and reopen it. The server appears under Connectors / the tools menu.

Cursor

Create ~/.cursor/mcp.json for all projects, or .cursor/mcp.json in a project:

{
  "mcpServers": {
    "cvm-mcp": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/msperlin/cvm-mcp.git",
        "cvm-mcp"
      ]
    }
  }
}

Reload the window if the server does not appear under Customize → MCP.

VS Code / GitHub Copilot

Create .vscode/mcp.json in the workspace:

{
  "servers": {
    "cvm-mcp": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/msperlin/cvm-mcp.git",
        "cvm-mcp"
      ]
    }
  }
}

VS Code uses the servers key. Portable .mcp.json files (Claude Desktop, Cursor, Cline, etc.) use mcpServers instead — do not mix the two.

You can also run MCP: Add Server from the Command Palette and choose Command (stdio) with:

uvx --from git+https://github.com/msperlin/cvm-mcp.git cvm-mcp

Codex CLI

Add to ~/.codex/config.toml (or .codex/config.toml in a trusted project):

[mcp_servers.cvm-mcp]
command = "uvx"
args = ["--from", "git+https://github.com/msperlin/cvm-mcp.git", "cvm-mcp"]
startup_timeout_sec = 30
tool_timeout_sec = 600

Codex reads server instructions and exposes the tools automatically. Use /mcp in a Codex session to inspect the connection.

Gemini CLI

Add to ~/.gemini/settings.json (user) or .gemini/settings.json (project):

{
  "mcpServers": {
    "cvm-mcp": {
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/msperlin/cvm-mcp.git",
        "cvm-mcp"
      ],
      "timeout": 600000
    }
  }
}

Then run /mcp inside Gemini CLI to check the connection. timeout is in milliseconds.

Continue

Create .continue/mcpServers/cvm-mcp.yaml:

name: CVM MCP
version: 0.0.1
schema: v1
mcpServers:
  - name: CVM
    type: stdio
    command: uvx
    args:
      - "--from"
      - "git+https://github.com/msperlin/cvm-mcp.git"
      - "cvm-mcp"

Continue can also import the JSON block from the Other MCP clients section into .continue/mcpServers/.

Other MCP clients

Most clients accept a stdio server in this shape:

{
  "mcpServers": {
    "cvm-mcp": {
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/msperlin/cvm-mcp.git",
        "cvm-mcp"
      ]
    }
  }
}

If your client asks for a single command line:

uvx --from git+https://github.com/msperlin/cvm-mcp.git cvm-mcp

Windows clients that cannot find uvx can use the executable installed by uv tool install directly, e.g. C:\Users\<you>\.local\bin\cvm-mcp.exe.

Example prompts

Once connected, ask in natural language:

  • “What were Vale's revenue, EBIT and net debt in 2024? Cite the CVM/DFP accounts.”
  • “Compare the last five years of ROE, net margin and net debt/EBITDA for Petrobras, Vale and Itaú.”
  • “Show the board composition, compensation and shareholders of Banco do Brasil in the latest Formulário de Referência.”
  • “Which insiders bought or sold WEG shares in the last six months?”
  • “List the largest FIDCs by net asset value in the latest month, with delinquency and credit segments.”
  • “How much did Brazilian companies raise in public offerings in 2024, by asset type and lead underwriter?”
  • “Find sanctioning proceedings mentioning insider trading since 2023.”
  • “Load DFP 2024 and run a SQL query joining the income statement with the company registry.”

The server is instructed to cite the dataset and reference period and never to invent figures.

Datasets

Domain Datasets Coverage
Companies dfp, itr, fre (36 tables), fca, vlmo (insider trading), cgvn (governance) DFP/ITR/FRE 2010+; FCA/VLMO/CGVN 2018+
Funds fi_inf_diario, fi_cda, fi_cad, fii_inf_mensal, fidc_inf_mensal (18 tables), fiagro_inf_mensal FI daily 2021-01+; CDA 2023-01+; FII 2016+; FIDC 2025-01+; FIAGRO 2025-05+
Offerings oferta (ICVM 400 / RCVM 160) 1988+
Enforcement sancionador (PAS) current
Registry cad_cia_aberta current

Use list_datasets from a client to see the exact table names and view names. describe_dataset shows columns and coverage; describe_dataset(detail=True) adds units and caveats.

Tools

There are two layers.

Curated tools for the common questions:

Group Tools
Identity search_company, resolve, list_companies, get_tickers
Statements list_account_codes, get_financial_statements, get_account_history, get_statement_summary
Corporate filings list_fre_tables, get_fre_table, get_company_overview, get_shareholders, get_compensation, get_board, get_capital
Insiders & governance get_insider_trades, insider_summary, governance_practices, governance_score
Funds search_fund, get_fund_nav, get_fund_flows, get_fund_portfolio, get_fidc_report, rank_funds
Offerings search_offerings, issuance_volume, league_table

Meta tools support both layers:

Tool Purpose
list_datasets All datasets, tables and DuckDB view names
describe_dataset Columns, cached periods and (with detail=True) column meanings
load_dataset Download/parse a dataset or period without forcing a refresh
cache_status What is cached, per dataset, with sizes
refresh_cache Force a re-download and rebuild
run_query Read-only DuckDB SQL over every cached table

run_query sees tables as <dataset>__<table>, e.g. dfp__dre_con, fi_inf_diario__informe, vlmo__transacoes. Only cached periods exist, so call load_dataset first when you need a specific period.

Configuration

All settings are optional environment variables:

Variable Default Meaning
CVMMCP_CACHE_DIR ~/.cache/cvm-mcp Cache root (downloads + Parquet)
CVMMCP_REFRESH_HOURS 12 Revalidation window for CVM archives; 0 disables revalidation
MCP_TRANSPORT stdio stdio, streamable-http or sse
MCP_HOST 127.0.0.1 Host for the HTTP transports
MCP_PORT 8000 Port for the HTTP transports

Add CVMMCP_CACHE_DIR wherever your client expects environment variables:

{
  "env": {
    "CVMMCP_CACHE_DIR": "/absolute/path/to/cvm-cache"
  }
}

For a long-running HTTP server:

MCP_TRANSPORT=streamable-http MCP_HOST=127.0.0.1 MCP_PORT=8000 cvm-mcp

The HTTP transports have no authentication; bind to localhost or put the server behind a reverse proxy.

Cache

~/.cache/cvm-mcp/
├── downloads/                     raw zips and CSVs, revalidated with If-Modified-Since
│   └── <archive>.meta.json        remote Last-Modified/ETag + last revalidation time
└── parquet/v1/<dataset>/<table>/period=<YYYY|YYYYMM|all>/data.parquet
  • Everything is lazy. The first call for a dataset downloads and parses the CVM archive; later calls read the Parquet partition.
  • CVM rewrites the current month in place, so archives are revalidated every 12 h by default (CVMMCP_REFRESH_HOURS).
  • A 304 Not Modified updates only the sidecar's checked_at; the archive mtime stays put, so the Parquet partition is reused instead of being parsed again.
  • load_dataset populates the cache without forcing a refresh. refresh_cache forces a re-download and rebuild.
  • cache_status reports datasets, periods, partition counts and bytes. To reclaim space, delete ~/.cache/cvm-mcp/parquet (it is rebuilt on demand) or point CVMMCP_CACHE_DIR at a larger disk.

Data notes

  • DFP / ITR keep CVM's uppercase column names. VL_CONTA is the raw value; VL_CONTA_BRL is already scaled by ESCALA_MOEDA and is the number to report.
  • FRE keeps the GetFREData-compatible snake_case schema and key block (cd_cvm, cnpj, nome_companhia, data_referencia, versao, id_documento).
  • Newer datasets (VLMO, CGVN, funds, offerings) are normalized to snake_case and gain a 14-digit cnpj column and a _period column.
  • fi_cda is heavy (~270 MB uncompressed per month). Build one block/period at a time; load_dataset refuses more than three periods of a heavy dataset in one call.

Fund family routing

CVM splits funds by instrument, not by manager, and the tools hide that. get_fund_nav and get_fund_portfolio resolve the class CNPJ in fi_cad, read its tipo_classe and pick the dataset:

Family Series Portfolio
FIF / FAPI fi_inf_diario (daily) fi_cda blocks 1–8
FII fii_inf_mensal (monthly) fii_inf_mensal/ativo_passivo
FIDC fidc_inf_mensal/tab_iv fidc_inf_mensal/tab_ii (credit segments)
FIAGRO fiagro_inf_mensal fi_cda/fie

get_fidc_report adds the credit dashboard (assets, portfolio, PL, delinquency).

Known gaps: FIP is quarterly and is not wired up yet; the tools say so explicitly. FIDC monthly reports start in 2025-01 — 2013–2024 lives in the HIST/ folder with a different layout and is not wired up. FII history starts in 2016.

How it works

The portal has ~1,259 files and ~10 GB of archives, but only about five shapes of data. Each dataset is described declaratively in registry.py — URL pattern, period granularity, tables inside the archive, normalizer — and the store turns every (dataset, table, period) into one Parquet partition. Adding a dataset is a data change, not a code change.

src/cvm_mcp/
├── app.py             MCP application object + server instructions
├── registry.py        declarative catalog of datasets and tables
├── fetch.py           download, revalidation, metadata sidecars, file locks
├── store.py           Parquet partitions + DuckDB views + read-only SQL
├── normalize.py       Latin-1 reader, header cleaning, CNPJ, type inference
├── identity.py        CNPJ ↔ cd_cvm ↔ ticker resolution
├── schema_dfp.py      canonical DFP/ITR schema
├── catalog_dfp.py     curated chart of accounts and roles
├── catalog_fre.py     the 36 FRE tables
├── fre_normalize.py   FRE normalization
├── data_dictionary.py curated column descriptions, units and caveats
├── tools_*.py         the MCP tools, one module per domain
└── server.py          entry point

Each archive is downloaded once and revalidated with If-Modified-Since; downloads are guarded by a cross-process file lock, and SQL is restricted to a single read-only SELECT / WITH over the cached views.

Development

git clone https://github.com/msperlin/cvm-mcp.git
cd cvm-mcp
uv sync

uv run pytest -m "not network"      # fast, offline
uv run pytest -m network            # hits dados.cvm.gov.br
uv run python scripts/smoke_mcp.py  # end-to-end stdio smoke test

To run the working tree instead of the GitHub package in a client config, point the command at the checkout:

{
  "command": "uv",
  "args": ["run", "--directory", "/absolute/path/to/cvm-mcp", "cvm-mcp"]
}

Releasing

Publishing happens on GitHub, not from a laptop, through PyPI trusted publishing (OIDC), so no API token is stored anywhere.

  1. Bump version in pyproject.toml and commit it.

  2. Tag the commit with a matching v prefix and push it:

    git tag v0.1.0
    git push origin v0.1.0
    
  3. Draft a GitHub release for that tag and publish it.

The publish workflow in .github/workflows/publish.yml then runs the offline test suite, builds the sdist and wheel, checks the metadata, verifies the tag matches the version, and uploads to PyPI. Re-running it manually (workflow_dispatch) rebuilds and re-uploads the current version, which PyPI rejects if the files already exist — so only do that after a failed release.

One-time setup (already required before the first upload): on PyPI, add a pending publisher for project cvm-mcp with owner msperlin, repository cvm-mcp, workflow publish.yml, and environment pypi. The matching environment is declared in the workflow.

Troubleshooting

Symptom Fix
uvx: command not found Install uv, or use the absolute path from which uvx / where uvx. GUI clients often do not inherit PATH.
Server starts but no tools appear Check the client's MCP panel: claude mcp list, opencode mcp list, /mcp in Gemini/Codex/Cursor/VS Code. Restart the app after editing JSON.
First tool call is slow The server is downloading and parsing a CVM archive. Use load_dataset for the exact period you need, and raise the client's tool timeout. fi_cda is the heaviest dataset.
run_query says “no data cached” Only cached periods are visible to SQL. Call load_dataset (e.g. dataset="dfp", period="2024") or a curated tool first.
The latest month looks stale CVM rewrites the current month in place. Call refresh_cache for that dataset/period.
Disk is filling up Check cache_status; delete ~/.cache/cvm-mcp/parquet (rebuilt on demand) or move CVMMCP_CACHE_DIR.
CVM returned HTTP 5xx / timeouts CVM is temporarily unavailable; the server retries 429/500/502/503/504 with backoff. Check connectivity to dados.cvm.gov.br.
Unknown dataset/table Call list_datasets and describe_dataset; ids and table slugs are exact.

License

MIT. CVM data is public; see the CVM open-data portal for the original terms and update policy.

Metadata

Release files for cvm-mcp 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cvm-mcp 0.1.0
File Size Uploaded Provenance Actions
cvm_mcp-0.1.0.tar.gz 78.0 kB With provenance Details for cvm_mcp-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for cvm-mcp 0.1.0
File Interpreter ABI Platform Actions
cvm_mcp-0.1.0-py3-none-any.whl Python 3 none any Details for cvm_mcp-0.1.0-py3-none-any.whl

Total release size: 160.8 kB

Release files / cvm_mcp-0.1.0.tar.gz

Download URL cvm_mcp-0.1.0.tar.gz
Size 78.0 kB
Tags Source
SHA-256 checksum
How to use checksums
bdf226bb0ec1cec2ceff58356dd0c1c142208af9c03600b553e384f92febae5b
BLAKE2b-256 checksum
How to use checksums
c87cdea54a400433ae5ec4561eae4f25f71f1450b5fbdb3c0b8c65fa0404366d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.

Transparency log

Release files / cvm_mcp-0.1.0-py3-none-any.whl

Download URL cvm_mcp-0.1.0-py3-none-any.whl
Size 82.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
50606c045656cbfeb1d8f5a1e7205780b0101059c543cbbcfe8f63a6ee959f23
BLAKE2b-256 checksum
How to use checksums
c0121f158aae9392a1ec0e2696eddc6368b60406f7bd68a2174fbac3b56705bc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.

Transparency log

Security for cvm-mcp 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for cvm_mcp-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page