English Β· PortuguΓͺs
openfinance-br-mcp
Experimental MCP server for Open Finance Brasil, with a complete mock environment and an evolving implementation toward FAPI-BR integration. Not certified, and not yet validated against real institutions - see VALIDATION.md and the implementation plan in IMPLEMENTATION_PLAN.md before relying on this outside environment=mock.

What it is
An MCP Server that abstracts away the complexity of Open Finance Brasil (FAPI 1.0 Advanced, OAuth2, consent, mTLS) and exposes simple tools to Claude:
Claude β "how much did I spend on food in March?"
Claude uses list_transactions(bank=nubank, categorize=true, date_from=2024-03-01)
Claude β "You spent R$ 847.30 on food in March..."
Supported banks
Mock adapters are implemented for the ten institutions below - each returns realistic, in-memory sample data with zero credentials or network access, and is the primary way to explore this project today. Real (non-mock) support is experimental: it has not been exercised against any bank's actual sandbox or production environment, is not FAPI-BR certified, and several endpoints/paths are still being brought in line with the official OpenAPI specs (tracked in IMPLEMENTATION_PLAN.md).
| Bank | ISPB | Mock adapter | Real integration |
|---|
| Nubank | 18236120 | β
| experimental, unvalidated |
| Sicoob | 04891850 | β
| experimental, unvalidated |
| Caixa EconΓ΄mica | 00360305 | β
| experimental, unvalidated |
| Banco do Brasil | 00000000 | β
| experimental, unvalidated |
| Bradesco | 60746948 | β
| experimental, unvalidated |
| ItaΓΊ Unibanco | 60701190 | β
| experimental, unvalidated |
| Santander | 90400888 | β
| experimental, unvalidated |
| XP | 33264668 | β
| experimental, unvalidated |
| PicPay | 22896431 | β
| experimental, unvalidated |
| BTG Pactual | 30306294 | β
| experimental, unvalidated |
PIX payment initiation (initiate_pix) and list_pix_keys are currently restricted to environment=mock, the real Open Finance Brasil Payments API journey (dedicated payment consent, signed JWS requests/responses, persistent idempotency) is not yet implemented; see IMPLEMENTATION_PLAN.md, phase P2.
New banks: implement BankAdapter (or subclass DefaultOpenFinanceAdapter) and register it - see "Adding a new bank" below.
| Tool | Description | Fase |
|---|
list_accounts | Lists checking, savings, and prepaid accounts | 2 |
get_balance | Available, blocked, and invested balance | 2 |
list_transactions | Statement with filters and DSPy categorization | 2 |
list_credit_cards | Credit cards and limits | 2 |
get_credit_card_bills | Open and past bills | 2 |
list_pix_keys | Registered PIX keys (mock-only, see below) | 2 |
initiate_pix | Idempotent PIX payment (mock-only, see below) | 3 |
list_investments | Fixed income (CDB, LCI, LCA) | 4 |
start_consent | Starts the FAPI-BR consent/authorization flow | - |
complete_consent | Completes consent after the user authorizes at the bank | - |
check_consent_status | Checks the status of an existing consent | - |
revoke_consent | Revokes an existing consent | - |
Quick start
Prerequisites
- Python 3.12+
- uv installed
git clone https://github.com/brunovicco/openfinance-br-mcp.git
cd openfinance-br-mcp
cp .env.example .env
uv sync
uv run openfinance-mcp
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"openfinance-br": {
"command": "uv",
"args": ["run", "--directory", "/path/to/openfinance-br-mcp", "openfinance-mcp"],
"env": {
"CLIENT_ID": "your_client_id",
"CLIENT_SECRET": "your_client_secret",
"MTLS_ENABLED": "false"
}
}
}
}
Development
uv sync
uv run pytest tests/ -v
uv run ruff check src/ tests/
uv run black src/ tests/
uv run mypy src/
Docker
docker build -t openfinance-br-mcp .
docker compose --profile test up
docker compose up openfinance-mcp
Kubernetes
kubectl create namespace fintech
kubectl apply -f k8s/config-and-secrets.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/ingress.yaml
Runs streamable-http behind 2 replicas, with CLIENT_ID/CLIENT_SECRET/
ANTHROPIC_API_KEY mounted as secret files rather than env vars, and a
shared Redis backend (REDIS_URL) so token/consent state is visible
across replicas.
Architecture
Claude (MCP Client)
β stdio or streamable-http
βΌ
openfinance-br-mcp (MCP Server)
βββ Auth + Consent (FAPI-BR 2.2.0: private_key_jwt, PAR/JAR, PKCE, mTLS)
βββ MCP Tools (12 tools, input validated with Pydantic v2)
β βββ Categorizer (DSPy + Claude for transaction classification)
βββ Bank Adapters (10 banks - extensible)
βββ Directory Client (resolves real bank endpoints from the BCB
Directory of Participants)
β HTTPS/mTLS
βΌ
Open Finance BR (BCB) - Directory of Participants
β
βΌ
Nubank Β· Sicoob Β· Caixa Β· + 100 participating institutions
Design principles
- SOLID: BankAdapter ABC (O/C, LSP), single-responsibility tools, constructor-based DI
- 12-Factor: config via env, stateless, logs to stdout
- Security: mTLS, SecretStr, in-memory tokens, mandatory PKCE
- Idempotency: asyncio.Lock on token refresh, X-Idempotency-Key on PIX
- DSPy: transaction categorization framed as an LLM classification problem
Environment variables
| Variable | Required | Description |
|---|
ENVIRONMENT | β | mock (default, no credentials needed), sandbox, or production |
CLIENT_ID | β οΈ non-mock | Client ID registered with the institution |
CLIENT_SECRET | β οΈ non-mock | Client secret |
PRIVATE_KEY_PATH | β οΈ non-mock | RSA private key for private_key_jwt/JAR signing |
MTLS_CERT_PATH | β οΈ prod | Path to the mTLS certificate |
MTLS_KEY_PATH | β οΈ prod | mTLS private key |
ANTHROPIC_API_KEY | β οΈ DSPy | Required for categorize=true |
REDIS_URL | β | Shares TokenStore/ConsentManager state across replicas |
MCP_TRANSPORT | β | stdio (default) or streamable-http |
LANGFUSE_OTLP_ENDPOINT | β | Enables tracing to Langfuse (with LANGFUSE_PUBLIC_KEY/LANGFUSE_SECRET_KEY) |
LOG_LEVEL | β | INFO, DEBUG, WARNING (default: INFO) |
LOG_FORMAT | β | json or console (default: json) |
See .env.example for the full list.
Adding a new bank
- Create
src/openfinance_br_mcp/adapters/my_bank.py
- Inherit from
DefaultOpenFinanceAdapter (or BankAdapter directly for a fully custom implementation)
- Override
bank_id, and pass base_url/token_endpoint defaults
- Add its ISPB to
directory/client.py's _ISPB_BY_BANK and register the adapter class in context.py
Documentation
- docs/en/authorization.md - the two token universes (MCP client auth vs. FAPI-BR bank auth), and why they can never cross
- CONTRIBUTING.md - dev setup, CI checks, adding a bank adapter
- SECURITY.md - scope, disclaimer, and how to report a vulnerability
- SOURCES.md - specs and RFCs this implementation follows
- VALIDATION.md - what's actually been validated, and what hasn't (no real BCB sandbox run)
- CHANGELOG.md - release history
License
MIT