sdmx-data-mcp
An MCP server that lets an AI assistant discover and retrieve official statistics from SDMX services.
Built on the BIS's own pysdmx library.
Why
Existing SDMX MCP servers navigate metadata well and then hand back a query URL. The assistant ends up with a link, not numbers.
sdmx-data-mcp finishes the job: get_data returns the observations.
Install
pip install sdmx-data-mcp
Python 3.10+.
Configure your client
Claude Code
claude mcp add sdmx -- sdmx-data-mcp
Claude Desktop — in claude_desktop_config.json:
{
"mcpServers": {
"sdmx": {
"command": "sdmx-data-mcp"
}
}
}
Cursor — in .cursor/mcp.json:
{
"mcpServers": {
"sdmx": {
"command": "sdmx-data-mcp"
}
}
}
If sdmx-data-mcp is not on your PATH, use the absolute path to the
executable in the environment where you installed it, or
"command": "python", "args": ["-m", "sdmx_data_mcp"].
To share one instance over the network instead:
sdmx-data-mcp --transport http --host 127.0.0.1 --port 8000
The four tools
Meant to be called in order.
| Tool | Purpose |
|---|---|
list_services |
Known endpoints, plus any SDMX-REST v2 base URL you supply |
search_dataflows |
One dataflows() call, then local term matching |
inspect_dataflow |
Components, available codes, size signals |
get_data |
Retrieves the observations |
A worked example
Asking an assistant "how much do Swiss banks have in foreign claims since 2020?" drives this sequence against the BIS.
1. Find the dataflow.
search_dataflows(query="consolidated banking")
-> ref: BIS:WS_CBS_PUB(1.0)
name: Consolidated banking
matched_on: name
2. Work out what "Swiss" actually means here.
inspect_dataflow(ref="BIS:WS_CBS_PUB(1.0)", find_code="CH")
-> code_locations:
L_REP_CTY (reporting country)
CBS_BANK_TYPE (bank type (shares a country codelist))
L_CP_COUNTRY (counterparty country)
series_count: 228370
size_warning: This scope holds 228,370 series ...
next_step: That code is ambiguous - it appears in 3 components ...
This is the step that prevents a confidently wrong answer. CH is available
in three different components of this dataflow, and each answers a different
question: claims by Swiss banks, claims on Switzerland, or a bank-type
code that happens to share the country codelist.
3. Scope it, and check the size.
inspect_dataflow(
ref="BIS:WS_CBS_PUB(1.0)",
filters="L_MEASURE = 'S' AND L_REP_CTY = 'CH' AND FREQ = 'Q'",
)
-> series_count: 6671 (down from 228370)
If the question was only whether data exist, the answer is already here.
4. Retrieve the numbers.
get_data(
ref="BIS:WS_CBS_PUB(1.0)",
filters="L_MEASURE = 'S' AND L_REP_CTY = 'CH' AND FREQ = 'Q'"
" AND TIME_PERIOD >= '2020-Q1'",
columns=["OBS_VALUE"],
limit=500,
)
-> row_count: 500
total_rows_available: 112648
truncated: true
next_step: Truncated: 112,648 rows matched but only 500 were returned.
These are the first rows in service order, not a sample ...
Services
pysdmx.api.dc.Endpoints currently ships exactly one endpoint, the BIS. Every
tool therefore takes a service argument accepting any SDMX-REST v2 base
URL as a first-class input:
search_dataflows(query="prices", service="https://your-service.org/api/v2")
The service must return structural metadata as SDMX-JSON 2.0.0 and data as SDMX-CSV. Other providers (ECB, OECD, IMF, Eurostat, ILO) are deliberately not hardcoded, because each needs verifying against those requirements first, and listing them unverified would invite confident failures.
Design notes
The non-obvious SDMX rules are enforced by the server rather than left for the assistant to remember.
Conjunctions only. The query parser supports AND. Never generate OR;
for several values of one component use IN ('A', 'B').
Availability is not validity. inspect_dataflow reports codes for which
data currently exist. A code absent from that list may still be valid in the
full codelist, so its absence is not evidence that something does not exist.
Size before retrieval. obs_count is frequently unreported — the BIS
returns None for it, on both full and filtered scopes — so series_count
is the signal relied on. Tools warn when a scope is large enough to truncate.
Truncation is not sampling. When truncated is true, the rows returned
are the first ones in service order. They must not be aggregated as though
they were a representative sample.
Time filters degrade gracefully. TIME_PERIOD comparisons are pushed
down to the service first. If the service rejects the query with a client
error, the clause is stripped, the narrower query is retried, and the cutoff
is applied with pandas — reported in filter_fallback. It deliberately does
not fall back on NotFound, Unavailable or InternalError, where
dropping a clause cannot help and would only obscure the real error.
Errors keep their meaning. The pysdmx error hierarchy is preserved rather
than flattened, so an assistant can tell a transient outage (unavailable,
retriable) from a bad reference (not_found, not retriable), instead of
retrying blindly or giving up too early.
Development
pip install -e ".[dev]"
ruff format && ruff check && mypy
pytest --cov=sdmx_data_mcp --cov-branch --cov-report=term-missing
The suite holds 100% statement and branch coverage. Most server tests inject
a fake connector so every branch is reachable deterministically; a separate
end-to-end module drives the real PandasConnector against respx-mocked
responses, so drift in URL construction or SDMX-CSV parsing surfaces there.
Relationship to pysdmx
This package depends on pysdmx[data] from PyPI and does not fork or vendor
it. The same server has also been proposed upstream as
bis-med-it/pysdmx#669; this
package exists so it is installable today regardless of what happens there.
Licence
Apache-2.0. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sdmx_data_mcp-0.1.0.tar.gz.
File metadata
- Download URL: sdmx_data_mcp-0.1.0.tar.gz
- Upload date:
- Size: 35.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b26ba8ecb2d64c101e9f5211c345807c6eef36402667d39616fe4ea5eed3d9d2
|
|
| MD5 |
519259da87b1404fd6e9daccf2576bc3
|
|
| BLAKE2b-256 |
a1f1755aaa7cb7cac18c128c8b0a4b182871d5a848c85d33c124c9b85a11d546
|
Provenance
The following attestation bundles were made for sdmx_data_mcp-0.1.0.tar.gz:
Publisher:
publish.yml on markchweya/sdmx-data-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sdmx_data_mcp-0.1.0.tar.gz -
Subject digest:
b26ba8ecb2d64c101e9f5211c345807c6eef36402667d39616fe4ea5eed3d9d2 - Sigstore transparency entry: 2419471488
- Sigstore integration time:
-
Permalink:
markchweya/sdmx-data-mcp@40149e6ffe851087e56df3be699585c14b6e21e1 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/markchweya
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@40149e6ffe851087e56df3be699585c14b6e21e1 -
Trigger Event:
release
-
Statement type:
File details
Details for the file sdmx_data_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sdmx_data_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 25.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
978bb37f69a0d9f5f643f9b3c44266292abf24abfeaacf8efd076fe96cbc7fc7
|
|
| MD5 |
48d20b5b70e06bcb17b15941bcb4d51f
|
|
| BLAKE2b-256 |
650ec7a9d5adcab8ebdbadb7c1da200602c930ed47a9db1408b217c3d34d3f56
|
Provenance
The following attestation bundles were made for sdmx_data_mcp-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on markchweya/sdmx-data-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sdmx_data_mcp-0.1.0-py3-none-any.whl -
Subject digest:
978bb37f69a0d9f5f643f9b3c44266292abf24abfeaacf8efd076fe96cbc7fc7 - Sigstore transparency entry: 2419472332
- Sigstore integration time:
-
Permalink:
markchweya/sdmx-data-mcp@40149e6ffe851087e56df3be699585c14b6e21e1 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/markchweya
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@40149e6ffe851087e56df3be699585c14b6e21e1 -
Trigger Event:
release
-
Statement type: