Skip to main content
Glama
nescoffee-create

SDMX MCP Gateway

SDMX MCP Gateway

A Model Context Protocol (MCP) server that provides progressive discovery tools for SDMX statistical artefacts and data. This implementation enables AI agents to explore and access SDMX-compliant statistical data repositories through interactive tools, resources, and prompts.

Version 0.2.0 - Now with structured outputs, Streamable HTTP transport, and elicitation support.

šŸš€ Key Features

  • Progressive Discovery: Reduces metadata transfer from 100KB+ to ~2.5KB

  • Structured Outputs: All tools return validated Pydantic models

  • Multiple Transports: STDIO (development) and Streamable HTTP (production)

  • Interactive Elicitation: User confirmation dialogs for endpoint switching

  • Multi-Provider Support: SPC, FBOS, SBS, ECB, UNICEF, IMF, OECD, ESTAT, ILO, ABS, BIS

Related MCP server: StatTools

Quick Start

A public instance of this server is hosted on Railway. Point any MCP client at the URL below and you can skip cloning, installing dependencies, and managing a Python environment.

https://sdmx-mcp-gateway-production.up.railway.app/mcp

Transport is Streamable HTTP. The endpoint is shared and stateless from the client's perspective; each MCP session gets its own server-side state (endpoint selection, client pool, mismatch-hint cache).

Quick check that it responds:

curl -X POST https://sdmx-mcp-gateway-production.up.railway.app/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}'

See MCP Client Configuration for ready-to-paste configs for Claude Code, Claude Desktop, Codex, Cursor, Zed, and OpenCode.

Health Status

A standalone monitor checks the hosted gateway and every provider endpoint (through the gateway and directly) every two hours. See monitor/README.md for running or deploying it. Once deployed, its status page shows current health, per-endpoint history, and whether a failure sits in the gateway or the upstream provider.

Self-Hosting

If you prefer to run the server yourself (offline use, private deployments, development on the tools themselves), see Installation and Running the Server.

cd sdmx-mcp-gateway
uv sync
uv run python main_server.py                                     # STDIO, for local clients
uv run python main_server.py --transport http --port 8000        # HTTP, for remote clients
uv run mcp dev ./main_server.py                                  # MCP Inspector (browser UI)

The Problem We Solve

Traditional SDMX queries with references=all return 100KB+ of XML metadata, overwhelming LLM context windows. Our progressive discovery approach provides a layered exploration:

Step

Operation

Data Size

1

Find dataflows by keyword

~300 bytes

2

Get dimension structure

~1KB

3

Explore specific dimension codes

~500 bytes

4

Check data availability

~700 bytes

5

Build final query URL

~200 bytes

Total

~2.5KB

Architecture

sdmx-mcp-gateway/
ā”œā”€ā”€ main_server.py              # FastMCP server with CLI
ā”œā”€ā”€ app_context.py              # Lifespan management & shared resources
ā”œā”€ā”€ config.py                   # Endpoint configuration
ā”œā”€ā”€ sdmx_progressive_client.py  # SDMX 2.1 REST client
ā”œā”€ā”€ utils.py                    # Validation & utilities
ā”œā”€ā”€ models/
│   ā”œā”€ā”€ __init__.py
│   └── schemas.py              # Pydantic output schemas
ā”œā”€ā”€ tools/
│   ā”œā”€ā”€ sdmx_tools.py           # Discovery tools implementation
│   └── endpoint_tools.py       # Endpoint management
ā”œā”€ā”€ resources/
│   └── sdmx_resources.py       # MCP resources
ā”œā”€ā”€ prompts/
│   └── sdmx_prompts.py         # Guided prompts
└── tests/                      # Test suite

Available Tools

Discovery Tools

Tool

Description

Output Schema

list_dataflows

Find dataflows by keyword

DataflowListResult

get_dataflow_structure

Get dimensions and structure

DataflowStructureResult

get_dimension_codes

Explore codes for a dimension

DimensionCodesResult

get_data_availability

Check what data exists

DataAvailabilityResult

get_structure_diagram

Generate Mermaid diagram of relationships

StructureDiagramResult

compare_structures

Compare two structures for differences

StructureComparisonResult

validate_query

Validate query parameters

ValidationResult

build_key

Construct SDMX key

KeyBuildResult

build_data_url

Generate data retrieval URL

DataUrlResult

get_codelist

Browse specific codelist

dict

SDMX 2.1 has no server-side pagination, so list_dataflows fetches a provider's entire dataflow listing under the hood even when limit is small; for ESTAT that listing alone is 37 MB. The parsed result is cached process-wide (shared across every session, not per client) for DATAFLOW_CACHE_TTL_S seconds (default 900, 15 minutes), keyed on the base URL, agency, and the other parameters that change the answer. The result's next_step field always states whether that call was served from cache and, if so, how old the entry is, so a caller never has to guess. Pass fresh=True to bypass the cache and force a live re-fetch; the fresh result still refreshes the cache for everyone else. Use fresh=True for liveness checks, where a cached answer would say nothing about whether the provider is reachable right now.

Reference Metadata

Tool

Description

Output Schema

get_reference_metadata

Summarise source, methodology, licence and caveats for a dataflow

ReferenceMetadataResult

get_metadata_attribute

Get every value of one metadata attribute, with the slice each applies to

MetadataAttributeValuesResult

Reference metadata is the descriptive material about a dataflow rather than its structure: who compiled it, from what source, under what licence, with what caveats. Coverage varies by provider, so the result's channels field reports which channel was available: .Stat Suite deployments (SPC, FBOS, SBS, OECD) publish it through a v2 MSD query, some other providers carry equivalent detail only in ordinary DSD attributes on the data message, and some publish neither. A channel status of inconclusive means the query did not produce a usable answer; that is different from a confirmed absence, which is what empty reports.

Pass key to narrow the query to one series. This matters for large dataflows: SPC's DF_SDG metadata query is 5.37 MB unfiltered against 5.6 KB with a partial key, and the tool refuses an unfiltered query over 2 MB (too_broad) by aborting the read partway through rather than downloading it in full; the same cap applies to both the MSD query and the DSD-attribute fallback used by providers without a /v2/ endpoint.

get_reference_metadata: the summary

get_reference_metadata returns one entry per attribute the provider declares, in metadata_attributes, plus a coverage count and a per-channel channels status. Each attribute carries:

  • status: populated when the provider published at least one value, declared_empty when every occurrence in the response read was blank -- for the whole dataflow when no key was supplied, or for the slice queried when one was, since a keyed request only reads that slice. A declared-but-empty attribute is a real, observed answer, not a missing one, and it is listed rather than omitted, so a blank licence field reads differently from a provider that has no licence concept at all.

  • value and drill_down: value carries the headline text when exactly one distinct value exists and either it describes the whole dataflow (dataflow/dataset scope, provider-marked unqualified), or it was identical on every data row this query actually returned (all_observed_rows scope). The second case is common: SPC's DF_SDG publishes the same value on every per-country row and has no dataflow-wide row at all, so before this rule every one of its populated attributes came back value: null. drill_down is false only for dataflow/dataset scope; for all_observed_rows it stays true, since that scope says nothing about rows the query did not return (a different key, or rows beyond a truncated response's row cap) and the per-row detail behind it still matters. When the attribute's values differ across the rows read, value is null and drill_down is true, meaning no single value can stand in as the answer.

  • distinct_values and scope: how many distinct values were found, and what the headline (when present) attaches to: the whole dataflow (dataflow/dataset), every row this query returned (all_observed_rows, weaker than dataflow: no provider ever marked it unqualified), or one slice (partial_key).

