Skip to main content
Glama
ivyyy0601

asian-etf-mcp

by ivyyy0601
README.md
# asian-etf-mcp

An [MCP](https://modelcontextprotocol.io) server that exposes **thematic ETF data
across 5 Asian markets + the US** (Hong Kong, China A-Share, Taiwan, South Korea,
US) as tools an LLM agent — or Claude Code / Claude Desktop — can call.

It fetches public OHLCV data from Yahoo Finance, computes industry returns /
momentum / rankings, and serves them through a small set of well-described tools.
Every result carries its **source files and `as_of` date**, so answers built on it
are auditable.

## Tools

| tool | args | returns |
|------|------|---------|
| `list_markets` | — | every market → industries → ETFs (call first to discover) |
| `get_etf_performance` | `market, industry, start?, end?` | each ETF's total return vs the benchmark |
| `get_industry_momentum` | `market, end_date?` | per-industry 5d / 21d / 63d / YTD return, absolute + relative |
| `get_industry_ranking` | `market, start?, end?` | industries ranked by return |
| `get_etf_ohlcv` | `code, market, start?, end?` | raw daily OHLCV bars |

`market` accepts `hk` / `cn` / `tw` / `sk` / `us` (or full names). Dates are ISO
strings like `2025-06-01`.

## Quick start

```bash
git clone https://github.com/ivyyy0601/etf-mcp.git
cd etf-mcp                       # (or the asian-etf-mcp directory)
python3.10+ -m venv .venv
./.venv/bin/pip install -r requirements.txt

# Build the data cache once (fetches ~55 symbols from Yahoo Finance, ~2-3 min)
./.venv/bin/python build_cache.py
```

That's it — the server is self-contained. The market/industry/ETF definitions
ship in `configs/`, and the data comes from public Yahoo Finance, so **you don't
need any account, API key, or access to anyone's server.**

## Use with Claude Code

```bash
claude mcp add asian-etf -- /abs/path/to/.venv/bin/python /abs/path/to/src/server.py
```

Then ask, e.g. *“use asian-etf to show which US sector has the strongest momentum.”*

## How it works

Two layers, kept separate on purpose:

```
src/server.py        the "menu": thin FastMCP wrapper, one @mcp.tool() per function
   │ calls
src/data_access.py   the "kitchen": reads CSVs, computes returns/momentum/rankings
```

`data_access.py` has **no MCP dependency** — it returns plain Python objects and
can be imported by anything (tests, a notebook, a LangGraph agent). `server.py`
only adds the protocol + tool descriptions.

**Caching (fast reads).** `build_cache.py` precomputes every standard view into
`cache.json` once. Default-parameter tool calls are served from that cache
(instant); only custom date ranges are computed on the fly.

**Refresh-on-use (always current, zero babysitting).** When a tool is called and
the cache is older than the latest trading day, the server rebuilds it first
(fetches the latest data), then answers. So you never have to run a cron or open
anything — it self-maintains.

## Configuration

| env var | default | meaning |
|---------|---------|---------|
| `ASIAN_ETF_ROOT` | `./data` | where OHLCV CSVs are stored (generated) |
| `ASIAN_ETF_CONFIG_DIR` | `./configs` | market/industry/ETF definitions (shipped) |

To add a market or ETF, edit the JSON files in `configs/` — no code changes.

## Keeping it fresh

- **Anyone:** nothing to do — refresh-on-use fetches the latest from Yahoo Finance
  when needed. Or run `python build_cache.py` whenever you want.
- **Maintainer fast-path (optional):** if you run the companion data collector on a
  server, `sync_data.sh` can pull its daily CSVs and `build_cache.py --no-live`
  recomputes from them in seconds. Requires SSH access to that server; everyone
  else simply uses the live Yahoo Finance path.

## Project layout

```
src/server.py        MCP server (5 tools)
src/data_access.py   Streamlit-free data + cache layer
build_cache.py       refresh job: fetch + precompute → cache.json
configs/             market definitions (committed)
sync_data.sh         maintainer fast-path (optional)
test_data_access.py  smoke test for the data layer (no MCP needed)
```