rba-mcp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rba_mcp-0.1.0/.github/workflows/test.yml +47 -0
- rba_mcp-0.1.0/.gitignore +16 -0
- rba_mcp-0.1.0/CHANGELOG.md +15 -0
- rba_mcp-0.1.0/LICENSE +28 -0
- rba_mcp-0.1.0/PKG-INFO +192 -0
- rba_mcp-0.1.0/README.md +161 -0
- rba_mcp-0.1.0/glama.json +4 -0
- rba_mcp-0.1.0/pyproject.toml +55 -0
- rba_mcp-0.1.0/src/rba_mcp/__init__.py +6 -0
- rba_mcp-0.1.0/src/rba_mcp/cache.py +95 -0
- rba_mcp-0.1.0/src/rba_mcp/client.py +68 -0
- rba_mcp-0.1.0/src/rba_mcp/curated.py +153 -0
- rba_mcp-0.1.0/src/rba_mcp/data/curated/F11.yaml +56 -0
- rba_mcp-0.1.0/src/rba_mcp/data/curated/F11_1.yaml +62 -0
- rba_mcp-0.1.0/src/rba_mcp/data/curated/F1_1.yaml +65 -0
- rba_mcp-0.1.0/src/rba_mcp/data/curated/F4.yaml +60 -0
- rba_mcp-0.1.0/src/rba_mcp/data/curated/F6.yaml +65 -0
- rba_mcp-0.1.0/src/rba_mcp/data/tables.yaml +102 -0
- rba_mcp-0.1.0/src/rba_mcp/models.py +71 -0
- rba_mcp-0.1.0/src/rba_mcp/parsing.py +255 -0
- rba_mcp-0.1.0/src/rba_mcp/py.typed +0 -0
- rba_mcp-0.1.0/src/rba_mcp/server.py +393 -0
- rba_mcp-0.1.0/src/rba_mcp/shaping.py +160 -0
- rba_mcp-0.1.0/src/rba_mcp/tables.py +129 -0
- rba_mcp-0.1.0/tests/__init__.py +0 -0
- rba_mcp-0.1.0/tests/conftest.py +20 -0
- rba_mcp-0.1.0/tests/fixtures/f1.1-data.csv +9998 -0
- rba_mcp-0.1.0/tests/fixtures/f11-data.csv +425 -0
- rba_mcp-0.1.0/tests/fixtures/f11.1-data.csv +2185 -0
- rba_mcp-0.1.0/tests/fixtures/f4-data.csv +9998 -0
- rba_mcp-0.1.0/tests/fixtures/f6-data.csv +9998 -0
- rba_mcp-0.1.0/tests/test_client.py +51 -0
- rba_mcp-0.1.0/tests/test_curated.py +99 -0
- rba_mcp-0.1.0/tests/test_integration.py +111 -0
- rba_mcp-0.1.0/tests/test_mcp_protocol.py +69 -0
- rba_mcp-0.1.0/tests/test_parsing.py +137 -0
- rba_mcp-0.1.0/tests/test_server_validation.py +96 -0
- rba_mcp-0.1.0/tests/test_shaping.py +100 -0
- rba_mcp-0.1.0/tests/test_tables.py +62 -0
- rba_mcp-0.1.0/uv.lock +1725 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- name: Install uv
|
|
19
|
+
uses: astral-sh/setup-uv@v3
|
|
20
|
+
with:
|
|
21
|
+
enable-cache: true
|
|
22
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
23
|
+
run: uv python install ${{ matrix.python-version }}
|
|
24
|
+
- name: Sync dependencies
|
|
25
|
+
run: uv sync --extra dev
|
|
26
|
+
- name: Install package
|
|
27
|
+
run: uv pip install -e .
|
|
28
|
+
- name: Run unit tests
|
|
29
|
+
run: uv run pytest -q
|
|
30
|
+
|
|
31
|
+
build:
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
needs: test
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
- name: Install uv
|
|
37
|
+
uses: astral-sh/setup-uv@v3
|
|
38
|
+
- name: Build wheel + sdist
|
|
39
|
+
run: uv build
|
|
40
|
+
- name: Verify wheel installs cleanly
|
|
41
|
+
run: |
|
|
42
|
+
uv run --isolated --with ./dist/*.whl python -c \
|
|
43
|
+
"import rba_mcp.server as s; n = len(s.list_curated()); assert n >= 5, f'expected >=5 curated, got {n}'; print(f'OK ({n} curated tables)')"
|
|
44
|
+
- uses: actions/upload-artifact@v4
|
|
45
|
+
with:
|
|
46
|
+
name: dist
|
|
47
|
+
path: dist/
|
rba_mcp-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-05-11)
|
|
4
|
+
|
|
5
|
+
Initial release. MCP server for RBA F-tables; companion to `abs-mcp`.
|
|
6
|
+
|
|
7
|
+
- 5 MCP tools: `search_tables`, `describe_table`, `get_data`, `latest`, `list_curated`
|
|
8
|
+
- 5 curated F-tables with plain-English series mappings: **F1.1** (money market — cash rate), **F4** (deposit rates), **F6** (housing lending rates), **F11** (FX monthly history), **F11.1** (FX daily current)
|
|
9
|
+
- 14 non-curated F-tables accessible via raw RBA series IDs
|
|
10
|
+
- Label-driven CSV header parser (resilient to RBA adding new metadata rows)
|
|
11
|
+
- SQLite-backed cache (6h data TTL, 15min latest TTL)
|
|
12
|
+
- Unit attribution per series (Per cent per annum / USD per AUD / Index / etc.)
|
|
13
|
+
- CC-BY 4.0 attribution surfaced in every response
|
|
14
|
+
- Input validation guards (URL-injection-safe)
|
|
15
|
+
- 76 unit tests + 21 live integration tests
|
rba_mcp-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Harry Vass
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
Note on RBA data: this software fetches statistical tables published by the
|
|
26
|
+
Reserve Bank of Australia. RBA data is licensed under Creative Commons
|
|
27
|
+
Attribution 4.0 International (CC BY 4.0) — see https://www.rba.gov.au/copyright/.
|
|
28
|
+
End-users redistributing data fetched via this server must credit the RBA.
|
rba_mcp-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rba-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server for the Reserve Bank of Australia statistical tables (F-tables). Plain-English access to interest rates, FX rates, deposit/lending rates.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Bigred97/rba-mcp
|
|
6
|
+
Project-URL: Issues, https://github.com/Bigred97/rba-mcp/issues
|
|
7
|
+
Author: Harry Vass
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: australia,claude,fastmcp,fx,interest-rates,mcp,rba
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Requires-Dist: aiosqlite>=0.20
|
|
20
|
+
Requires-Dist: fastmcp<4,>=2.0
|
|
21
|
+
Requires-Dist: httpx>=0.27
|
|
22
|
+
Requires-Dist: pandas<3,>=2.2
|
|
23
|
+
Requires-Dist: pydantic>=2.7
|
|
24
|
+
Requires-Dist: pyyaml>=6.0
|
|
25
|
+
Requires-Dist: rapidfuzz>=3.9
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
29
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# rba-mcp
|
|
33
|
+
|
|
34
|
+
[](https://github.com/Bigred97/rba-mcp/actions/workflows/test.yml)
|
|
35
|
+
[](https://pypi.org/project/rba-mcp/)
|
|
36
|
+
[](https://pypi.org/project/rba-mcp/)
|
|
37
|
+
[](LICENSE)
|
|
38
|
+
|
|
39
|
+
**Ask Claude about Australian interest rates, exchange rates, and lending rates and get real, current numbers** — not "I don't have access to that data." This MCP server gives Claude (and other MCP clients like Cursor) live access to the [Reserve Bank of Australia's statistical tables](https://www.rba.gov.au/statistics/tables/), with curated mappings for the most-asked indicators.
|
|
40
|
+
|
|
41
|
+
Companion to [abs-mcp](https://github.com/Bigred97/abs-mcp) — together they cover the most-asked Australian economic data.
|
|
42
|
+
|
|
43
|
+
## What you can ask
|
|
44
|
+
|
|
45
|
+
Once installed, your LLM can answer questions like:
|
|
46
|
+
|
|
47
|
+
| Question | Real response |
|
|
48
|
+
|---|---|
|
|
49
|
+
| What's the current RBA cash rate? | RBA Cash Rate Target, latest month |
|
|
50
|
+
| What's AUD/USD today? | Latest daily exchange rate |
|
|
51
|
+
| Show me AUD vs major currencies in 2024 | Multi-series query with monthly observations |
|
|
52
|
+
| What's the average mortgage rate? | Owner-occupier variable, outstanding loans |
|
|
53
|
+
| What rate are 12-month term deposits at? | Latest from F4 |
|
|
54
|
+
| What's the trade-weighted index trend? | TWI series back to 1983 |
|
|
55
|
+
|
|
56
|
+
Every answer comes with the period, units (Per cent per annum, USD per AUD, etc.), and a link back to the RBA source.
|
|
57
|
+
|
|
58
|
+
## Install
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# After publish:
|
|
62
|
+
uvx rba-mcp
|
|
63
|
+
|
|
64
|
+
# Local dev:
|
|
65
|
+
uv pip install -e .
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Claude Desktop
|
|
69
|
+
|
|
70
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"mcpServers": {
|
|
75
|
+
"rba": {
|
|
76
|
+
"command": "uvx",
|
|
77
|
+
"args": ["rba-mcp"]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
If you also have `abs-mcp` installed, both servers run side-by-side. Claude disambiguates with the server prefix (`rba:get_data` vs `abs:get_data`).
|
|
84
|
+
|
|
85
|
+
For local dev (pre-PyPI):
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"mcpServers": {
|
|
90
|
+
"rba": {
|
|
91
|
+
"command": "uv",
|
|
92
|
+
"args": ["run", "--directory", "/absolute/path/to/rba-mcp", "rba-mcp"]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Cursor
|
|
99
|
+
|
|
100
|
+
Add to `~/.cursor/mcp.json` (or workspace `.cursor/mcp.json`):
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"mcpServers": {
|
|
105
|
+
"rba": {
|
|
106
|
+
"command": "uvx",
|
|
107
|
+
"args": ["rba-mcp"]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Tools
|
|
114
|
+
|
|
115
|
+
| Tool | What it does |
|
|
116
|
+
|---|---|
|
|
117
|
+
| `search_tables(query, limit=10)` | Fuzzy-search RBA F-tables by name or topic. |
|
|
118
|
+
| `describe_table(table_id)` | Plain-English series listing for one F-table. |
|
|
119
|
+
| `get_data(table_id, series, start_date, end_date, format)` | Query data. `series=None` returns all curated series; format = records / series / csv. |
|
|
120
|
+
| `latest(table_id, series)` | Most-recent observation for the requested series. |
|
|
121
|
+
| `list_curated()` | The 5 F-table IDs with hand-curated plain-English support. |
|
|
122
|
+
|
|
123
|
+
## Curated F-tables
|
|
124
|
+
|
|
125
|
+
For these five, `series` accepts plain-English keys (e.g. `"aud_usd"` instead of `"FXRUSD"`):
|
|
126
|
+
|
|
127
|
+
- **F1.1** — Money Market — Monthly: cash rate target, cash rate, bank bills, OIS rates, treasury notes
|
|
128
|
+
- **F4** — Retail Deposit & Investment Rates: transaction accounts, savings, term deposits, cash management trusts
|
|
129
|
+
- **F6** — Housing Lending Rates: owner-occupier vs investor, variable vs fixed, outstanding vs new loans
|
|
130
|
+
- **F11** — Exchange Rates — Monthly History (1983+): AUD/USD, AUD/EUR, AUD/GBP, AUD/JPY, AUD/CNY, AUD/NZD, TWI
|
|
131
|
+
- **F11.1** — Exchange Rates — Daily (2023+): same series, daily resolution
|
|
132
|
+
|
|
133
|
+
Any other F-table works too — pass raw RBA series IDs (e.g. `"FXRUSD"`) instead of curated keys.
|
|
134
|
+
|
|
135
|
+
## Worked examples
|
|
136
|
+
|
|
137
|
+
**"What's the current RBA cash rate?"**
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
latest(table_id="F1.1", series="cash_rate_target")
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**"AUD to USD over the last year"**
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
get_data(table_id="F11.1", series="aud_usd", start_date="2024")
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**"Compare AUD against USD, EUR and GBP since 2020"**
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
get_data(
|
|
153
|
+
table_id="F11",
|
|
154
|
+
series=["aud_usd", "aud_eur", "aud_gbp"],
|
|
155
|
+
start_date="2020"
|
|
156
|
+
)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Period formats
|
|
160
|
+
|
|
161
|
+
RBA series use ISO-style date formats. Pass `start_date` / `end_date` as:
|
|
162
|
+
|
|
163
|
+
| Format | Example | Use for |
|
|
164
|
+
|---|---|---|
|
|
165
|
+
| `YYYY` | `"2024"` | Year start |
|
|
166
|
+
| `YYYY-MM` | `"2024-03"` | Month start |
|
|
167
|
+
| `YYYY-MM-DD` | `"2024-03-15"` | Specific day (daily tables only) |
|
|
168
|
+
|
|
169
|
+
## Development
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
git clone https://github.com/Bigred97/rba-mcp.git
|
|
173
|
+
cd rba-mcp
|
|
174
|
+
uv sync --extra dev
|
|
175
|
+
uv pip install -e .
|
|
176
|
+
|
|
177
|
+
# Unit tests (no network)
|
|
178
|
+
uv run pytest
|
|
179
|
+
|
|
180
|
+
# Live integration tests (hits RBA CDN)
|
|
181
|
+
uv run pytest -m live
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The SQLite cache lives at `~/.rba-mcp/cache.db`. Data refreshes every 6h, latest 15min. Delete to force a refresh.
|
|
185
|
+
|
|
186
|
+
## Data attribution
|
|
187
|
+
|
|
188
|
+
RBA data is licensed under [Creative Commons Attribution 4.0 International (CC BY 4.0)](https://www.rba.gov.au/copyright/). Every `DataResponse` from this server includes an `attribution` field with the required notice. If you redistribute responses, credit the RBA.
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
MIT — Harry Vass, 2026.
|
rba_mcp-0.1.0/README.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# rba-mcp
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Bigred97/rba-mcp/actions/workflows/test.yml)
|
|
4
|
+
[](https://pypi.org/project/rba-mcp/)
|
|
5
|
+
[](https://pypi.org/project/rba-mcp/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
**Ask Claude about Australian interest rates, exchange rates, and lending rates and get real, current numbers** — not "I don't have access to that data." This MCP server gives Claude (and other MCP clients like Cursor) live access to the [Reserve Bank of Australia's statistical tables](https://www.rba.gov.au/statistics/tables/), with curated mappings for the most-asked indicators.
|
|
9
|
+
|
|
10
|
+
Companion to [abs-mcp](https://github.com/Bigred97/abs-mcp) — together they cover the most-asked Australian economic data.
|
|
11
|
+
|
|
12
|
+
## What you can ask
|
|
13
|
+
|
|
14
|
+
Once installed, your LLM can answer questions like:
|
|
15
|
+
|
|
16
|
+
| Question | Real response |
|
|
17
|
+
|---|---|
|
|
18
|
+
| What's the current RBA cash rate? | RBA Cash Rate Target, latest month |
|
|
19
|
+
| What's AUD/USD today? | Latest daily exchange rate |
|
|
20
|
+
| Show me AUD vs major currencies in 2024 | Multi-series query with monthly observations |
|
|
21
|
+
| What's the average mortgage rate? | Owner-occupier variable, outstanding loans |
|
|
22
|
+
| What rate are 12-month term deposits at? | Latest from F4 |
|
|
23
|
+
| What's the trade-weighted index trend? | TWI series back to 1983 |
|
|
24
|
+
|
|
25
|
+
Every answer comes with the period, units (Per cent per annum, USD per AUD, etc.), and a link back to the RBA source.
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# After publish:
|
|
31
|
+
uvx rba-mcp
|
|
32
|
+
|
|
33
|
+
# Local dev:
|
|
34
|
+
uv pip install -e .
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Claude Desktop
|
|
38
|
+
|
|
39
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"mcpServers": {
|
|
44
|
+
"rba": {
|
|
45
|
+
"command": "uvx",
|
|
46
|
+
"args": ["rba-mcp"]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If you also have `abs-mcp` installed, both servers run side-by-side. Claude disambiguates with the server prefix (`rba:get_data` vs `abs:get_data`).
|
|
53
|
+
|
|
54
|
+
For local dev (pre-PyPI):
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"mcpServers": {
|
|
59
|
+
"rba": {
|
|
60
|
+
"command": "uv",
|
|
61
|
+
"args": ["run", "--directory", "/absolute/path/to/rba-mcp", "rba-mcp"]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Cursor
|
|
68
|
+
|
|
69
|
+
Add to `~/.cursor/mcp.json` (or workspace `.cursor/mcp.json`):
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"mcpServers": {
|
|
74
|
+
"rba": {
|
|
75
|
+
"command": "uvx",
|
|
76
|
+
"args": ["rba-mcp"]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Tools
|
|
83
|
+
|
|
84
|
+
| Tool | What it does |
|
|
85
|
+
|---|---|
|
|
86
|
+
| `search_tables(query, limit=10)` | Fuzzy-search RBA F-tables by name or topic. |
|
|
87
|
+
| `describe_table(table_id)` | Plain-English series listing for one F-table. |
|
|
88
|
+
| `get_data(table_id, series, start_date, end_date, format)` | Query data. `series=None` returns all curated series; format = records / series / csv. |
|
|
89
|
+
| `latest(table_id, series)` | Most-recent observation for the requested series. |
|
|
90
|
+
| `list_curated()` | The 5 F-table IDs with hand-curated plain-English support. |
|
|
91
|
+
|
|
92
|
+
## Curated F-tables
|
|
93
|
+
|
|
94
|
+
For these five, `series` accepts plain-English keys (e.g. `"aud_usd"` instead of `"FXRUSD"`):
|
|
95
|
+
|
|
96
|
+
- **F1.1** — Money Market — Monthly: cash rate target, cash rate, bank bills, OIS rates, treasury notes
|
|
97
|
+
- **F4** — Retail Deposit & Investment Rates: transaction accounts, savings, term deposits, cash management trusts
|
|
98
|
+
- **F6** — Housing Lending Rates: owner-occupier vs investor, variable vs fixed, outstanding vs new loans
|
|
99
|
+
- **F11** — Exchange Rates — Monthly History (1983+): AUD/USD, AUD/EUR, AUD/GBP, AUD/JPY, AUD/CNY, AUD/NZD, TWI
|
|
100
|
+
- **F11.1** — Exchange Rates — Daily (2023+): same series, daily resolution
|
|
101
|
+
|
|
102
|
+
Any other F-table works too — pass raw RBA series IDs (e.g. `"FXRUSD"`) instead of curated keys.
|
|
103
|
+
|
|
104
|
+
## Worked examples
|
|
105
|
+
|
|
106
|
+
**"What's the current RBA cash rate?"**
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
latest(table_id="F1.1", series="cash_rate_target")
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**"AUD to USD over the last year"**
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
get_data(table_id="F11.1", series="aud_usd", start_date="2024")
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**"Compare AUD against USD, EUR and GBP since 2020"**
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
get_data(
|
|
122
|
+
table_id="F11",
|
|
123
|
+
series=["aud_usd", "aud_eur", "aud_gbp"],
|
|
124
|
+
start_date="2020"
|
|
125
|
+
)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Period formats
|
|
129
|
+
|
|
130
|
+
RBA series use ISO-style date formats. Pass `start_date` / `end_date` as:
|
|
131
|
+
|
|
132
|
+
| Format | Example | Use for |
|
|
133
|
+
|---|---|---|
|
|
134
|
+
| `YYYY` | `"2024"` | Year start |
|
|
135
|
+
| `YYYY-MM` | `"2024-03"` | Month start |
|
|
136
|
+
| `YYYY-MM-DD` | `"2024-03-15"` | Specific day (daily tables only) |
|
|
137
|
+
|
|
138
|
+
## Development
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
git clone https://github.com/Bigred97/rba-mcp.git
|
|
142
|
+
cd rba-mcp
|
|
143
|
+
uv sync --extra dev
|
|
144
|
+
uv pip install -e .
|
|
145
|
+
|
|
146
|
+
# Unit tests (no network)
|
|
147
|
+
uv run pytest
|
|
148
|
+
|
|
149
|
+
# Live integration tests (hits RBA CDN)
|
|
150
|
+
uv run pytest -m live
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The SQLite cache lives at `~/.rba-mcp/cache.db`. Data refreshes every 6h, latest 15min. Delete to force a refresh.
|
|
154
|
+
|
|
155
|
+
## Data attribution
|
|
156
|
+
|
|
157
|
+
RBA data is licensed under [Creative Commons Attribution 4.0 International (CC BY 4.0)](https://www.rba.gov.au/copyright/). Every `DataResponse` from this server includes an `attribution` field with the required notice. If you redistribute responses, credit the RBA.
|
|
158
|
+
|
|
159
|
+
## License
|
|
160
|
+
|
|
161
|
+
MIT — Harry Vass, 2026.
|
rba_mcp-0.1.0/glama.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "rba-mcp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "MCP server for the Reserve Bank of Australia statistical tables (F-tables). Plain-English access to interest rates, FX rates, deposit/lending rates."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Harry Vass" }]
|
|
13
|
+
keywords = ["mcp", "rba", "australia", "interest-rates", "fx", "claude", "fastmcp"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Topic :: Scientific/Engineering :: Information Analysis",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"fastmcp>=2.0,<4",
|
|
25
|
+
"httpx>=0.27",
|
|
26
|
+
"pydantic>=2.7",
|
|
27
|
+
"rapidfuzz>=3.9",
|
|
28
|
+
"pandas>=2.2,<3",
|
|
29
|
+
"aiosqlite>=0.20",
|
|
30
|
+
"PyYAML>=6.0",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
dev = [
|
|
35
|
+
"pytest>=8",
|
|
36
|
+
"pytest-asyncio>=0.23",
|
|
37
|
+
"respx>=0.21",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
rba-mcp = "rba_mcp.server:main"
|
|
42
|
+
|
|
43
|
+
[project.urls]
|
|
44
|
+
Homepage = "https://github.com/Bigred97/rba-mcp"
|
|
45
|
+
Issues = "https://github.com/Bigred97/rba-mcp/issues"
|
|
46
|
+
|
|
47
|
+
[tool.hatch.build.targets.wheel]
|
|
48
|
+
packages = ["src/rba_mcp"]
|
|
49
|
+
|
|
50
|
+
[tool.pytest.ini_options]
|
|
51
|
+
asyncio_mode = "auto"
|
|
52
|
+
markers = ["live: hits the real RBA CDN"]
|
|
53
|
+
addopts = "-m 'not live'"
|
|
54
|
+
testpaths = ["tests"]
|
|
55
|
+
pythonpath = ["src"]
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""SQLite-backed HTTP cache with per-read TTL.
|
|
2
|
+
|
|
3
|
+
Single table; the same row can satisfy different TTL windows because TTL is
|
|
4
|
+
evaluated at read time. The `kind` column lets us run targeted invalidation
|
|
5
|
+
later without renaming.
|
|
6
|
+
|
|
7
|
+
Ported from abs-mcp 0.2.8 — only differences:
|
|
8
|
+
- DEFAULT_DB_PATH points at ~/.rba-mcp/
|
|
9
|
+
- CacheKind enum reduced to {"data", "latest"} (no SDMX catalogue/datastructure)
|
|
10
|
+
- Default TTLs tuned for RBA's daily-CDN refresh cadence
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import asyncio
|
|
15
|
+
import time
|
|
16
|
+
from datetime import timedelta
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Literal
|
|
19
|
+
|
|
20
|
+
import aiosqlite
|
|
21
|
+
|
|
22
|
+
CacheKind = Literal["data", "latest"]
|
|
23
|
+
|
|
24
|
+
DEFAULT_DB_PATH = Path.home() / ".rba-mcp" / "cache.db"
|
|
25
|
+
|
|
26
|
+
TTL: dict[CacheKind, timedelta] = {
|
|
27
|
+
"data": timedelta(hours=6), # RBA refreshes mid-morning Sydney for daily tables
|
|
28
|
+
"latest": timedelta(minutes=15), # post-publication freshness window
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
_SCHEMA = """
|
|
32
|
+
CREATE TABLE IF NOT EXISTS http_cache (
|
|
33
|
+
cache_key TEXT PRIMARY KEY,
|
|
34
|
+
payload BLOB NOT NULL,
|
|
35
|
+
cached_at REAL NOT NULL,
|
|
36
|
+
kind TEXT NOT NULL
|
|
37
|
+
);
|
|
38
|
+
CREATE INDEX IF NOT EXISTS idx_kind_cached_at ON http_cache(kind, cached_at);
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Cache:
|
|
43
|
+
def __init__(self, db_path: Path = DEFAULT_DB_PATH) -> None:
|
|
44
|
+
self.db_path = db_path
|
|
45
|
+
self.db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
46
|
+
self._initialized = False
|
|
47
|
+
self._init_lock = asyncio.Lock()
|
|
48
|
+
|
|
49
|
+
async def _ensure_init(self) -> None:
|
|
50
|
+
if self._initialized:
|
|
51
|
+
return
|
|
52
|
+
async with self._init_lock:
|
|
53
|
+
if self._initialized:
|
|
54
|
+
return
|
|
55
|
+
async with aiosqlite.connect(self.db_path) as conn:
|
|
56
|
+
await conn.execute("PRAGMA journal_mode=WAL")
|
|
57
|
+
await conn.executescript(_SCHEMA)
|
|
58
|
+
await conn.commit()
|
|
59
|
+
self._initialized = True
|
|
60
|
+
|
|
61
|
+
async def get(self, key: str, ttl: timedelta) -> bytes | None:
|
|
62
|
+
await self._ensure_init()
|
|
63
|
+
cutoff = time.time() - ttl.total_seconds()
|
|
64
|
+
async with aiosqlite.connect(self.db_path) as conn:
|
|
65
|
+
async with conn.execute(
|
|
66
|
+
"SELECT payload FROM http_cache WHERE cache_key = ? AND cached_at >= ?",
|
|
67
|
+
(key, cutoff),
|
|
68
|
+
) as cur:
|
|
69
|
+
row = await cur.fetchone()
|
|
70
|
+
return row[0] if row else None
|
|
71
|
+
|
|
72
|
+
async def set(self, key: str, value: bytes, kind: CacheKind) -> None:
|
|
73
|
+
await self._ensure_init()
|
|
74
|
+
async with aiosqlite.connect(self.db_path) as conn:
|
|
75
|
+
await conn.execute(
|
|
76
|
+
"""
|
|
77
|
+
INSERT INTO http_cache (cache_key, payload, cached_at, kind)
|
|
78
|
+
VALUES (?, ?, ?, ?)
|
|
79
|
+
ON CONFLICT(cache_key) DO UPDATE SET
|
|
80
|
+
payload = excluded.payload,
|
|
81
|
+
cached_at = excluded.cached_at,
|
|
82
|
+
kind = excluded.kind
|
|
83
|
+
""",
|
|
84
|
+
(key, value, time.time(), kind),
|
|
85
|
+
)
|
|
86
|
+
await conn.commit()
|
|
87
|
+
|
|
88
|
+
async def clear(self, kind: CacheKind | None = None) -> None:
|
|
89
|
+
await self._ensure_init()
|
|
90
|
+
async with aiosqlite.connect(self.db_path) as conn:
|
|
91
|
+
if kind:
|
|
92
|
+
await conn.execute("DELETE FROM http_cache WHERE kind = ?", (kind,))
|
|
93
|
+
else:
|
|
94
|
+
await conn.execute("DELETE FROM http_cache")
|
|
95
|
+
await conn.commit()
|