Fuzzy-search ABS dataflow names, descriptions, and keywords.
Use this when you don't know the exact dataset ID. The curated dataflows
(LF, CPI, ANA_AGG, etc.; see list_curated()) get a relevance boost so common queries like
"unemployment" or "gdp" return the right dataset at rank #1 — not one of
ABS's 800+ census tables that mention these keywords incidentally.
Examples:
# Discover which dataflow answers "what's NSW unemployment?"
results = await search_datasets("unemployment")
# → [{id: 'LF', name: 'Labour Force', is_curated: True}, ...]
# Broader topic exploration
results = await search_datasets("housing", limit=5)
# → top 5 housing-related dataflows, curated first
When to use:
- You have a natural-language question and need to identify the dataset
- You want to discover what ABS publishes on a topic
- You're not sure if a topic has a plain-English (curated) mapping yet
Returns:
List of DatasetSummary (id, name, description, is_curated), ranked
by relevance. Curated dataflows surface above raw SDMX dataflows.
Describe an ABS dataflow's filter dimensions, value codes, and source.
For curated dataflows (LF, CPI, ANA_AGG, AWE, BA_GCCSA, ERP_Q, JV,
LEND_HOUSING, WPI, ABS_ANNUAL_ERP_ASGS2021), returns plain-English
dimension names + curated value keys + the ABS source URL.
For other dataflows (~1,200 in total), returns raw SDMX dimensions
and codelists translated to the same response shape — pass raw SDMX
codes to get_data when querying these.
Examples:
# Curated path — plain-English values
detail = await describe_dataset("LF")
# detail.dimensions = [{'name': 'region', 'values': [{'key': 'nsw',
# 'sdmx_code': '1'}, {'key': 'vic', 'sdmx_code': '2'}, ...]}, ...]
# Raw path — full SDMX codelist
detail = await describe_dataset("ALC") # Apparent Consumption of Alcohol
# detail.is_curated == False; values are raw SDMX codes
When to use:
- Before calling get_data on an unfamiliar dataflow — to discover
valid filter dim names and value keys
- To get the canonical source URL on the ABS site
- To see whether a dataflow is curated (plain-English) or raw SDMX
Returns:
DatasetDetail with id, name, description, is_curated flag, the list
of filter dimensions (name, sdmx_id, values), and abs_url.
Query an ABS dataflow and return observations.
Pass filters and/or a period range — unfiltered queries on large
dataflows can return tens of thousands of observations.
Curated dataflows accept plain-English filter keys and values that
are translated to SDMX codes server-side. For example, on LF:
`{"region": "nsw", "measure": "unemployment_rate"}` resolves to
SDMX key `M13.3.1599.20.1.M` with hidden-dim defaults auto-applied.
Examples:
# NSW unemployment monthly for 2024
resp = await get_data(
"LF",
filters={"region": "nsw", "measure": "unemployment_rate"},
start_period="2024",
end_period="2024-12",
)
# → resp.records[0]: period='2024-01', value=4.8, unit='Percent'
# Multi-state comparison
resp = await get_data(
"LF",
filters={"region": ["nsw","vic","qld"], "measure": "unemployment_rate"},
start_period="2024",
format="csv",
)
# → resp.csv contains 36 rows (3 states × 12 months)
# Australia quarterly CPI annual change
resp = await get_data(
"CPI",
filters={"region": "australia", "measure": "change_year"},
start_period="2020",
)
When to use:
- You want observations over a time range (use latest() for the most-recent only)
- You want a multi-state or multi-measure comparison via list filters
- You want a CSV for downstream charting / spreadsheet tools
Returns:
DataResponse with records (list of {period, value, dimensions, unit}),
unit (when homogeneous), period bounds, the resolved query echo,
the ABS source URL, and the CC-BY 4.0 attribution string.
Return the most recent observation(s) for a dataflow.
Wraps get_data with lastNObservations=1 and a 15-minute cache TTL
(vs 1 hour for general data calls). Use this for "what's the current
X?" questions — it's a cheap, fast call: warm-cache p50 ~22ms,
cold-cache ~200ms.
Examples:
# Latest NSW unemployment rate
resp = await latest("LF", {"region": "nsw", "measure": "unemployment_rate"})
# → resp.records[0]: period='2026-03', value=4.61, unit='Percent'
# Latest Australia headline annual inflation
resp = await latest("CPI", {"region": "australia", "measure": "change_year"})
# → resp.records[0]: period='2026-Q1', value=4.6, unit='Percent'
# Latest Greater Sydney population
resp = await latest("ABS_ANNUAL_ERP_ASGS2021",
{"region": "greater_sydney", "region_type": "gccsa"})
# → resp.records[0]: period='2025', value=5640000, unit='Persons'
When to use:
- You want "the current value" of an indicator (most common workflow)
- You're answering a "what's the unemployment rate?" style question
- You want sub-50ms warm-cache latency for chat/agent integration
Returns:
DataResponse with one most-recent observation per matched dimension
combination, capped at `limit` rows. Same envelope as get_data.
`truncated_at` is set to the original row count when the cap fires.
Return the N rows with the largest (or smallest) value of a measure.
Ranks across the most-recent available period only (uses
lastNObservations=1 under the hood) so the result is a clean
"top N entities at the latest period" view — not noisy historical highs.
This is the most common agent workflow: "show me the top 10 X by Y".
Without this tool, an agent would call get_data, receive the full time
series, and then sort/slice locally — wasting tokens and turns. top_n
does the rank server-side and returns only the requested rows.
Examples:
# 5 states with the highest current unemployment rate
top_n("LF", "unemployment_rate", n=5)
# 10 GCCSAs with the largest populations
top_n("ABS_ANNUAL_ERP_ASGS2021", "estimated_resident_population",
n=10, filters={"region_type": "gccsa"})
# 3 industries with the lowest wage growth
top_n("WPI", "wage_price_index", n=3, direction="bottom")
Returns:
DataResponse with at most `n` records, sorted by `measure` value
in the requested direction. Other fields (period, unit, attribution)
match a regular get_data call.
List the ABS dataflow IDs with hand-curated plain-English support.
These are the dataflows where get_data accepts plain-English filter
keys (`{"region": "nsw"}`) and describe_dataset returns rich
human-readable metadata. All other ABS dataflows (~1,200) are still
accessible via get_data with raw SDMX dimension IDs and codes.
The registry is one entry per YAML under data/curated/ and grows over
time; the returned list, not a number in this docstring, is the source
of truth. Headline members:
- LF — Labour Force (unemployment, employment, participation)
- CPI — Consumer Price Index (inflation)
- WPI — Wage Price Index (wage growth)
- AWE — Average Weekly Earnings
- JV — Job Vacancies
- BA_GCCSA — Building Approvals (by Greater Capital City)
- LEND_HOUSING — Lending Indicators / Housing Finance
- ANA_AGG — National Accounts (GDP)
- ERP_Q — Estimated Resident Population (quarterly)
- ABS_ANNUAL_ERP_ASGS2021 — Population (annual; supports SA2/SA3/SA4)
- ...and the rest of the registry (census, trade, retail, dwellings,
migration, business indicators)
Example:
ids = list_curated()
# → ['ABS_ANNUAL_ERP_ASGS2021', 'ABS_NOM_VISA_CY', 'ANA_AGG', 'AWE',
# 'BA_GCCSA', ..., 'WPI']
When to use:
- You want to know which dataflows have plain-English support
- You're enumerating capabilities programmatically (e.g. building a UI)
- You're showing users a "supported topics" list
Returns:
Sorted list of dataflow IDs, one per curated YAML.
Upcoming ABS publication schedule (data releases).
Scrapes the official ABS release calendar
(https://www.abs.gov.au/release-calendar/future-releases-calendar) and
returns each scheduled publication with its release timestamp, title,
reference period, and — when the title maps to a curated abs-mcp
dataset — the `dataset_id` an agent can plug into `get_data` or
`latest`. Curated mappings cover the datasets in `list_curated()`
plus a handful of commonly-watched non-curated catalogues (Retail
Trade, International Trade in Goods, etc., where `dataset_id` stays
null but `publication_id` carries the ABS catalogue number).
`release_at` is returned with Sydney's local UTC offset (`+10:00` AEST
or `+11:00` AEDT) — what ABS publishes against. The DST switch is
naive (month-based), within an hour of correct at the changeover
boundary; downstream code should treat the offset as authoritative
rather than re-deriving local time.
Examples:
# Next 7 days
cal = await release_calendar(7)
for r in cal.releases:
print(r.release_at, r.title, r.dataset_id)
# Filter to curated datasets only
cal = await release_calendar(30)
curated_releases = [r for r in cal.releases if r.dataset_id]
When to use:
- Building a webhook / notification feed (ABS publishes at 11:30 AEST)
- "What's next from the ABS?" agent answers
- Pre-warming caches the morning of a known release
Returns:
`ReleaseCalendarResponse` — same envelope shape as `rba-mcp`'s
`release_calendar` for portfolio interop. Sorted ascending by
`release_at`. `stale=True` + `stale_reason` is set when the live
HTML scrape failed and a cached payload was served past TTL.