Skip to main content
Glama
Australian Bureau of Statistics

Australian Bureau of Statistics

abs-mcp

mcp-name: io.ausdata/abs-mcp

PyPI Python License Tests CodeQL Glama MCP server quality

Ask Claude about the Australian economy 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 ABS Data API, with curated mappings for the 10 most-asked Australian economic indicators.

Hosted access? For cross-source queries, webhooks, an always-on REST API, and a uniform response envelope across all 9 sources, see ausdata.io — free tier available (500 calls/mo, no card).

abs-mcp answering "What's the unemployment rate in NSW?" in Claude Desktop

Behind the scenes it wraps SDMX 2.1, but you never see SDMX codes — just plain-English filters like region: "nsw" and measure: "unemployment_rate". Five tools, ten curated dataflows (Labour Force, CPI, Wage Price Index, Job Vacancies, Average Weekly Earnings, GDP / National Accounts, quarterly + annual Estimated Resident Population, Building Approvals, Lending Indicators), and 1,200+ other ABS dataflows accessible via raw codes.

Companion to rba-mcp (Reserve Bank of Australia — cash rate, FX, lending rates), ato-mcp (Australian Taxation Office — postcode-level personal tax, company tax by industry, corporate tax transparency, ACNC charity register), and au-weather-mcp (Australian weather — 21 curated locations + postcode/place-name lookup, current observations, 16-day forecasts, 80yr historical archive). Install all four for the full AU macro / regulator / tax / climate stack.

What you can ask

Once installed, your LLM can answer questions like:

Question

Real response (verified)

What's the unemployment rate in NSW?

4.27% (Mar 2026)

AU annual CPI inflation?

4.60% (Mar 2026)

AU annual wage growth?

3.40% (Q4 2025)

Average weekly earnings in Australia?

$1,562 (Sep–Oct 2025)

AU GDP quarterly growth?

0.80% (Q4 2025)

AU GDP per capita?

$24,900/qtr (Q4 2025)

Job vacancies in NSW?

101,200 (Q1 2026)

Dwelling approvals in NSW?

4,400/month (Mar 2026)

New NSW housing loan commitments?

$19.7B (Q4 2025)

Quarterly population of Australia?

27.7M (Q3 2025)

Every answer comes with the period, units, and a link back to the ABS source page. Comparisons and time-series queries work just as well — see Worked examples below.

Related MCP server: Reserve Bank of Australia

Install

# After publish:
uvx --upgrade abs-mcp

# Local dev install:
uv pip install -e .

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "abs": {
      "command": "uvx",
      "args": ["--upgrade", "abs-mcp"]
    }
  }
}

Why --upgrade? uvx abs-mcp (without the flag) uses whatever wheel is cached and never adopts new PyPI releases on its own — Claude Desktop's MCP child process keeps running the same wheel until you fully quit the app and refresh the cache by hand. --upgrade makes uvx check PyPI on each launch and pull a newer release if one exists. To verify which version is currently serving you, look at the server_version field on any DataResponse (added in 0.2.10).

For a local checkout (before PyPI publish):

{
  "mcpServers": {
    "abs": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/abs-mcp", "abs-mcp"]
    }
  }
}

Restart Claude Desktop. The abs server appears in the tools panel with five tools.

Cursor

Add to ~/.cursor/mcp.json (or workspace .cursor/mcp.json):

{
  "mcpServers": {
    "abs": {
      "command": "uvx",
      "args": ["--upgrade", "abs-mcp"]
    }
  }
}

Tools

Tool

What it does

search_datasets(query, limit=10)

Fuzzy-search ABS dataflow names. Returns the top matches.

describe_dataset(dataset_id)

Plain-English description of a dataflow's dimensions and values.

get_data(dataset_id, filters, start_period, end_period, format)

Query a dataflow with filters. Returns clean records (default), grouped series, or CSV.

latest(dataset_id, filters)

Just the most recent observation(s) — wraps get_data with lastNObservations=1.

top_n(dataset_id, measure, n=10, filters=None, direction="top")

Rank rows of a curated dataflow by a measure (e.g. unemployment_rate) at the most-recent period and return the top (or bottom) N.

list_curated()

The ten dataflow IDs that have hand-curated plain-English support.

Curated dataflows

For these curated dataflows, filters accepts plain-English values (e.g. "region": "nsw" instead of "REGION": "1"):

  • LF — Labour Force, monthly: employment, unemployment, participation by state/sex

  • CPI — Consumer Price Index, quarterly inflation (cat 6401.0 — the headline rate)

  • CPI_MONTHLY — Monthly CPI Indicator (cat 6484.0), full sub-category and per-city breakdown

  • WPI — Wage Price Index, quarterly wage growth by industry/sector/state

  • PPI_FD — Producer Price Index Final Demand, quarterly producer inflation

  • JV — Job Vacancies, quarterly labour demand by industry/sector/state

  • AWE — Average Weekly Earnings, half-yearly by industry/sector/state

  • ANA_AGG — National Accounts: GDP, GDP per capita, terms of trade, real income (Australia, quarterly)

  • ABS_ANNUAL_ERP_ASGS2021 — Estimated Resident Population, annual by state and sub-state geography

  • ERP_Q — Quarterly Estimated Resident Population, by state/sex/age

  • BUILDING_APPROVALS — Building Approvals (cat 8731.0), monthly by state/capital region, building type (houses / townhouses / apartments / total dwellings / non-residential) and measure (number / value). The property-economist "Building Index" series.

  • BA_GCCSA — Building Approvals, monthly by state/capital region and building type (raw GCCSA dimension surface; BUILDING_APPROVALS is the cleaner alias)

  • BA_LGA2024 — Building Approvals at the council (Local Government Area) level, monthly, ~570 councils — far more granular than BA_GCCSA's 8-capital geography. Pass region= an LGA code (e.g. "10050" Albury, "22750" Greater Geelong, "31000" Brisbane) for council-by-council approvals; defaults to Brisbane. Council-level only — for state / national totals use BUILDING_APPROVALS. Resolves to ABS's current BA_LGA2025 SDMX dataflow so the series stays live.

  • BUILDING_ACTIVITY — Building Activity (cat 8752.0), quarterly dwelling units completed / commenced / under construction plus value of work, by state and building type. The trailing-reality counterpart to BUILDING_APPROVALS — pair the two for approvals-vs-completions, and add NOM for the supply-vs-migration story.

  • NOM — Net Overseas Migration (cat 3412.0), financial-year arrivals/departures/net by state and age. The dominant rents-vs-migration series; publishes the headline net figure to the latest FY.

  • ABS_NOM_VISA_CY — NOM by visa subclass (calendar year, student / skilled / working holiday / permanent streams)

  • LEND_HOUSING — Lending Indicators, quarterly new housing loan commitments by purpose, lender, and state

  • HSI_M — Monthly Household Spending Indicator (ABS-blessed retail-trade replacement), COICOP category × discretionary × state

  • RT — Retail Trade (43-year historical series, ceased Jul 2025)

  • C21_G01_POA / C21_G02_POA / C21_G02_SA2 — Census 2021 selected characteristics and medians by postcode / SA2

Any other ABS dataflow still works — pass raw SDMX dimension IDs and codes.

Worked examples

Cross-source compatibility. All location filters accept canonical state codes ("NSW"), full names ("New South Wales"), case-insensitive variants ("nsw"), ISO 3166-2 ("AU-NSW"), and 4-digit postcodes ("2000" → NSW). Powered by aus-identity — the same input format works across abs-mcp, ato-mcp, apra-mcp, aihw-mcp, and asic-mcp.

"What's the current unemployment rate in NSW?"

Claude calls:

