mcp-TesouroDireto
by msperlin
README.md
# mcp-TesouroDireto
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/mcp-tesouro-direto`
(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/mcp-TesouroDireto.git
cd mcp-TesouroDireto
uv sync
```
Run over stdio:
```sh
uv run mcp-tesouro-direto
```
Or install it as a standalone tool:
```sh
uv tool install .
mcp-tesouro-direto
```
## 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": {
"type": "local",
"command": [
"/home/msperlin/GitRepo/mcp-servers/mcp-TesouroDireto/.venv/bin/python",
"-m",
"mcp_tesouro_direto"
]
}
}
}
}
```
Or with `uv`, without hard-coding a virtualenv path:
```jsonc
"command": ["uv", "run", "--directory", "/path/to/mcp-TesouroDireto", "mcp-tesouro-direto"]
```
## Register with Claude Desktop
```jsonc
{
"mcpServers": {
"tesouro-direto": {
"command": "uvx",
"args": ["--from", "git+https://github.com/msperlin/mcp-TesouroDireto", "mcp-tesouro-direto"]
}
}
}
```
## 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/mcp-tesouro-direto` | 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/mcp_tesouro_direto/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