coverage (declared / populated / empty) is reported only when the MSD channel itself answered found on an untruncated read: that is the only channel that can see a declared-but-empty attribute (parse_msd_csv's declared_empty status). Neither an MSD empty answer nor the DSD-attribute fallback can establish it, even when both agree: the DSD fallback only ever sees what a message actually populates, so it can never confirm that a provider declares nothing further, and a truncated MSD read cannot rule out a value past the row cap. coverage is None in every one of those cases -- when the only channel that answered was the DSD-attribute fallback, which shows populated attributes only; when the MSD channel answered empty (with or without the DSD fallback also resolving); or when the MSD channel found something but the read was cut off before finishing.

get_metadata_attribute: the drill-down

Call get_metadata_attribute(dataflow_id, attribute_id, key=None, agency_id=None) after get_reference_metadata reports drill_down: true for an attribute, to read every distinct value with the dimension key (key_context) it applies to. attribute_id is the short id from the summary, not the full dotted path. The result (MetadataAttributeValuesResult) has no separate error field; every case below is a normally-shaped result distinguished by total and by the text of notes. Four answers matter and are kept distinct:

  • Populated: one entry per distinct (value, key_context) pair; the same value may appear multiple times with different key_context values. total counts these pairs, while the summary's distinct_values counts distinct values only (the two need not match), and truncated is true when more than 200 pairs exist, with values limited to the first 200.

  • Declared but empty: total: 0, values: [], and a note stating the attribute is declared and left blank -- for the whole dataflow when no key was supplied, for the slice queried when one was. The first note does not start with "Error:".

  • Unknown attribute id: total: 0, values: [], and a first note starting with "Error: " reading "Error: Unknown attribute '<id>' for <dataflow>: declared attributes are <ids>", naming the dataflow's declared attribute ids so a typo reads as "here is what exists" rather than as an empty result. This wording is only used when the MSD channel itself answered found: that is the one channel outcome that can vouch for a provider's full declared set, so the listed ids are genuinely everything declared. A caller distinguishes this from the declared-but-empty case above by checking whether the first note starts with "Error:", not by looking for a field that does not exist on this result.

  • No channel confirmed a declared set: total: 0, values: [], and notes explaining which channel could not answer and why that is not evidence the attribute is missing. This covers an MSD channel that answered too_broad, inconclusive or unsupported, and also the MSD channel's own empty answer -- even when the DSD-attribute fallback separately found something or itself resolved to empty, since that fallback only ever sees what a message actually populates and can never see an attribute the DSD declares but a given response leaves blank, so it cannot vouch for the full declared set on its own. Like the declared-but-empty case, the notes here do not start with "Error:".

Each value's key_context is null in two different situations that a caller must not conflate: from the MSD channel, null means the value is genuinely dataflow-wide; from the DSD-attribute fallback channel (used by providers without a /v2/ endpoint), null means that channel has no per-value key to report at all, even when the value actually attaches to one series or observation rather than to the whole dataflow. A note on the result says which channel supplied the attribute when this applies.

Endpoint Management

Tool

Description

Output Schema

get_current_endpoint

Show the session's default provider

EndpointInfo

list_available_endpoints

List all configured providers

EndpointListResult

The session default is set once at startup from the SDMX_ENDPOINT env var and is not mutable at runtime. To target a specific provider for an individual call, pass endpoint=<KEY> to any endpoint-scoped tool.

Resources

  • sdmx://agencies - List of known SDMX data providers

  • sdmx://agency/{id}/info - Specific agency details

  • sdmx://formats/guide - Data format comparison

  • sdmx://syntax/guide - Query syntax reference

Prompts

  • discovery_guide - Step-by-step data discovery workflow

  • troubleshooting_guide - Common issue resolution

  • best_practices - Use-case specific guidance

  • query_builder - Interactive query construction

Supported Data Sources

Key

Provider

Description

Constraints

SPC

Pacific Data Hub

Pacific regional statistics (default)

Actual (single + bulk)

FBOS

Fiji Bureau of Statistics

Fiji official national statistics

Actual (single + bulk)

SBS

Samoa Bureau of Statistics

Samoa official national statistics

Actual (single + bulk)

ECB

European Central Bank

European financial statistics

Allowed (single + bulk)

UNICEF

UNICEF

Children and youth statistics

Actual (single + bulk)

IMF

International Monetary Fund

Global financial statistics

Actual (single)

OECD

OECD

Economic and social statistics

Actual (single)

BIS

Bank for International Settlements

International financial statistics

Actual (single)

ABS

Australian Bureau of Statistics

Australian official statistics

Actual (single)

ILO

International Labour Organization

Labour and employment statistics

Actual (single)

ESTAT

Eurostat

European Union official statistics

None

Target a provider per call:

# Pass endpoint= on any endpoint-scoped tool
list_dataflows(endpoint="ECB", limit=10)
get_dataflow_structure(dataflow_id="DF_CPI", endpoint="FBOS")

# Or rely on the session default (set at startup from SDMX_ENDPOINT env var)
list_dataflows(limit=10)

See docs/ENDPOINT_CONFIGURATION.md for provider-specific behaviours and constraint strategies.

Installation

Prerequisites

  • Python 3.12 or higher

  • uv (recommended) or pip

cd sdmx-mcp-gateway
uv sync

Using pip

cd sdmx-mcp-gateway
pip install -r requirements.txt

Dependencies

  • mcp[cli]>=1.26.0 - Model Context Protocol SDK

  • pydantic>=2.0.0 - Structured output validation

  • httpx>=0.27.0 - Async HTTP client

  • certifi>=2024.0.0 - SSL certificates

Running the Server

CLI Options

uv run python main_server.py [OPTIONS]

Options:
  --transport, -t    Transport type: stdio, http, streamable-http (default: stdio)
  --host             Host for HTTP transport (default: HOST env or 0.0.0.0)
  --port, -p         Port for HTTP transport (default: PORT env or 8000)
  --stateless        Run in stateless mode (HTTP only)
  --json-response    Use JSON responses instead of SSE (HTTP only)
  --debug            Enable debug logging

Development Mode (STDIO)

# Direct execution
uv run python main_server.py

# With MCP Inspector (opens browser UI)
uv run mcp dev ./main_server.py

Production Mode (Streamable HTTP)

uv run python main_server.py --transport streamable-http --host 0.0.0.0 --port "${PORT:-8000}"

For container platforms such as Vercel, Railway, or Fly, prefer binding to 0.0.0.0 and reading the port from the platform-provided PORT environment variable. The server now fails fast if the installed MCP SDK ignores the requested HTTP bind settings, rather than silently falling back to localhost.

MCP Client Configuration

The recommended path is to point your client at the hosted Railway URL. Each section below shows:

  • Hosted (HTTP): uses https://sdmx-mcp-gateway-production.up.railway.app/mcp. Nothing to install beyond the client itself.

  • Self-hosted (STDIO): runs the server from a clone of this repo. Requires uv and git (see Installation).

Clients that only speak STDIO can still reach the hosted instance via the mcp-remote bridge, which proxies HTTP MCP servers through stdio via npx.

Claude Code

Hosted, one-liner:

claude mcp add --transport http sdmx-gateway https://sdmx-mcp-gateway-production.up.railway.app/mcp

Or in .claude/settings.json / ~/.claude/settings.json:

{
    "mcpServers": {
        "sdmx-gateway": {
            "type": "http",
            "url": "https://sdmx-mcp-gateway-production.up.railway.app/mcp"
        }
    }
}

Self-hosted (STDIO):

{
    "mcpServers": {
        "sdmx-gateway": {
            "command": "uv",
            "args": [
                "run",
                "--directory",
                "/path/to/sdmx-mcp-gateway",
                "python",
                "main_server.py"
            ]
        }
    }
}

If uv is not on your PATH, use the full path (e.g. "/home/user/.local/bin/uv").

OpenAI Codex CLI

Hosted, via ~/.codex/config.toml (uses mcp-remote to bridge HTTP into stdio):

[mcp_servers.sdmx]
command = "npx"
args = ["-y", "mcp-remote", "https://sdmx-mcp-gateway-production.up.railway.app/mcp"]
enabled = true
tool_timeout_sec = 120

Or via the CLI:

codex mcp add sdmx -- npx -y mcp-remote https://sdmx-mcp-gateway-production.up.railway.app/mcp

Self-hosted:

[mcp_servers.sdmx]
command = "uv"
args = ["run", "--directory", "/path/to/sdmx-mcp-gateway", "python", "main_server.py"]
enabled = true
tool_timeout_sec = 120

The command field must be the executable only. If uv or npx is not on your PATH, use the full path. Arguments go in args as a separate array.

Claude Desktop

Claude Desktop does not yet speak HTTP MCP natively, so use mcp-remote to reach the hosted server.

Config file locations:

  • Linux: ~/.config/Claude/claude_desktop_config.json

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Hosted:

{
    "mcpServers": {
        "sdmx-gateway": {
            "command": "npx",
            "args": [
                "-y",
                "mcp-remote",
                "https://sdmx-mcp-gateway-production.up.railway.app/mcp"
            ]
        }
    }
}

Self-hosted (STDIO):

{
    "mcpServers": {
        "sdmx-gateway": {
            "command": "uv",
            "args": [
                "run",
                "--directory",
                "/path/to/sdmx-mcp-gateway",
                "python",
                "main_server.py"
            ]
        }
    }
}

On Windows, escape the path: "C:\\path\\to\\sdmx-mcp-gateway".

Cursor

  1. Open Cursor Settings > MCP.

  2. Add a new global MCP server.

  3. Set the URL to https://sdmx-mcp-gateway-production.up.railway.app/mcp (Cursor supports Streamable HTTP servers directly).

For a self-hosted instance, use the STDIO command shown for Claude Code.

Zed

Zed uses "Context Servers" for MCP integration. Settings file:

  • Linux: ~/.config/zed/settings.json

  • macOS: ~/Library/Application Support/Zed/settings.json

  • Project-specific: .zed/settings.json in your project root

Add the context_servers key at the top level of your settings.json, alongside other settings like theme and ui_font_size.

Hosted (via mcp-remote):

{
    "context_servers": {
        "sdmx-gateway": {
            "command": {
                "path": "npx",
                "args": [
                    "-y",
                    "mcp-remote",
                    "https://sdmx-mcp-gateway-production.up.railway.app/mcp"
                ]
            }
        }
    }
}

Self-hosted:

{
    "context_servers": {
        "sdmx-gateway": {
            "command": {
                "path": "uv",
                "args": [
                    "run",
                    "--directory",
                    "/path/to/sdmx-mcp-gateway",
                    "python",
                    "main_server.py"
                ]
            }
        }
    }
}

OpenCode

~/.config/opencode/config.json:

{
    "mcpServers": {
        "sdmx-gateway": {
            "command": "npx",
            "args": [
                "-y",
                "mcp-remote",
                "https://sdmx-mcp-gateway-production.up.railway.app/mcp"
            ]
        }
    }
}

Or, for a self-hosted instance, swap to the uv run ... command shown in the Claude Code section.

Generic MCP Client (Streamable HTTP)

Any client with Streamable HTTP support connects directly to the hosted URL:

https://sdmx-mcp-gateway-production.up.railway.app/mcp

To run your own HTTP instance locally:

uv run python main_server.py --transport http --port 8000

Point the client at http://localhost:8000/mcp. Add --stateless --json-response if your client cannot consume Server-Sent Events.

Usage Examples

Progressive Discovery Workflow

# Step 1: Find relevant dataflows
list_dataflows(keywords=["digital", "development"])
# → Returns: DataflowListResult with matching dataflows

# Step 2: Get structure
get_dataflow_structure("DF_DIGITAL_DEVELOPMENT")
# → Returns: DataflowStructureResult with dimensions

# Step 3: Find country code
get_dimension_codes("DF_DIGITAL_DEVELOPMENT", "GEO_PICT", search_term="tonga")
# → Returns: DimensionCodesResult with TO = Tonga

# Step 4: Check availability
get_data_availability("DF_DIGITAL_DEVELOPMENT", dimension_values={"GEO_PICT": "TO"})
# → Returns: DataAvailabilityResult with time ranges

# Step 5: Build query
build_data_url("DF_DIGITAL_DEVELOPMENT", key="A..TO.", format_type="csv")
# → Returns: DataUrlResult with ready-to-use URL

Structure Relationship Visualization

Understand how SDMX structures relate to each other with Mermaid diagrams:

# See what a DSD references (codelists, concept schemes)
get_structure_diagram("datastructure", "DSD_DF_POP", direction="children")
# → Returns: StructureDiagramResult with mermaid_diagram field

# See what uses a codelist (impact analysis)
get_structure_diagram("codelist", "CL_FREQ", direction="parents")
# → Shows which DSDs and concept schemes use this codelist

# Get full relationship graph
get_structure_diagram("dataflow", "DF_POP", direction="both")
# → Shows both parent and child relationships

# Show version numbers on all nodes (important for impact analysis!)
get_structure_diagram("datastructure", "DSD_SDG", direction="children", show_versions=True)
# → Displays version numbers like "CL_FREQ v1.0", "CL_GEO v2.0"
# This is critical because different versions are independent -
# a dataflow using CL_FREQ v1.0 won't be affected by changes to v2.0

The mermaid_diagram field contains ready-to-render Mermaid code.

Without versions (default):

graph TD
    subgraph dataflow["Dataflows ⭐"]
        dataflow_DF_POP["šŸ“Š <b>DF_POP</b><br/>Population Statistics"]
    end
    subgraph datastructure["Data Structures"]
        datastructure_DSD_POP["šŸ—ļø DSD_POP<br/>Population DSD"]
    end
    subgraph codelist["Codelists"]
        codelist_CL_FREQ["šŸ“‹ CL_FREQ<br/>Frequency"]
        codelist_CL_GEO["šŸ“‹ CL_GEO<br/>Geography"]
    end
    dataflow_DF_POP -->|"defines structure"| datastructure_DSD_POP
    datastructure_DSD_POP -->|"uses codelist"| codelist_CL_FREQ
    datastructure_DSD_POP -->|"uses codelist"| codelist_CL_GEO

With show_versions=True (shows exact version dependencies):

graph TD
    subgraph datastructure["Data Structures ⭐"]
        datastructure_DSD_SDG["šŸ—ļø <b>DSD_SDG</b> v3.0<br/>DSD for SDG"]
    end
    subgraph codelist["Codelists"]
        codelist_CL_FREQ["šŸ“‹ CL_FREQ v1.0<br/>Frequency"]
        codelist_CL_GEO["šŸ“‹ CL_GEO v2.0<br/>Geography"]
    end
    datastructure_DSD_SDG -->|"uses codelist"| codelist_CL_FREQ
    datastructure_DSD_SDG -->|"uses codelist"| codelist_CL_GEO

Comparing Structures

Identify differences between two structures (useful for version upgrades and cross-structure analysis).

Comparing Codelists (compares actual codes):

# Compare two versions of a codelist - what codes changed?
compare_structures(
    structure_type="codelist",
    structure_id_a="CL_GEO",
    version_a="1.0",
    version_b="2.0"
)
# → Shows added/removed/renamed codes between versions

# Compare two different codelists - find intersection and differences
compare_structures(
    structure_type="codelist",
    structure_id_a="CL_FREQ",
    structure_id_b="CL_TIME_FREQ"
)
# → Shows which codes are unique to each, and which are shared

Comparing DSDs (compares codelist/conceptscheme references):

# Compare two versions of a DSD - what codelist references changed?
compare_structures(
    structure_type="datastructure",
    structure_id_a="DSD_SDG",
    version_a="2.0",
    version_b="3.0"
)
# → Shows added/removed/version-changed codelist references

# Compare two different DSDs
compare_structures(
    structure_type="datastructure",
    structure_id_a="DSD_SDG",
    structure_id_b="DSD_EDUCATION"
)
# → Shows which codelists are unique to each, and which are shared

The comparison identifies:

  • āž• Added: Items that exist in B but not A

  • āž– Removed: Items that exist in A but not B

  • šŸ”„ Modified: Same ID but changed (version change for DSD refs, name change for codes)

  • āœ“ Unchanged: Identical items in both

Example codelist comparison output:

Comparing codelist CL_GEO: v1.0 → v2.0
Total codes: A has 25, B has 28

Summary: 5 change(s) detected
   - āž• Added codes: 3
   - āž– Removed codes: 0
   - šŸ”„ Name changed: 2
   - āœ“ Unchanged: 23

āž• Added codes:
   - `PW`: Palau
   - `MH`: Marshall Islands
   - `FM`: Federated States of Micronesia

Example DSD comparison with diff diagram:

graph LR
    subgraph comparison["Structure Comparison"]
        A["šŸ—ļø DSD_SDG<br/>v3.0"]
        B["šŸ—ļø DSD_EDUCATION<br/>v1.0"]
    end
    subgraph added_group["āž• Added"]
        add_CL_EDUCATION["šŸ“‹ CL_EDUCATION_INDICATORS<br/>v1.0"]
    end
    subgraph removed_group["āž– Removed"]
        rem_CL_SDG["šŸ“‹ CL_SDG_INDICATORS<br/>v3.0"]
    end
    subgraph changed_group["šŸ”„ Version Changed"]
        chg_CL_GEO["šŸ“‹ CL_GEO<br/>v1.0 → v2.0"]
    end
    A -.->|removed| rem_CL_SDG
    B -->|added| add_CL_EDUCATION
    A -.->|was| chg_CL_GEO
    B -->|now| chg_CL_GEO
    style add_CL_EDUCATION fill:#c8e6c9,stroke:#388e3c
    style rem_CL_SDG fill:#ffcdd2,stroke:#d32f2f
    style chg_CL_GEO fill:#fff9c4,stroke:#fbc02d

Targeting a Provider Per Call

Every endpoint-scoped tool accepts an optional endpoint=<KEY> argument:

list_dataflows(endpoint="ECB", limit=10)
get_dataflow_structure(dataflow_id="EXR", endpoint="ECB")
build_data_url(dataflow_id="DF_CPI", filters={"GEO_AREA": "FJI"}, endpoint="FBOS")

Calls without endpoint= use the session's default (set at server startup from the SDMX_ENDPOINT env var). Parallel calls to different providers are safe — each resolves independently.

Structured Outputs

All tools return Pydantic models with validated, typed data:

# Example: DataflowListResult
{
  "discovery_level": "overview",
  "agency_id": "SPC",
  "total_found": 45,
  "showing": 10,
  "offset": 0,
  "limit": 10,
  "dataflows": [
    {"id": "DF_GDP", "name": "GDP Statistics", "description": "..."},
    ...
  ],
  "pagination": {
    "has_more": true,
    "next_offset": 10,
    "total_pages": 5,
    "current_page": 1
  },
  "next_step": "Use get_dataflow_structure() to explore a dataflow"
}

Testing

# Run all tests
uv run pytest

# Run with coverage
uv run pytest --cov=. --cov-report=html

# Run specific test categories
uv run pytest tests/unit/
uv run pytest tests/integration/
uv run pytest tests/e2e/

Known Limitations

Multi-User Endpoint Isolation

Each MCP session has its own client pool (one SDMXProgressiveClient per endpoint it has touched) and its own mismatch-hint registry. STDIO mode uses a single session; HTTP transport uses Mcp-Session-Id headers for per-user isolation. Sessions timeout after 30 minutes of inactivity. The session default endpoint is immutable at runtime — set it via the SDMX_ENDPOINT env var at server startup.

See docs/MULTI_USER_CONSIDERATIONS.md for production deployment details.

Project Status

Feature

Status

SDK upgrade (v1.26.0)

āœ… Complete

Structured outputs

āœ… Complete

Streamable HTTP transport

āœ… Complete

Lifespan context

āœ… Complete

Elicitation support

āœ… Complete

Icons & metadata

šŸ”„ Pending

Documentation

āœ… Complete

See TODO.md for detailed modernization progress.

Contributing

Key areas for contribution:

  • Additional SDMX provider support

  • Enhanced semantic search

  • Performance optimization

  • Test coverage expansion

References

License

MIT License - See LICENSE file for details.

Available Tools

20 tools
build_data_urlA
Generate final SDMX REST API URLs for data retrieval.

Creates URLs that can be used directly to download data in various formats.
This is the final step in the SDMX query construction process.

Args:
    dataflow_id: The dataflow to query
    key: The data key (use build_key() to construct), or use filters instead
    filters: Dictionary of dimension_id -> code (alternative to key)
    start_period: Start of time range (optional)
    end_period: End of time range (optional)
    format_type: Output format (csv, json, xml)
    agency_id: The agency (uses session endpoint if not specified)
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.

Returns:
    Structured result with the complete data URL and usage information
ParametersJSON Schema
NameRequiredDescriptionDefault
keyNo
filtersNo
endpointNo
agency_idNo
end_periodNo
dataflow_idYes
format_typeNocsv
start_periodNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
keyYesSDMX key used
urlYesComplete data retrieval URL
noteNoAdditional notes (e.g., version resolution)
usageYesInstructions for using the URL
formatYesOutput format (csv, json, xml)
versionYesResolved dataflow version
time_rangeNoTime period filter if specified
dataflow_idYesDataflow identifier
formats_availableNoAvailable output formats
dimension_at_observationYesObservation dimension setting

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It explains the tool produces URLs and returns a structured result, but does not explicitly disclose whether any network request is made, whether validation occurs, or any permission requirements. This is acceptable for a URL-building tool but lacks deeper behavioral detail.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is structured with an Args/Returns format appropriate for an 8-parameter tool. The first two sentences are slightly redundant ('Generate final SDMX REST API URLs...' and 'Creates URLs...'), but they add useful detail about formats and direct download use.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity, the description covers all parameters, indicates the return type, and situates the tool as the final step in a pipeline. The output schema exists, so detailed return values are less critical. It does not explain every sibling relationship, but enough context is provided.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides only parameter titles with no descriptions (0% coverage), so the description's Args section is essential. It explains each parameter, including the distinction between key and filters, format options, and the endpoint override concept. Some descriptions are brief (e.g., 'Start of time range') but generally sufficient.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description states a specific verb ('Generate'), resource ('SDMX REST API URLs'), and purpose ('for data retrieval'). It also positions itself as 'the final step in the SDMX query construction process,' which clearly distinguishes it from siblings like build_key and probe_data_url.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly frames when to use the tool ('final step in the SDMX query construction process') and mentions using build_key() to construct the key, providing a clear alternative. However, it does not explicitly state when NOT to use it or contrast all sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

build_keyA
Build a properly formatted SDMX key from dimension values.

This helper tool constructs the key string with dimensions in the correct order
according to the dataflow structure. Unspecified dimensions are left empty
(meaning "all values").

Use this before build_data_url() to ensure your key has the correct format.

Args:
    dataflow_id: The dataflow identifier
    filters: Optional dict mapping dimension IDs to values
    agency_id: The agency (uses session endpoint if not specified)
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.

Returns:
    Structured result with the constructed key and usage information
ParametersJSON Schema
NameRequiredDescriptionDefault
filtersNo
endpointNo
agency_idNo
dataflow_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
keyYesConstructed SDMX key
usageYesHow to use this key
versionYesResolved dataflow version
dataflow_idYesDataflow identifier
key_templateYesTemplate showing dimension positions
dimensions_usedYesDimension values that were specified
dimensions_wildcardYesDimensions left as wildcard (all values)

TDQS

A4.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses key behaviors: 'Unspecified dimensions are left empty (meaning "all values")' and 'constructs the key string with dimensions in the correct order according to the dataflow structure.' It also mentions the structured result. However, it does not disclose error handling or validation behavior (e.g., what happens if a dimension value is invalid), which would have made it fully transparent. Hence a 4 rather than 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a concise introduction, a key behavioral note, an explicit usage direction, and a formatted Args list. Every sentence adds value; there is no fluff or repetition. It is appropriately sized for a non-trivial helper tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's role as a helper, the description covers its purpose, usage sequence relative to build_data_url, handling of unspecified dimensions, and return value. The output schema exists, so the description need not detail the return structure. It is suitably complete for an agent to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Despite 0% schema description coverage, the description includes an Args section that richly explains each parameter: dataflow_id is 'the dataflow identifier', filters is 'Optional dict mapping dimension IDs to values', agency_id 'uses session endpoint if not specified', and endpoint is explained with examples ('FBOS', 'ECB') and defaulting behavior. This fully compensates for the schema's lack of descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Build a properly formatted SDMX key from dimension values' and elaborates that it 'constructs the key string with dimensions in the correct order.' This specific verb+resource distinguishes it from sibling tools like build_data_url and validate_query, especially with the explicit 'Use this before build_data_url()' guidance.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells the agent when to use it: 'Use this before build_data_url() to ensure your key has the correct format.' It also clarifies optional endpoint and agency overrides, providing clear context for when to employ the tool versus alternatives. This is strong usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_time_availabilityA
Check whether a specific time period is likely to have data in a dataflow.

Uses the Actual ContentConstraint (FREQ values + TimeRange) to quickly
rule out periods that definitely have no data, without querying the data
itself. The constraint only tells us what CAN'T exist — a "plausible"
result means "worth querying", not "guaranteed to have data".

Use after identifying a dataflow and before building a data URL.
For confirmed availability, query the data directly via build_data_url().

Three-valued result:
- "no": constraint rules this out — don't bother querying
- "plausible": period within range and frequency matches — worth trying
- "plausible_different_frequency": data exists in this time window but
  at different granularity (e.g. querying monthly but only annual exists)

Args:
    dataflow_id: The dataflow to check
    query_period: The period to check (e.g. "2010", "2010-Q1", "2010-01", "2010-W05")
    agency_id: The agency (uses session endpoint if not specified)
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.

Returns:
    TimeAvailabilityResult with availability classification and reasoning
ParametersJSON Schema
NameRequiredDescriptionDefault
endpointNo
agency_idNo
dataflow_idYes
query_periodYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
overlapYesTime overlap: 'full', 'partial', or 'none'
query_endYesEnd of query period (ISO date)
dataflow_idYesDataflow checked
query_startYesStart of query period (ISO date)
availabilityYes'no' (ruled out), 'plausible' (worth querying), or 'plausible_different_frequency' (data exists but at different granularity)
query_periodYesPeriod that was queried
api_calls_madeNoNumber of API calls made
interpretationYesStep-by-step reasoning
recommendationYesSuggested next action
discovery_levelNo
implied_frequencyYesImplied frequency: A, S, Q, M, W, or D
constraint_time_endNoLatest date in constraint TimeRange
available_frequenciesYesFREQ codes from the constraint
constraint_time_startNoEarliest date in constraint TimeRange

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses how the tool works internally (Actual ContentConstraint), its limitation ('The constraint only tells us what CAN'T exist'), and exactly what 'plausible' means ('worth querying', not guaranteed). This is excellent behavioral transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is organized with a lead summary, then methodology, usage, result semantics, and args. Each section is information-dense and the content is front-loaded. No sentence is wasted; the structure makes it easy to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the tool's purpose, usage context, result values, parameters, and even notes the return type. Even though an output schema exists, the added context about the three-valued result and its implications makes this complete for an agent to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It does so thoroughly: the Args section explains every parameter, gives concrete query_period examples ('2010', '2010-Q1', '2010-01'), and clarifies the endpoint/agency_id defaults. This adds significant meaning beyond the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource: 'Check whether a specific time period is likely to have data in a dataflow.' It clearly distinguishes this tool from siblings by explaining that it uses the Actual ContentConstraint to rule out impossible periods, and contrasts it with build_data_url() for confirmed availability.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use it: 'Use after identifying a dataflow and before building a data URL.' It also tells the agent when not to rely on it ('For confirmed availability, query the data directly via build_data_url()'), and explains the meaning of each result value so the agent knows how to act on the output.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

compare_dataflow_dimensionsA
Compare dimension structures across two dataflows to understand how they relate.

Use this whenever you want to combine or contrast data from two dataflows.
Returns which dimensions are shared, whether their codes overlap, time period
coverage, and recommended join columns. Works across providers too — e.g.
compare SPC population data with UNICEF child health indicators.

**When to use this tool:**
- After discovering dataflows with find_code_usage_across_dataflows(), compare
  them to understand how they can be joined.
- When a user asks about combining datasets from different topics or providers.
- To check geographic, temporal, and dimensional overlap before writing queries.

Supports cross-provider comparison (e.g., SPC vs IMF) by specifying endpoint_a/b.
When endpoints are omitted, uses the current session endpoint.

Args:
    dataflow_id_a: First dataflow identifier
    dataflow_id_b: Second dataflow identifier
    endpoint_a: Optional endpoint key for dataflow A (e.g., "SPC", "IMF", "ECB")
    endpoint_b: Optional endpoint key for dataflow B
    ctx: MCP context

Returns:
    DataflowDimensionComparisonResult with dimension comparison, overlap stats,
    and join column recommendations
ParametersJSON Schema
NameRequiredDescriptionDefault
endpoint_aNo
endpoint_bNo
dataflow_id_aYes
dataflow_id_bYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataflow_aYes
dataflow_bYes
dimensionsYes
endpoint_aYesEndpoint key used for dataflow A (e.g. 'SPC')
endpoint_bYesEndpoint key used for dataflow B (e.g. 'IMF')
next_stepsNo
join_columnsNoRecommended join keys
time_overlapNoTime period overlap between the two dataflows. None when constraint time ranges are unavailable.
api_calls_madeNo
interpretationNo
dataflow_name_aNo
dataflow_name_bNo
discovery_levelNo
shared_dimensionsNoSame dim ID, same codelist ID+agency
compatible_dimensionsNoSame dim ID, different codelist

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses default endpoint behavior ('When endpoints are omitted, uses the current session endpoint') and cross-provider support, adding useful context beyond the schema. It does not explicitly state read-only behavior, but 'compare' and the nature of the output strongly imply a non-mutating operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a summary, usage guidance, and parameter details. While it is longer than a simple two-liner, each section earns its place—especially the 'When to use' bullets and endpoint behavior. The Args section partially duplicates the schema but adds examples, making it valuable rather than repetitive.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has an output schema, so return values are covered externally. The description covers when to use, parameter semantics, default endpoint behavior, and cross-provider capability, making it complete for a comparison tool. It lacks explicit error-handling notes or prerequisites, but these are not critical for the tool's primary use case.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It defines each parameter clearly: dataflow_id_a/b as identifiers, endpoint_a/b as optional with examples ('SPC', 'IMF', 'ECB') and explains the fallback to the session endpoint. This adds meaningful semantics beyond the bare schema titles, though it could be even more detailed about ID formats or constraints.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool 'Compare dimension structures across two dataflows to understand how they relate,' which is a specific verb+resource pair. It further details what is returned (shared dimensions, code overlap, time coverage, join columns), distinguishing it from siblings like get_dataflow_structure or compare_structures by focusing on dimensional relationships and join recommendations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The 'When to use this tool' section explicitly lists three concrete scenarios (after find_code_usage_across_dataflows, combining datasets, checking overlap before queries). It provides clear context for when to use, though it does not explicitly state when not to use it or name alternative tools, which prevents a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

compare_structuresA
Compare two SDMX structures to identify differences.

Supports comparing different structure types with specialized logic:

**Codelists** (`structure_type="codelist"`):
- Compares actual codes (code IDs and names)
- Shows added/removed/renamed codes
- Perfect for: "What codes changed between CL_GEO v1.0 and v2.0?"

**Data Structure Definitions** (`structure_type="datastructure"`):
- Compares codelist/concept scheme references
- Shows version changes in referenced codelists
- Perfect for: "What codelists were updated in DSD v3.0?"

**Dataflows** (`structure_type="dataflow"`):
- Compares structural references (DSD, constraints)
- Perfect for: "What structures do these dataflows share?"

Args:
    structure_type: Type of structure to compare:
        - "codelist": Compare codes within codelists
        - "datastructure" or "dsd": Compare DSD references
        - "dataflow": Compare dataflow references
        - "conceptscheme": Compare concept schemes
    structure_id_a: First structure identifier
    structure_id_b: Second structure identifier (defaults to same as A for version comparison)
    version_a: Version of first structure (default "latest")
    version_b: Version of second structure (default "latest")
    agency_id: Agency ID (uses current endpoint's default if not specified)
    show_diagram: Generate a Mermaid diff diagram (default True)
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.

Returns:
    StructureComparisonResult with type-specific changes:
        - code_changes: For codelist comparisons
        - reference_changes: For DSD/dataflow comparisons
        - summary: Counts of added/removed/modified/unchanged
        - mermaid_diff_diagram: Visual diff diagram
        - interpretation: Human-readable explanation

Examples:
    # Compare two versions of a codelist - see what codes changed
    >>> compare_structures("codelist", "CL_GEO", version_a="1.0", version_b="2.0")

    # Compare two different codelists - find intersection/differences
    >>> compare_structures("codelist", "CL_FREQ", "CL_TIME_FREQ")

    # Compare DSD versions - see what codelist references changed
    >>> compare_structures("datastructure", "DSD_SDG", version_a="2.0", version_b="3.0")

    # Compare two different DSDs
    >>> compare_structures("datastructure", "DSD_SDG", "DSD_EDUCATION")
ParametersJSON Schema
NameRequiredDescriptionDefault
endpointNo
agency_idNo
version_aNolatest
version_bNolatest
show_diagramNo
structure_id_aYes
structure_id_bNo
structure_typeYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoAdditional notes or warnings
summaryYesSummary counts of changes
structure_aYesFirst structure being compared
structure_bYesSecond structure being compared
code_changesNoChanges in codes (for codelist comparisons)
api_calls_madeYesNumber of SDMX API calls made
interpretationYesHuman-readable explanation of the differences
structure_typeNoType of structures being compared: 'codelist', 'conceptscheme', 'datastructure', 'dataflow'
comparison_typeYesType of comparison: 'version_comparison' or 'cross_structure'
concept_changesNoChanges in concepts (for concept scheme comparisons)
discovery_levelNoDiscovery workflow level
dimension_changesNoChanges in dimensions (for DSD comparisons)
reference_changesNoChanges in structural references (codelists, concept schemes referenced)
mermaid_diff_diagramNoMermaid diagram highlighting differences (green=added, red=removed, yellow=changed)

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations present, the description carries the full burden. It explains default behaviors (version_a/b default to 'latest', structure_id_b defaults to same as A for version comparison), how agency_id uses the current endpoint's default, endpoint override semantics, and the return object's type-specific fields. It does not explicitly state that the operation is non-destructive, but 'compare' strongly implies it, and no side effects are hinted.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with bold headers, a clear overview, per-type sections, a structured Args list, a Returns field list, and examples. It is longer than average but every section is necessary given the 8 parameters and multiple comparison modes. The core purpose is front-loaded, and the markdown formatting aids scanning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a complex tool with 8 parameters and multiple structure types, yet the description covers all angles: purpose, type-specific behavior, all parameters with semantics, return fields, and examples. Even though an output schema exists, the description already details the return object structure, making the agent well-prepared to interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides only types and defaults with 0% description coverage. The description's Args section compensates fully: it explains the meaning and allowed values for structure_type, clarifies that structure_id_b defaults to same as A (a key semantic not in the schema), and describes the endpoint override and agency_id defaults. The examples further illustrate parameter combinations for each type.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Compare two SDMX structures to identify differences.' It then provides specialized logic for codelists, DSDs, and dataflows, each with concrete examples like 'What codes changed between CL_GEO v1.0 and v2.0?' This clearly distinguishes it from sibling tools like get_codelist or compare_dataflow_dimensions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit 'Perfect for:' scenarios for each structure type, telling the agent when to invoke the tool for version comparisons, cross-structure comparisons, and reference checks. It does not explicitly name alternative tools or exclusions, but the context is clear and actionable for each mode.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_code_usage_across_dataflowsA
Discover all dataflows that have data for a given code.

Use this as your starting point when exploring what data exists for a
country, indicator, or any other code. For example, to find everything
available for Fiji: find_code_usage_across_dataflows("FJ", dimension_id="GEO_PICT").
Searches all constraints in a single API call.

**When to use this tool:**
- "What datasets have data for Vanuatu?" -> code="VU", dimension_id="GEO_PICT"
- "Which dataflows cover GDP indicators?" -> code="GDP", dimension_id="INDICATOR"
- "What data exists for this country across all topics?" -> start here, then use
  compare_dataflow_dimensions() to check how the discovered dataflows relate.

**Workflow A -- search by dimension (direct):**
    find_code_usage_across_dataflows("FJ", dimension_id="GEO_PICT")
    Returns only matches where "FJ" appears in the GEO_PICT dimension.

**Workflow B -- search by codelist (two steps):**
    If you know a code belongs to a codelist (e.g., CL_COM_GEO_PICT) but
    not which dimensions use it:
    1. Call this tool WITHOUT dimension_id to get all dataflows/dimensions
       where the code appears.
    2. For each matched dataflow, call get_dataflow_structure() to inspect
       the DSD and verify which codelist each matched dimension uses.

**Provider support:** Bulk search requires endpoint support. Currently
supported by SPC (Actual), ECB (Allowed), and UNICEF (Actual). Other
endpoints will return a message explaining the limitation.

Args:
    code: The specific code to check (e.g., "FJ")
    dimension_id: Optional dimension to restrict search (e.g., "GEO_PICT").
        If provided, only matches in this dimension are returned.
        If omitted, all dimensions are searched.
    agency_id: The agency (uses session endpoint if not specified)
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.

Returns:
    CrossDataflowCodeUsageResult with:
        - dataflows_with_data: Dataflows where code is actually used
        - summary: Counts of usage
ParametersJSON Schema
NameRequiredDescriptionDefault
codeYes
endpointNo
agency_idNo
dimension_idNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
codeYesCode checked
summaryYesSummary: dataflows_checked, with_data, without_data
dimension_idNoDimension filter (None = searched all dimensions)
api_calls_madeYesNumber of API calls made
interpretationYesHuman-readable explanation
discovery_levelNoDiscovery level
dataflows_with_dataYesDataflows where code has actual data
total_dataflows_checkedYesDataflows checked for actual usage

TDQS

A4.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Since no annotations are provided, the description carries the behavioral disclosure burden. It discloses that the tool performs a bulk search across all constraints in a single API call, explains the difference in behavior when dimension_id is provided vs. omitted, and explicitly notes the provider support limitation ('SPC (Actual), ECB (Allowed), and UNICEF (Actual)') and that others will return an explanatory message. It could explicitly state that the operation is read-only and non-mutating, but the context strongly implies this, making the transparency solid.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is lengthy but meticulously structured with headings, bullet lists, and code examples. The first line states the core purpose immediately. Every section adds value: usage scenarios, workflows, provider support, parameter explanations, and return value summary. No filler or redundancy. The format makes it easy for an agent to quickly extract the needed guidance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (4 parameters, one required, output schema present) and no annotations, the description is remarkably complete. It covers all parameters, workflows, provider limitations, and return value structure. The output schema covers the return contract, so the description's brief mention of the result type is sufficient. The description leaves no major ambiguity about how to invoke the tool and what to expect.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does thoroughly. Each parameter is explained with meaning and examples: code ('the specific code to check'), dimension_id (with both provided/omitted semantics), agency_id (defaults to session endpoint), and endpoint (targeting a specific provider). The examples for code and dimension_id ('FJ', 'GEO_PICT') make usage concrete. This far exceeds the bare schema information.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear, specific statement: 'Discover all dataflows that have data for a given code.' It names the tool's resource (dataflows) and verb (find/discover), and it distinguishes itself from sibling tools like get_code_usage by positioning this as the 'starting point' for exploring data existence. The workflow examples further clarify that it searches across all constraints in a single call.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The 'When to use this tool' section provides explicit scenarios with concrete examples (e.g., Fiji, GDP) and directly references an alternative: 'then use compare_dataflow_dimensions() to check how the discovered dataflows relate.' Workflow B explains when to omit dimension_id and when to follow up with get_dataflow_structure(). Provider support limitations are also mentioned, giving clear guidance on when this tool will or won't work.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_codelistA
Get codes and values for a specific codelist.

Codelists define the allowed values for dimensions (e.g., country codes, commodity codes).
Use this to find the exact codes needed for your data query.

Args:
    codelist_id: The codelist identifier
    agency_id: The agency (uses session endpoint if not specified)
    version: Version (default: "latest")
    search_term: Optional search term to filter codes
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.

Returns:
    Dictionary with codelist information and codes
ParametersJSON Schema
NameRequiredDescriptionDefault
versionNolatest
endpointNo
agency_idNo
codelist_idYes
search_termNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It explains parameter defaults (agency_id uses session endpoint if not specified, version defaults to 'latest', endpoint defaults to session's current) and the return type (dictionary with codelist information and codes). It does not disclose error behavior or side effects, but for a read-only 'get' operation, this is sufficient.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a compact docstring with a brief summary, a clarifying sentence on codelists, then structured Args and Returns sections. Every sentence serves a purpose, and it is front-loaded with the core action.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema exists, the description need not detail return fields. It covers the tool's purpose, all parameters, defaults, and usage context. It could mention error conditions or prerequisites, but for a simple get operation it is reasonably complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description enumerates all five parameters with meanings beyond the bare schema titles: codelist_id identifier, agency_id session behavior, version default, search_term filter, and endpoint override with examples (FBOS, ECB). This fully compensates for the 0% schema description coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states 'Get codes and values for a specific codelist' with a clear verb and resource, and explains that codelists define allowed values for dimensions. It is unambiguous but does not explicitly differentiate from sibling tools like get_dimension_codes, so it misses a top score.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description says 'Use this to find the exact codes needed for your data query,' providing clear context for when to use the tool. It does not mention when not to use it or name alternatives, so it lacks full usage exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_code_usageA
Efficiently check if specific codes are actually used in a dataflow's data.

This uses the Actual ContentConstraint (if available) to determine which
codes have real data, WITHOUT iterating through data queries. This is
much faster than trial-and-error data requests.

Use cases:
- "Is country code 'FJ' actually used in DF_SDG?"
- "Which indicator codes have data?" (leave codes empty)
- "Are these 5 codes I want to use valid AND have data?"

Args:
    dataflow_id: The dataflow to check
    codes: Optional list of specific codes to check. If empty, returns all used codes.
    dimension_id: Optional dimension to check. If empty, checks all dimensions.
    agency_id: The agency (uses session endpoint if not specified)
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.

Returns:
    CodeUsageResult with:
        - codes_checked: List of codes with their usage status
        - all_used_codes: All codes that have data (by dimension)
        - summary: Counts of used/unused codes

Examples:
    >>> get_code_usage("DF_SDG", codes=["FJ", "WS", "XX"], dimension_id="GEO_PICT")
    # Checks if Fiji, Samoa, and "XX" have SDG data

    >>> get_code_usage("DF_SDG", dimension_id="INDICATOR")
    # Returns all indicator codes that actually have data
ParametersJSON Schema
NameRequiredDescriptionDefault
codesNo
endpointNo
agency_idNo
dataflow_idYes
dimension_idNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
summaryYesSummary counts: total_checked, used, unused
dataflow_idYesDataflow checked
dimension_idNoDimension checked (if specific)
codes_checkedYesUsage status for each code
constraint_idNoActual constraint used
all_used_codesNoAll codes with actual data per dimension (if no specific codes requested)
api_calls_madeNoNumber of API calls made
interpretationYesHuman-readable explanation
discovery_levelNoDiscovery workflow level

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden. It discloses the internal optimization ('uses the Actual ContentConstraint... WITHOUT iterating through data queries'), behavior for empty codes/dimension, and default endpoint behavior. It stops short of discussing error cases or side effects, but being a read-only check, it is well covered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well structured with use cases, args, returns, and examples. It is longer than minimal but each section earns its place. Slightly verbose for a simple tool, but the complexity of parameters justifies the length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the 5-parameter tool with output schema, the description covers all aspects: purpose, method, use cases, parameter meanings, return structure, and examples. It is fully self-contained and leaves no major gaps for an agent to misuse the tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema descriptions are absent (0% coverage), but the Args section explains every parameter with defaults and optionality. For example, 'codes: Optional list... If empty, returns all used codes' and 'endpoint: Defaults to the session's current endpoint.' This fully compensates for the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource+scope: 'check if specific codes are actually used in a dataflow's data.' It clearly distinguishes from siblings like find_code_usage_across_dataflows and get_dimension_codes by focusing on usage within a single dataflow efficiently.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides concrete use cases with example queries and explicitly notes this avoids 'trial-and-error data requests.' It implies when to use the tool but does not name alternative sibling tools or state when not to use it, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_current_endpointA
Get information about the currently active SDMX data source.

Shows which statistical organization's API is being used (e.g., Pacific Data,
European Central Bank, UNICEF).

In multi-user deployments, this returns the endpoint for the current session.

Returns:
    Current endpoint name, URL, agency ID, and description
ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
keyNoEndpoint key (e.g., 'SPC', 'ECB')
nameYesHuman-readable endpoint name
statusNoEndpoint status
base_urlYesAPI base URL
agency_idYesDefault agency identifier
is_currentNoWhether this is the currently active endpoint
descriptionYesWhat data this endpoint provides

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the burden of disclosing behavior. It clearly states what the tool returns (endpoint name, URL, agency ID, description) and adds context about multi-user session scoping. It does not mention error cases or authentication, but for a read-only getter this is a minor gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded. The first sentence states the core purpose, followed by a clarifying example and a succinct return-value list. Every sentence contributes value without repetition or padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (no parameters, output schema provided), the description is fully complete: it explains what the tool does, the session nuance, and the exact return fields. There are no complex edge cases or additional prerequisites that need explanation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the baseline is 4. The description needs no parameter explanation; it focuses entirely on return values and context, which is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Get information about the currently active SDMX data source,' which is a specific verb+resource combination. It further clarifies by naming examples of organizations and explicitly distinguishes itself from tools like list_available_endpoints by focusing on the 'currently active' endpoint.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context about when to use the tool: it reports the active endpoint for the current session, especially in multi-user deployments. However, it does not explicitly mention alternatives or when not to use it, such as when listing all endpoints would be more appropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_data_availabilityA
Get actual data availability for a dataflow or specific dimension combinations.

This tool is critical for avoiding empty query results. Use it to check
if data exists before building the final data URL.

Args:
    dataflow_id: The dataflow to check
    filters: Optional dict of dimension=value pairs to check
    agency_id: The agency ID
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.

Returns:
    Information about what data exists, including time ranges and suggestions
ParametersJSON Schema
NameRequiredDescriptionDefault
filtersNo
endpointNo
agency_idNo
dataflow_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoWhy the answer is empty, when it is
time_rangeNoAvailable time period range
data_existsNoWhether data exists for checked combination
dataflow_idYesDataflow identifier
cube_regionsNoSpecific data regions available
constraint_idNoConstraint identifier if available
has_constraintYesWhether availability constraints exist
interpretationNoHuman-readable interpretation
recommendationNoRecommendation based on availability
constraint_typeNoActual (confirmed data) or Allowed (schema-permitted)
discovery_levelNoDiscovery workflow level
observation_countNoObservation count if the provider exposes it
dimension_values_checkedNoDimension values that were checked

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses the return value ('information about what data exists, including time ranges and suggestions'), explains the endpoint override behavior, and implies a read-only operation through the 'get' verb. Missing details like permissions or side effects, but these are less critical for a read-only check tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately structured with a brief context paragraph, an Args section, and a Returns line. Every sentence serves a purpose, though the Args section could be slightly more compact. Overall, it is well-organized and not bloated.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description provides purpose, usage, parameter semantics, and return information. An output schema exists, so detailed return formatting is not necessary. The mention of avoiding empty query results and targeting a provider adds valuable context. Minor gaps include lack of error handling or example usage, but these are not essential for tool invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has no descriptions (0% coverage), so the description must compensate. It explains all four parameters: dataflow_id (the dataflow to check), filters (optional dimension=value pairs), agency_id (agency ID), and endpoint (optional provider override with default). This adds significant meaning beyond the raw schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb (Get) and resource (data availability) and specifies the scope (dataflow or specific dimension combinations). It distinguishes this tool from siblings like check_time_availability and validate_query by focusing on actual data availability.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit guidance on when to use the tool: 'critical for avoiding empty query results' and 'check if data exists before building the final data URL.' It does not mention alternatives or exclusions, but the usage context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_dataflow_structureA
Get detailed structure information for a specific dataflow.

Returns dimensions, attributes, measures, and codelist references.
Use this after list_dataflows() to understand data organization.

Args:
    dataflow_id: The dataflow identifier
    agency_id: The agency (uses session endpoint if not specified)
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.

Returns:
    Structured result with dataflow metadata and structure definition
ParametersJSON Schema
NameRequiredDescriptionDefault
endpointNo
agency_idNo
dataflow_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataflowYesDataflow metadata
structureYesData structure definition
next_stepsYesSuggested next actions
discovery_levelNoDiscovery workflow level

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must carry the behavioral transparency burden. It implies a read-only operation via 'Get' and explains parameter behaviors (e.g., endpoint defaults to session and can be overridden per call), but it does not explicitly state that it has no side effects, or discuss auth/rate limits. This is acceptable for a simple getter, but could be more explicit.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact, with a clear one-line purpose, a usage sentence, and a truncated Args/Returns block. It is well organized and every line adds value, though it could arguably be tightened further.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has a simple read-only profile and an output schema, so the description does not need to detail return values. It covers purpose, usage, and parameters adequately, but lacks mention of potential errors, timeouts, or performance considerations, which is a minor gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description is the only source of parameter meaning. It provides descriptions for all three parameters, with endpoint getting the most detail (optional key, examples, default behavior), while dataflow_id is only described as 'the dataflow identifier,' which is minimally informative but sufficient given the tool's purpose.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Get detailed structure information for a specific dataflow,' which clearly identifies the action and target. It also enumerates the returned components (dimensions, attributes, measures, codelist references) and positions it relative to list_dataflows(), distinguishing it from sibling tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly states 'Use this after list_dataflows() to understand data organization,' giving a clear sequential usage guideline. It does not, however, provide when-not-to-use or alternative tools for other scenarios, so it lacks full exclusion criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_dimension_codesA
Get codes for a specific dimension of a dataflow.

This allows drilling down into specific dimensions without loading all codelists at once.
Useful for finding valid values for a particular dimension in your data query.

Args:
    dataflow_id: The dataflow identifier
    dimension_id: The dimension identifier
    limit: Maximum codes to return (default: 50)
    offset: Number of codes to skip for pagination (default: 0)
    agency_id: The agency (uses session endpoint if not specified)
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.

Returns:
    Structured result with codes for the dimension
ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
offsetNo
endpointNo
agency_idNo
dataflow_idYes
dimension_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
codesYesList of code values
usageYesHow to use these codes in queries
showingYesNumber of codes in this response
positionYesPosition in the SDMX key
codelist_idNoSource codelist identifier
dataflow_idYesParent dataflow identifier
search_termNoSearch term used for filtering
total_codesYesTotal codes available
dimension_idYesDimension identifier
example_keysYesExample key construction hints
discovery_levelNoDiscovery workflow level

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does a solid job: it explains pagination via limit/offset, the agency_id defaulting to the session endpoint, and endpoint targeting 'for this call only.' The read-only nature is signaled by 'Get,' though it does not explicitly state safety or permissions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a well-structured docstring: a one-line purpose, a brief use-case context, an Args list, and a Returns line. Every sentence contributes information, with no filler or repetition of schema details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema exists, the return summary suffices. The description covers purpose, usage scenario, every parameter with semantics, pagination, endpoint override behavior, and the relationship to full codelists. This is complete for a 6-parameter tool with no annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 0% description coverage, so the description must compensate, and it does thoroughly. It explains all 6 parameters, including defaults (limit=50, offset=0), the meaning of agency_id and endpoint, and pagination semantics, adding substantial meaning beyond the parameter names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening line, 'Get codes for a specific dimension of a dataflow,' clearly states the verb, resource, and scope. It further distinguishes itself from siblings like get_codelist by explaining that it enables drilling down into specific dimensions without loading all codelists at once.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use the tool: 'drilling down into specific dimensions' and 'finding valid values for a particular dimension in your data query.' It implies the alternative of loading full codelists but does not explicitly name a sibling tool or state when not to use this tool, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_metadata_attributeA

Get every value of one reference metadata attribute, with the slice each applies to.

Use after get_reference_metadata() reports drill_down=true for an
attribute, which means more detail remains than the summary shows. This
can happen because the attribute's values differ across the dataflow (for
example recommended-uses text that differs per country), or because a
single value was identical on every row this query returned but drill_down
stays true since other rows queried differently might differ.

Args:
    dataflow_id: The dataflow to read
    attribute_id: An attribute id from get_reference_metadata()
    key: Optional dimension key to narrow the query. Strongly recommended
        for large dataflows: an unfiltered request that is too large to
        return is reported back rather than guessed at, but supplying a
        key (for example a single indicator or reference area) up front
        avoids that round trip.
    agency_id: The agency that owns the dataflow
    endpoint: Optional endpoint key for this call only

Returns:
    Every value of the attribute, each with the dimension key it applies to
ParametersJSON Schema
NameRequiredDescriptionDefault
keyNo
endpointNo
agency_idNo
dataflow_idYes
attribute_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
labelNoHuman-readable label
notesNoRemarks for the caller
totalNoCount of (value, key_context) pairs found
statusYesOne of four outcomes, mirroring the populated/declared_empty vocabulary on MetadataAttribute: 'values' -- the attribute has values, returned in `values`. 'declared_empty' -- the provider declares this attribute for this dataflow and published no value. 'unknown_attribute' -- no such attribute in the declared set; the declared ids are named in `notes`. 'unestablished' -- no channel resolved to a declared set, so nothing can be concluded about whether the attribute exists. This last value must never be rendered as 'no metadata': it is not an observation that the attribute is absent, only that this provider's channels could not confirm one way or the other.
valuesNoValues found
truncatedNoTrue when values holds fewer than total
value_kindNoprose, url, date or unknown
dataflow_idYesDataflow queried
attribute_idYesAttribute queried
distinct_valuesNoCount of distinct value texts among the values found. `total` counts (value, key_context) pairs and answers a different question: three countries publishing the same source organisation give total: 3, distinct_values: 1. Counted over the full uncapped set, not the capped 200, so it stays truthful when `truncated` is true. 0 for the three non-'values' statuses.

TDQS

A4.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description discloses important behavior: unfiltered requests too large to return are 'reported back rather than guessed at,' and supplying a key avoids that round trip. It also explains why drill_down may remain true. However, it does not mention potential errors, rate limits, or auth, though these are less critical for a read-only metadata retrieval.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured: a concise summary sentence, a brief use-case paragraph, a labeled Args list, and a Returns line. Every sentence carries useful information without fluff. The front-loaded purpose is immediately clear.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter tool with no annotations, the description covers all parameters, explains when to use it, describes its return value, and provides practical tips for large dataflows. The presence of an output schema reduces the need to describe return format in more detail. This is sufficiently complete for an agent to invoke correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, but the description provides meaningful documentation for every parameter: 'dataflow_id: The dataflow to read', 'attribute_id: An attribute id from get_reference_metadata()', and especially 'key' with guidance on large dataflows. This goes far beyond the raw schema by explaining relationships and usage context.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Get every value of one reference metadata attribute, with the slice each applies to.' It clearly distinguishes this from the sibling get_reference_metadata() by explaining it is for drilling down when drill_down=true, making the purpose unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use: 'Use after get_reference_metadata() reports drill_down=true.' It also provides practical guidance on the 'key' parameter for large dataflows to avoid round trips, which directly informs when and how to use this tool over alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_reference_metadataA
Get reference metadata for a dataflow: source, methodology, licence, caveats.

Reference metadata is the descriptive material about a dataflow rather
than its structure: who compiled it, from what source, under what licence.
Use it to explain or cite data you have retrieved.

Coverage varies by provider and the result says which channels were
available, so an empty answer can be told apart from an unanswerable one.

Args:
    dataflow_id: The dataflow to describe
    key: Optional dimension key to narrow the query. Strongly recommended
        for large dataflows: SPC's DF_SDG is 5.37 MB unfiltered and 5.6 KB
        with a partial key.
    agency_id: The agency (uses the session endpoint if not specified)
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.
    ctx: MCP context

Returns:
    Reference metadata attributes, their provenance, and channel status
ParametersJSON Schema
NameRequiredDescriptionDefault
keyNo
endpointNo
agency_idNo
dataflow_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesNoPlain-language remarks for the caller
versionNoResolved version
channelsNoState of each channel: found, empty, inconclusive, too_broad, unsupported or skipped
coverageNoDeclared / populated / empty counts from the MSD channel, the only channel that can see a declared-but-empty attribute; null when the MSD channel did not answer found on an untruncated read
endpointNoEndpoint key
agency_idYesOwning agency
dataflow_idYesDataflow queried
metadata_attributesNoReference metadata found

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the transparency burden. It discloses that coverage varies by provider, that channel status is reported, and that empty vs unanswerable results are distinguishable. It also includes a performance warning for large dataflows. However, it doesn't explicitly state read-only behavior or error handling, though 'get' implies a safe operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with an intro, usage note, args list, and returns summary. It is slightly longer than necessary due to the detailed performance example, but every sentence contributes valuable information, so it remains appropriately sized.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given an output schema exists, the description needn't detail return format, but it still summarizes output (attributes, provenance, channel status) and covers edge cases like provider coverage and empty vs unanswerable results. It omits explicit error scenarios but is otherwise complete for this metadata retrieval tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description fully compensates by explaining each parameter in prose: dataflow_id, key (with performance example), agency_id, and endpoint (with provider examples). This adds substantial meaning beyond the bare schema definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb-resource pair ('Get reference metadata for a dataflow') and lists concrete content types (source, methodology, licence, caveats). It explicitly contrasts with structural metadata ('rather than its structure'), distinguishing it from sibling tools like get_dataflow_structure.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit usage context 'Use it to explain or cite data you have retrieved' and a clear when-not distinction ('rather than its structure'). This guides the agent toward appropriate invocation contexts without ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_structure_diagramA
Generate an SDMX-aware Mermaid diagram for any structural artifact.

The visualization adapts based on the artifact type to show the most
relevant information following the SDMX information model:

**Dataflow**: Shows full SDMX hierarchy (entry point view)
    - Dataflow → DSD → Components (Dimensions, Attributes, Measure)
    - Components → Concepts (semantic meaning from ConceptSchemes)
    - Components → Representations (Codelists or free text)

**DSD/DataStructure**: Shows component structure + relationships
    - Parent dataflows that use this DSD
    - Child codelists and concept schemes referenced

**Codelist**: Shows impact/usage view (building block)
    - Parent DSDs/dimensions that reference this codelist
    - Useful for impact analysis (what breaks if I change this?)

**ConceptScheme**: Shows usage across structures
    - Parent DSDs/components that use these concepts

Args:
    structure_type: Type of structure - one of:
        - "dataflow": Statistical data publication (shows full hierarchy)
        - "datastructure" or "dsd": Data Structure Definition
        - "codelist": Code list (enumeration of valid values)
        - "conceptscheme": Concept scheme (definitions)
        - "categoryscheme": Category scheme (classification)
    structure_id: The structure identifier
    agency_id: Agency ID (uses current endpoint's default if not specified)
    version: Version string (default "latest") - query a specific version
    direction: Relationship direction to explore (ignored for dataflow):
        - "parents": Show structures that USE this one
        - "children": Show structures this one REFERENCES
        - "both": Show both directions (default)
    show_versions: If True, display version numbers on each node
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.

Returns:
    StructureDiagramResult with:
        - mermaid_diagram: Ready-to-render Mermaid code
        - nodes: All structures in the relationship graph
        - edges: Relationships between structures
        - interpretation: Human-readable explanation

Examples:
    >>> get_structure_diagram("dataflow", "DF_SDG")
    # Shows complete SDG dataflow structure with SDMX hierarchy

    >>> get_structure_diagram("codelist", "CL_FREQ", show_versions=True)
    # Shows what structures use CL_FREQ (impact analysis)

    >>> get_structure_diagram("dsd", "DSD_POP", direction="children")
    # Shows codelists and concept schemes used by DSD_POP
ParametersJSON Schema
NameRequiredDescriptionDefault
versionNolatest
endpointNo
agency_idNo
directionNoboth
structure_idYes
show_versionsNo
structure_typeYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoAdditional notes or warnings
depthYesTraversal depth used
edgesYesAll edges (relationships) in the graph
nodesYesAll nodes in the relationship graph
targetYesThe queried target structure
directionYesDirection queried: 'parents', 'children', or 'both'
api_calls_madeYesNumber of SDMX API calls made
interpretationYesHuman-readable explanation of the relationships
discovery_levelNoDiscovery workflow level
mermaid_diagramYesReady-to-render Mermaid diagram code showing structure relationships

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full behavioral burden. It transparently explains how output adapts per artifact type, the meaning of direction, the default version/agency/endpoint behavior, and what the result contains. It does not mention side effects or error conditions, but the read-only nature is implied by 'Generate' and 'Returns'.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-structured with a clear summary, type-specific bullets, Args, Returns, and Examples. Each section adds necessary detail without redundancy, and the main purpose is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 7 parameters and type-dependent behavior, the description is exceptionally complete. It covers all parameter semantics, behavioral variations, output structure, and includes three diverse examples. The presence of an output schema further reduces the need to document return fields, yet the description still does.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It provides a dedicated Args section explaining every parameter, including allowed values for structure_type, defaults for version/agency_id/direction/show_versions/endpoint, and the meaning of direction. Examples further clarify parameter usage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Generate an SDMX-aware Mermaid diagram for any structural artifact.' It further distinguishes itself from sibling tools by detailing type-specific visualization views (dataflow, DSD, codelist, concept scheme), making its unique role clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage context, such as 'impact analysis' for codelists and 'shows complete SDG dataflow structure' in examples. However, it does not explicitly name alternative tools or state when not to use this tool, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_available_endpointsA
List all available SDMX data sources that can be switched to.

Shows all configured statistical data providers (e.g., SPC, ECB, UNICEF)
and indicates which one is currently active for your session.

You don't need to switch endpoints to compare data across providers.
Use compare_dataflow_dimensions(df_a, df_b, endpoint_a="SPC", endpoint_b="ECB")
to directly compare dataflows from different providers.

In multi-user deployments, the current endpoint is session-specific.

Returns:
    List of available endpoints with their descriptions and status
ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteYesUsage hint
currentYesCurrently active endpoint key
endpointsYesList of available endpoints

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Without annotations, the description carries the burden of behavioral disclosure. It explains that the tool returns a list with descriptions and status, indicates the active endpoint, and notes that the endpoint is session-specific in multi-user deployments. However, it does not explicitly state read-only behavior, auth requirements, or any side effects, though these are reasonably implied for a listing operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and concise: it states the purpose in the first line, adds relevant usage guidance in the middle, and ends with a clear summary of returns. Every sentence provides useful information, and the overall length is appropriate for the tool's simplicity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is simple (no params), and the description covers purpose, usage, return structure, and session-specific behavior. An output schema exists, but the description's return summary suffices given the simplicity. Sibling tool comparisons are addressed via the alternative usage advice, making the description complete for an agent to select and invoke correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, and the input schema is an empty object, so schema coverage is trivially 100%. With 0 params, the baseline is 4. The description adds no parameter details because none exist, but it does describe the return payload conceptually, which is not required for this dimension.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: 'List all available SDMX data sources that can be switched to.' It specifies the resource (SDMX data sources) and the action (list), and further clarifies that it shows all configured statistical data providers and indicates the currently active one. This distinguishes it from sibling tools like get_current_endpoint, which likely returns only the current endpoint.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly provides usage context: it explains when this tool is useful (to see available endpoints/current active) and provides an explicit alternative for a different task: 'Use compare_dataflow_dimensions(...) to directly compare dataflows from different providers.' It also notes session-specific behavior in multi-user deployments, which guides when to rely on the result.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_dataflowsA
List available SDMX dataflows, optionally filtered by keywords.

This is typically the first step in SDMX data discovery. Returns a list of
statistical domains (dataflows) available from the specified agency.

If you already know a country code or indicator code, consider using
find_code_usage_across_dataflows() instead — it directly discovers all
dataflows with data for that code, across all topics.

Args:
    keywords: Optional keyword string or list of keywords to filter dataflows
    agency_id: The agency to query (uses session endpoint if not specified)
    limit: Number of results to return (default: 10)
    offset: Number of results to skip for pagination (default: 0)
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.
    fresh: Bypass the module-level dataflow listing cache and force a
        live re-fetch from the provider. The fetch still refreshes the
        cache for other callers. Defaults to False; use True only when
        the point of the call is to prove the provider is reachable
        right now (a cached answer would say nothing about that).

Returns:
    Structured result with dataflows, pagination info, and navigation hints
ParametersJSON Schema
NameRequiredDescriptionDefault
freshNo
limitNo
offsetNo
endpointNo
keywordsNo
agency_idNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
limitYesMaximum results per page
offsetYesCurrent offset for pagination
showingYesNumber of dataflows in this response
keywordsNoKeywords used for filtering
agency_idYesAgency identifier queried
dataflowsYesList of dataflow summaries
next_stepYesSuggested next action in the discovery workflow
paginationYesPagination information
filter_infoNoFilter statistics if keywords were used
total_foundYesTotal dataflows found (after filtering)
discovery_levelNoDiscovery workflow level

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses caching behavior (the `fresh` param bypasses cache but refreshes it for others), explains endpoint fallback to session default, and mentions pagination. It could also note any permissions or rate-limit implications, but for a list operation this is largely sufficient. It adds meaningful context beyond what bare annotations would have provided.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is multi-paragraph but each paragraph earns its place: an overview paragraph, an alternative guidance paragraph, a full Args list, and a Returns summary. It is verbose but not wasteful; a 5 would require tighter phrasing, though the current structure is well-organized and scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the existence of an output schema, the description needn't detail return values, and it doesn't over-explain. It covers what the tool does, when to use it, alternatives, all parameters, caching semantics, and pagination. There is no obvious missing context that an agent would need to select and invoke this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description's Args section is the only parameter documentation. It thoroughly explains each parameter: keywords as string or list, agency_id defaulting to session, limit/offset for pagination, endpoint for per-call provider override, and fresh with a clear rationale for when to use it. This fully compensates for the absent schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'List available SDMX dataflows' with a specific verb and resource, and positions it as 'typically the first step in SDMX data discovery.' It also distinguishes itself from siblings by naming an alternative (find_code_usage_across_dataflows) for when codes are already known, making the scope unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says this is the first step in SDMX data discovery and provides a concrete 'instead' recommendation: 'If you already know a country code or indicator code, consider using find_code_usage_across_dataflows() instead.' This clarifies when to use this tool versus a sibling, which is exactly what usage guidelines should do.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

probe_data_urlA
Probe an exact SDMX data query and return whether it contains data.

This answers the question that validation and code-usage checks cannot:
does this exact query return observations right now?

Accepts either a complete data URL or structured parameters.
Uses lightweight probing (firstNObservations=1) to minimise payload.

Args:
    data_url: Complete SDMX data URL to probe
    dataflow_id: Dataflow ID (alternative to data_url)
    filters: Dimension filters (alternative to data_url)
    start_period: Start time period
    end_period: End time period
    agency_id: Owning agency when different from the session default.
        Required for OECD sub-agency flows (e.g. pass "OECD.STI.STP"
        alongside dataflow_id="DSD_RDS_GERD@DF_GERD_SOF"). Only consulted
        when data_url is not provided; ignored when data_url is.
    sample_observations_limit: Max sample observations to return
    max_distinct_values_per_dimension: Max distinct values per dimension summary
    timeout_ms: Probe timeout in milliseconds
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.

Returns:
    Probe result with status, observation count, shape, and sample data
ParametersJSON Schema
NameRequiredDescriptionDefault
filtersNo
data_urlNo
endpointNo
agency_idNo
end_periodNo
timeout_msNo
dataflow_idNo
start_periodNo
sample_observations_limitNo
max_distinct_values_per_dimensionNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesNoDiagnostic notes
statusYesProbe outcome: 'nonempty' if observations were returned, 'empty' if the query resolved to zero observations, 'error' if the probe failed (HTTP error, parse failure, etc.)
dimensionsNoSummary of observed dimension values
series_countNoNumber of distinct series
geo_dimension_idNoGeography dimension ID if detected
observation_countNoNumber of actual observations returned
query_fingerprintNoSHA-256 fingerprint of the normalised query
time_period_countNoNumber of distinct time period values
has_time_dimensionNoWhether a time dimension was detected
sample_observationsNoBounded sample of observations

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description fully carries the transparency burden. It discloses key behaviors: uses 'lightweight probing (firstNObservations=1)' to minimize payload, returns 'status, observation count, shape, and sample data', and clarifies that agency_id is 'Required for OECD sub-agency flows' and 'ignored when data_url is'. This gives the agent concrete expectations about side effects and output.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a clear intro, use-case statement, parameter list, and return description. It is somewhat verbose due to the detailed parameter explanations, but every sentence adds necessary context. It could be slightly tightened, but overall it earns its length given the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the 10-parameter complexity and the presence of an output schema, the description is complete. It explains input alternatives, output structure, timeout defaults, endpoint selection, and special cases like sub-agency flows. The agent has all context needed to invoke the tool correctly without needing to infer from structured data.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It does so admirably, explaining all 10 parameters with relationships, examples, and edge cases. For instance, it notes data_url and dataflow_id are alternatives, clarifies agency_id usage conditions, and provides endpoint examples. This adds significant meaning beyond the raw schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool 'Probe an exact SDMX data query and return whether it contains data', using a specific verb and resource. It explicitly distinguishes from sibling tools by explaining it answers the question validation and code-usage checks cannot, making its unique purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context on when to use the tool: 'This answers the question that validation and code-usage checks cannot'. It also explains the flexible input modes (data_url or structured parameters). However, it does not explicitly name alternative sibling tools or state when not to use it, though the comparison to validation/code-usage checks implies it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

suggest_nonempty_queriesA
Suggest nearby non-empty SDMX queries when the original returns no data.

Given an exact query that may be empty, explores bounded relaxations —
removing one filter at a time — and returns validated alternatives ranked
by minimal deviation from the original.

Args:
    data_url: The exact SDMX data URL to recover from
    relax_dimensions: Only relax these dimensions (None = try all)
    max_suggestions: Maximum number of suggestions to return
    max_probes: Maximum HTTP probes to make (budget)
    strategy: Recovery strategy (currently only least_change)
    intent_hint: One of generic, kpi, timeseries, ranking, map
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.

Returns:
    Suggestion result with ranked non-empty alternatives
ParametersJSON Schema
NameRequiredDescriptionDefault
data_urlYes
endpointNo
strategyNoleast_change
max_probesNo
intent_hintNogeneric
max_suggestionsNo
relax_dimensionsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesNoDiagnostic notes
probes_usedNoNumber of probes consumed
suggestionsNoRanked non-empty alternatives
original_statusYesProbe status of the original query
original_query_fingerprintNoFingerprint of original

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. It discloses HTTP probing behavior with a budget (max_probes), the relaxation strategy, and that alternatives are validated. Also explains the endpoint parameter overrides session endpoint for this call only. Lacks details on errors or side effects, but core behaviors are covered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Overview is two focused sentences, followed by a clean Args list. No fluff—every line adds functional value, and the structure is easy to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity and presence of an output schema, the description adequately covers input semantics, algorithm, and probing budget. It omits edge cases like invalid URLs or no-alternatives-found behavior, but for an agent deciding to invoke the tool, it provides enough context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, but the Args block explains all 7 parameters with meaningful semantics: 'None = try all' for relax_dimensions, 'budget' for max_probes, 'currently only least_change' for strategy, and listed values for intent_hint. Doesn't fully explain intent_hint's effect, but covers the essentials.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description opens with 'Suggest nearby non-empty SDMX queries when the original returns no data,' providing a specific verb and resource. It clearly differentiates from sibling tools like probe_data_url or get_data_availability by focusing on recovery suggestions for empty results.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

States a clear trigger condition ('when the original returns no data') and describes the approach (bounded relaxations, removing one filter at a time). This gives contextual use case, but doesn't explicitly mention when not to use it or name alternative tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

validate_queryA
Validate SDMX query parameters before building the final URL.

Checks syntax according to SDMX 2.1 REST API specification.
Validates that dimension codes actually exist in the dataflow.

Args:
    dataflow_id: The dataflow to validate against
    key: The data key (dimensions separated by dots)
    filters: Dictionary of dimension_id -> code (alternative to key)
    start_period: Start of time range
    end_period: End of time range
    agency_id: The agency
    endpoint: Optional endpoint key (e.g. "FBOS", "ECB") to target a
        specific provider for this call only. Defaults to the session's
        current endpoint.

Returns:
    Validation results including any errors, warnings, and validated parameters
ParametersJSON Schema
NameRequiredDescriptionDefault
keyNo
filtersNo
endpointNo
agency_idNo
end_periodNo
dataflow_idYes
start_periodNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
keyYesKey that was validated
validYesWhether the query is valid
errorsNoValidation errors
warningsNoValidation warnings
suggestionNoSuggestion for fixing issues
dataflow_idYesDataflow being validated against
invalid_codesNoInvalid dimension codes if code validation was performed

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden. It states the two validation checks and the return value (errors, warnings, validated parameters), which is useful. However, it does not disclose whether the tool makes network calls to fetch dataflow structure or what side effects occur, a notable gap given it validates against a dataflow.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded with the primary purpose. The Args/Returns structure organizes information efficiently, and every sentence adds value without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers purpose, all parameters, and summarizes the return type, which suffices given the output schema exists. The main missing element is side-effect disclosure (e.g., network access), preventing a perfect score.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Despite 0% schema description coverage, the Args section explains all seven parameters, including nuanced details like `key` being dot-separated dimensions, `filters` being a dimension-to-code dictionary, and `endpoint` targeting a provider with a default. Some entries are terse (e.g., 'agency_id: The agency') but overall the description compensates well.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the tool as a validator of SDMX query parameters, specifying that it checks syntax per the SDMX 2.1 spec and verifies dimension code existence. This distinguishes it from sibling tools like build_data_url or probe_data_url, positioning it as a pre-build validation step.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'before building the final URL' provides clear contextual timing, implying use prior to URL construction. However, it does not explicitly mention when not to use it or compare it to alternatives like probe_data_url, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

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

  1. 20 tool updatesv0.2.0
    • First observedbuild_data_url
    • First observedbuild_key
    • First observedcheck_time_availability
    • First observedcompare_dataflow_dimensions
    • First observedcompare_structures
    • First observedfind_code_usage_across_dataflows
    • First observedget_code_usage
    • First observedget_codelist
    • First observedget_current_endpoint
    • First observedget_data_availability
    • First observedget_dataflow_structure
    • First observedget_dimension_codes
    • First observedget_metadata_attribute
    • First observedget_reference_metadata
    • First observedget_structure_diagram
    • First observedlist_available_endpoints
    • First observedlist_dataflows
    • First observedprobe_data_url
    • First observedsuggest_nonempty_queries
    • First observedvalidate_query

TDQS

A4.4/5.0

Scored across 20 tools

Disambiguation4/5

Most tools have clearly distinct purposes, but several availability-check tools (get_data_availability, get_code_usage, check_time_availability, probe_data_url) overlap in function and could lead to misselection without careful description reading. The descriptions themselves disambiguate well, so the issue is mild.

Naming Consistency5/5

All tool names follow a consistent snake_case verb_noun pattern (get_, list_, check_, find_, compare_, validate_, build_, probe_, suggest_). No mixed conventions or vague verbs like 'process' or 'do_thing'.

Tool Count4/5

20 tools is slightly heavy but justified for a comprehensive SDMX gateway covering discovery, structure, availability, query construction, metadata, visualization, and endpoint management. Each tool serves a defined role, though some could arguably be merged.

Completeness5/5

The tool surface covers the full SDMX data workflow: discovery (list_dataflows, find_code_usage_across_dataflows), structure inspection, availability checks, query building/validation, URL generation, probing, recovery from empty results, reference metadata, and endpoint management. No obvious dead ends or missing core operations for its stated purpose.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    A model Context Protocol (MCP) server that provides comprehensive OECD statistics through the SDMX API, supporting AI assistants and chatbots to query OECD datasets in areas such as economy, health, education, and environment.
    9
    2
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    An MCP server that lets AI assistants discover and retrieve official statistics from SDMX services, returning actual data observations rather than just query URLs.
    Apache 2.0