latest(dataset_id="LF", filters={"region": "nsw", "measure": "unemployment_rate"})

Returns:

{
  "dataset_id": "LF",
  "dataset_name": "Labour Force",
  "query": {"region": "nsw", "measure": "unemployment_rate"},
  "period": {"start": "2026-03", "end": "2026-03"},
  "unit": "Percent",
  "records": [
    {
      "period": "2026-03",
      "value": 4.27,
      "dimensions": {"measure": "Unemployment rate", "region": "New South Wales", "sex": "Persons"},
      "unit": "Percent"
    }
  ],
  "source": "Australian Bureau of Statistics",
  "retrieved_at": "2026-05-11T03:14:22Z",
  "abs_url": "https://www.abs.gov.au/statistics/labour/employment-and-unemployment/labour-force-australia"
}

"Show me NSW housing approvals over the last two years"

get_data(dataset_id="BA_GCCSA", filters={"region": "nsw", "measure": "dwelling_units"}, start_period="2024")

"Compare monthly CPI inflation in Sydney vs Melbourne"

get_data(dataset_id="CPI_MONTHLY", filters={"region": ["sydney", "melbourne"], "measure": "change_year"}, start_period="2023")

(CPI itself publishes only the national weighted average at quarterly cadence; the monthly indicator carries per-city series.)

Period formats

ABS uses different period formats per dataflow. Pass start_period / end_period in the matching format:

Dataflows

Frequency

Format

Example

LF, BA_GCCSA, BUILDING_APPROVALS

Monthly

YYYY-MM

"2026-03"

BUILDING_ACTIVITY

Quarterly

YYYY-Qn

"2025-Q4"

CPI, WPI, PPI_FD, JV, ANA_AGG, LEND_HOUSING, ERP_Q

Quarterly

YYYY-Q*

"2025-Q4"

CPI_MONTHLY, HSI_M

Monthly

YYYY-MM

"2025-12"

AWE

Half-yearly

YYYY-S*

"2025-S2"

NOM (financial year), ABS_ANNUAL_ERP_ASGS2021

Annual

YYYY

"2025"

Verifying your install

The running MCP server reports its version on every DataResponse:

{ ..., "server_version": "0.2.11", ... }

If you see a value below the latest on PyPI, your uvx cache is stale. Either switch to ["--upgrade", "abs-mcp"] in your config (recommended), or refresh manually:

uvx --refresh abs-mcp --help
# Then fully quit and relaunch Claude Desktop (Cmd+Q — window-close is not enough).

Claude Desktop's MCP child processes are long-lived; refreshing the wheel cache does not restart an already-running server. Cold app launch is required.

Development

git clone https://github.com/Bigred97/abs-mcp.git
cd abs-mcp
uv sync --extra dev
uv pip install -e .

# Unit tests (no network)
uv run pytest

# Live integration tests (hits real ABS API)
uv run pytest -m live

The SQLite cache lives at ~/.abs-mcp/cache.db. Catalogue refreshes every 24h, codelists every 7 days, data responses every hour, latest 15 minutes. Delete the file to force a refresh.

How it works

When you ask Claude an ABS question, it picks the right tool, fills in the curated filters, and calls the live ABS API. You see the reasoning + tool call inline:

Claude reasoning + tool call panel

Claude does the picking; this server does the SDMX translation, unit attribution, and clean response shaping. You don't have to know what M13.3.1599.20.1.M means — and neither does Claude.

How it differs from existing ABS MCP servers

The one existing community option (seansoreilly/abs) exposes a single query_dataset tool that passes raw SDMX through. This package offers semantic tools and curated mappings for the highest-value dataflows so an LLM can answer real questions without you needing to know what M13.3.1599.20.1.M means.

Sister MCPs (Australian Public Data portfolio)

