mcp-TesouroDireto
# tesouro-direto-mcp
An MCP server for **Brazilian government bonds (Tesouro Direto)** — historical
prices and yields, current rates, per-maturity statistics and the ANBIMA yield
curve — built for LLM agents.
It is the Python/MCP counterpart of the R package
[`GetTDData`](https://github.com/msperlin/GetTDData): same asset codes, same
parsing rules, same fields. It talks directly to the official Tesouro
Transparente CKAN open data portal, so no R installation is required.
## Why this server
- **Official data, no R dependency.** Downloads `precotaxatesourodireto.csv`
from Tesouro Transparente and reproduces `GetTDData::td_get2()` semantics.
- **Robust downloads.** Retries, validates the CSV header before replacing the
cache, and falls back to a previously valid cache when the portal is down.
- **Local cache.** One download per day, stored in `~/.cache/tesouro-direto-mcp`
(configurable), with an in-memory parsed cache for fast repeated calls.
- **Token-efficient output.** CSV with a short comment header — not thousands
of repetitive JSON records. Long series can be aggregated monthly/yearly.
- **The whole curve.** `get_yield_curve` scrapes ANBIMA's ETTJ and computes
maturity dates with the Brazil/ANBIMA business-day calendar.
- **Agent guidance.** Server instructions, a static bond catalog resource and
an `analyze_bond` prompt.
## Tools
| Tool | What it does |
| --- | --- |
| `list_bond_types` | Bond catalog: code, official name, indexer, coupon, description and aliases. |
| `get_bond_data` | Historical daily prices/yields, filterable by bond family, maturity, dates; optional monthly/yearly means. |
| `get_current_rates` | Latest snapshot of every bond (one row per maturity). |
| `get_bond_stats` | Per-maturity summary: last/mean/min/max yield, dates, observation counts. |
| `get_yield_curve` | ANBIMA real, nominal and implicit-inflation yield curves. |
Resources: `tesouro://catalog/bond-types`. Prompt: `analyze_bond`.
### Output conventions
- `yield_bid` is a **decimal annual rate**: `0.1183` means **11.83% p.a.**
`yield_bid_pct` and the `*_pct` statistics are already in percent.
- `price_bid` is the unit purchase price in **BRL (R$)**.
- `asset_code` is the bond family plus maturity as `DDMMYY`, e.g.
`LTN 010123`, `NTN-B Principal 150835`.
- Data starts in **2005**. Daily series are truncated to the most recent
`max_rows` rows; use `frequency="monthly"` or a narrower range for long
histories.
## Install
Requires Python 3.10+ and [uv](https://docs.astral.sh/uv/).
```sh
git clone https://github.com/msperlin/tesouro-direto-mcp.git
cd tesouro-direto-mcp
uv sync
```
Run over stdio:
```sh
uv run tesouro-direto-mcp
```
Or install it as a standalone tool:
```sh
uv tool install .
tesouro-direto-mcp
```
## Register with OpenCode
Add to `~/.config/opencode/opencode.json` (or a project `opencode.json`):
```jsonc
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"servers": {
"tesouro-direto-mcp": {
"type": "local",
"command": [
"/home/msperlin/GitRepo/mcp-servers/tesouro-direto-mcp/.venv/bin/python",
"-m",
"tesouro_direto_mcp"
]
}
}
}
}
```
Or with `uv`, without hard-coding a virtualenv path:
```jsonc
"command": ["uv", "run", "--directory", "/path/to/tesouro-direto-mcp", "tesouro-direto-mcp"]
```
## Register with Claude Desktop
```jsonc
{
"mcpServers": {
"tesouro-direto-mcp": {
"command": "uvx",
"args": ["--from", "git+https://github.com/msperlin/tesouro-direto-mcp", "tesouro-direto-mcp"]
}
}
}
```
## Examples
Ask the agent:
> What are the current NTN-B Principal yields and maturities?
> How did the LTN 010127 yield evolve in 2024?
> Compare the last 10 years of NTN-B Principal yields with the ANBIMA real
> return curve.
> Summarize the inflation implied by today's Brazilian yield curve.
Typical tool calls:
```text
list_bond_types(asset_codes=["NTN-B Principal"])
get_bond_data(asset_codes=["LTN"], first_year=2024, last_year=2024, asset_code="010127")
get_bond_data(asset_codes=["NTN-B Principal"], first_year=2015, frequency="monthly")
get_current_rates(asset_codes=["LFT", "LTN"])
get_bond_stats(asset_codes=["NTN-B Principal"], first_year=2015, max_assets=10)
get_yield_curve()
```
A live call returns:
```text
# Tesouro Direto — source: Tesouro Transparente (CKAN)
# Retrieved: 2026-11-01T12:00:00+00:00 | data file date: 2026-11-01 | latest ref date: 2026-10-30 | stale cache: no
# yield_bid is a decimal annual rate (0.1183 = 11.83% p.a.); ...
ref_date,yield_bid,yield_bid_pct,price_bid,asset_code,matur_date
2026-10-30,0.118300,11.8300,912.34,LTN 010127,2027-01-01
```
## Configuration
| Variable | Default | Purpose |
| --- | --- | --- |
| `TESOURO_DIRETO_CACHE_DIR` | `~/.cache/tesouro-direto-mcp` | Where the raw CSV is cached. |
| `TESOURO_DIRETO_CSV_URL` | Official CKAN resource URL | Override with a direct CSV URL or a local file path (useful offline/tests). |
| `MCP_TRANSPORT` | `stdio` | `stdio`, `streamable-http` or `sse`. |
| `MCP_HOST` / `MCP_PORT` | `127.0.0.1` / `8000` | Bind address for HTTP transports. |
## Development
```sh
uv sync
uv run pytest # offline unit + end-to-end MCP stdio tests
uv run python scripts/smoke_test.py # live test against Tesouro/ANBIMA
```
The test suite uses a small CSV fixture, so it does not need network access.
The smoke test downloads the real dataset and the current ANBIMA curve.
The ANBIMA business-day calendar (`src/tesouro_direto_mcp/anbima_holidays.txt`)
was exported from the `bizdays` Brazil/ANBIMA calendar used by `GetTDData`, so
curve maturity dates match the R package.
## Data sources and disclaimer
- Bond data: [Tesouro Transparente](https://www.tesourotransparente.gov.br/ckan/dataset/taxas-dos-titulos-ofertados-pelo-tesouro-direto),
the official open data portal of the Brazilian National Treasury.
- Yield curve: [ANBIMA](https://www.anbima.com.br/informacoes/est-termo/CZ.asp).
This project is not affiliated with Tesouro Nacional, ANBIMA or the R package
authors. Data is provided as-is; verify before making financial decisions.
## License
MIT © Marcelo S. Perlin
TDQS
Scored across 5 tools
Each tool targets a distinct data shape: bond type metadata, historical series, current snapshot, summary statistics, and the ANBIMA yield curve. There is mild overlap between get_current_rates and get_bond_stats (both expose latest yields) and between get_bond_stats and get_bond_data aggregation, but descriptions clearly steer selection.
All names are snake_case with a predictable verb_noun structure (list_bond_types, get_bond_data, get_current_rates, get_bond_stats, get_yield_curve). The 'get_' retrieval prefix plus domain object makes intent obvious across the set.
Five tools is well-scoped for a read-only market-data source, and each covers a genuinely different access pattern (metadata, history, snapshot, stats, curve). No tool looks redundant enough to remove.
The read-only lifecycle is covered end to end: discover bond types, pull history, get current quotes, summarize, and fetch the reference curve. Minor gaps exist — no lookup of a single bond by code/alias alias beyond list_bond_types, no fee/tax or liquidity/coupon-payment detail.