Want all 9 sources behind one REST API? The hosted gateway at ausdata.io adds cross-source joins, full history, webhooks, and HMAC-signed responses on top of these MCPs — free tier (500 calls/mo, no card).

  • abs-mcp — this one. Australian Bureau of Statistics (CPI, unemployment, ERP, building approvals)

  • rba-mcp — Reserve Bank of Australia (cash rate, lending stats, exchange rates)

  • ato-mcp — Australian Taxation Office (tax stats, ACNC charities)

  • apra-mcp — Australian Prudential Regulation Authority (banking, insurance, super)

  • aihw-mcp — Australian Institute of Health and Welfare

  • asic-mcp — Australian Securities and Investments Commission (company registers)

  • aemo-mcp — Australian Energy Market Operator (NEM dispatch, spot prices, generation)

  • au-weather-mcp — Open-Meteo (Bureau of Meteorology aggregator)

  • wgea-mcp — Workplace Gender Equality Agency

  • aus-identity — Postcode / state / ABN normalisation helper used by all sisters

Changelog

See CHANGELOG.md for release history.

License

MIT — Harry Vass, 2026.

Available Tools

7 tools
describe_datasetA

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.

Inputs: dataset_id (required). Returns: id, name, abs_url, dimensions, +3 more

get_dataA

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.

Inputs: dataset_id (required), format, filters, end_period, +1 more. Returns: csv, unit, query, stale, +13 more

latestA

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. Same envelope as get_data.

Inputs: dataset_id (required), filters. Returns: csv, unit, query, stale, +13 more

list_curatedA

List the 10 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 10 curated dataflows: - 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)

Example: ids = list_curated() # → ['ABS_ANNUAL_ERP_ASGS2021', 'ANA_AGG', 'AWE', 'BA_GCCSA', 'CPI', # 'ERP_Q', 'JV', 'LEND_HOUSING', 'LF', '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. Always 10 entries today.

Inputs: no named parameters. Returns: result

release_calendarA

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 10 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.

Inputs: days_ahead. Returns: Upcoming ABS publications over a rolling horizon. Shape mirrors `rba-mcp.Releas…

search_datasetsA

Fuzzy-search ABS dataflow names, descriptions, and keywords.

Use this when you don't know the exact dataset ID. The 10 curated dataflows (LF, CPI, ANA_AGG, etc.) 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.

Inputs: query (required), limit. Returns: result

top_nA

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.

Inputs: measure (required), dataset_id (required), n, filters, +1 more. Returns: csv, unit, query, stale, +13 more

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.7/5.0

    Scored across 7 tools

    Disambiguation5/5

    Each tool has a clearly distinct purpose: describe for metadata, get_data for historical data, latest for current, list_curated for curated IDs, release_calendar for schedule, search for discovery, top_n for ranking. No overlap in functionality.

    Naming Consistency4/5

    Most tool names follow a verb_noun pattern (describe_dataset, search_datasets, list_curated), but get_data, top_n, and release_calendar use different forms. However, all are snake_case and descriptive, making them predictable.

    Tool Count5/5

    Seven tools cover the essential operations for a statistics bureau server: metadata discovery, data retrieval, listing curated sources, release schedule, and search. The scope is neither too broad nor too narrow.

    Completeness5/5

    The tool set covers querying, latest values, ranking, metadata description, search, and release calendar. For a read-only statistical data portal, this is comprehensive; no obvious gaps for common workflows.

    Maintenance

    ActivityNo data
    ResponsivenessSyncing

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      C
      maintenance
      Enables querying the ONS NOMIS labour market and census API from Claude, with tools for dataset discovery, dimension exploration, code resolution, and data fetching while guarding against silent truncation.
      6
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI agents to browse, search, and query Australian Bureau of Statistics datasets through the ABS Data API, exposing dataflow discovery, dimension/code structure inspection, and SDMX dataKey-based retrieval of time-indexed observations with decoded labels. It can run as a hosted gateway endpoint or a local stdio server.
      99 npm
      MIT