ilostat-mcp-server
Server Details
Search ILOSTAT labour indicators, query and compare series, build country profiles, run SQL.
- Status
- Healthy
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
- Repository
- cyanheads/ilostat-mcp-server
- GitHub Stars
- 1
- Server Listing
- ilostat-mcp-server
TDQS
Scored across 8 tools
Tools target distinct stages: catalog search, dataset metadata, vocabulary lookup, data retrieval, geographic comparison, country profile, and dataframe SQL. Minor overlap exists between query_indicator and compare_geographies (both return values for areas), and get_country_profile could be mimicked by multiple query calls, but descriptions clearly delineate their specialized purposes.
All tools share the ilostat_ prefix and snake_case, making names readable and predictable. Most follow verb_noun (describe_indicator, query_indicator, list_reference), while dataframe_describe and dataframe_query use noun_verb, a minor deviation within a resource subgroup.
Eight tools are well-scoped for a read-only statistical API: discovery, metadata, retrieval, comparison, profiling, and SQL post-processing. No tool appears redundant or extraneous.
The surface covers the full read-only lifecycle: search and describe indicators, decode reference vocabularies, fetch filtered observations, compare geographies, build country profiles, and run SQL on staged dataframes. No major gaps are apparent for ILOSTAT data access and analysis.
Available Tools
8 toolsilostat_compare_geographiesCompare areas on an ILOSTAT datasetARead-onlyIdempotentInspect
Compare reference areas on one ILOSTAT dataset and one slice — a sex code plus breakdown codes, defaulting to the dataset's totals — giving each area's value at a common period or at its latest non-projected period, optional change over N years, and a rank, with each value's period, source, status, and basis (reported, modelled_estimate, or projection). Areas without a value are listed separately with the reason, and the response flags mixed periods and mixed bases rather than hiding them. Select areas by code list, by group (X01 for every country, an ILO region or subregion, or a World Bank income group), or both; X-coded aggregates require a dataset with aggregates.
| Name | Required | Description | Default |
|---|---|---|---|
| sex | No | Sex code SEX_T, SEX_M, SEX_F, or SEX_O; T/M/F/O and total/both/male/female/other are accepted. Defaults to SEX_T on a dataset with a sex breakdown; refused on one without. | |
| sort | No | Row order: value_desc (default), value_asc, or ref_area. rank is always by value, highest first. | value_desc |
| period | No | A common period, YYYY, YYYYQn, or YYYYMmm matching the dataset frequency (2024-Q2 and 2025-03 are normalized). Omit to compare each area at its latest period. | |
| classif1 | No | First breakdown code, case-insensitive. Defaults to the dataset's total code; required when the breakdown has no total (deciles); refused on a dataset without the breakdown. ilostat_describe_indicator lists the dataset's codes and marks its totals. | |
| classif2 | No | Second breakdown code; same defaults and rules as classif1. | |
| ref_areas | No | Reference areas (up to 300): ISO3 codes (USA) or X-coded aggregates (X01 World); case-insensitive, ILO_GEO_ forms accepted. At least one of ref_areas or area_group is required. | |
| area_group | No | X01 for every country, an ILO region or subregion, or a World Bank income group (X06, X56, X02, …); expands to its member countries. The group's own aggregate is compared only when listed in ref_areas. ilostat_list_reference topic area_groups lists the codes. | |
| dataset_id | Yes | One dataset ID (UNE_DEAP_SEX_AGE_RT_A), as ilostat_search_indicators returns it; case-insensitive, a DF_ prefix (the SDMX dataflow form) stripped, a bare indicator code resolved when it has one frequency. | |
| change_years | No | Adds each value's change from the same sub-period this many years earlier, in the dataset unit. | |
| lookback_years | No | Latest mode: an area's latest value must fall within this many years of the current year. | |
| include_projections | No | Latest mode: let projections (ILO modelled values after the cutoff) be an area's latest value. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cap | No | Inline preview budget, in serialized characters. |
| mode | No | latest: each area's latest value; period: every area at one period. |
| rows | No | Areas with a value, in the requested order; the staged dataframe holds all when larger. |
| error | No | Present when the call failed. Absent on success. |
| shown | No | Rows returned inline. |
| slice | No | The one series compared per area. |
| legend | No | Labels for the status flags and note codes in rows. |
| notice | No | Mixed periods, mixed bases, missing areas, a unit or area list the structure service could not supply, where the full comparison is staged, or why the inline rows stop early. |
| period | No | Period mode: the period compared. |
| dataset | No | One requested dataset and how its values are classed. |
| missing | No | Requested areas with no value, and why. |
| dataframe | No | The staged dataframe holding the full result; present only when staged. |
| truncated | No | True when the inline rows stop before the last area — also when a dataframe holds the full comparison. |
| attribution | No | Citation to keep with any use of the data. |
| window_from | No | Latest mode: the first year requested — lookback_years before the current year, and change_years further back to reach the change base. A latest value still falls within lookback_years. |
| change_years | No | Years the change is measured over, when requested. |
| comparability | No | What makes the values more or less comparable, over every area. |
| applied_filters | No | Every parameter sent upstream. |
| include_projections | No | Whether a projection could be an area's latest value. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only, idempotent, open-world behavior, yet the description goes well beyond them: areas lacking values are listed separately with a reason, mixed periods and mixed bases are flagged rather than hidden, and each value carries period, source, status, and basis (reported/modelled_estimate/projection). That is exactly the kind of output-shape and edge-case disclosure annotations cannot provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Content is front-loaded and every clause carries information, but the opening sentence is a long run-on enumerating period, change, rank, and basis in one breath. Given the tool's 11-parameter complexity the length is defensible, though it could be split for scanability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 11-parameter, single-required-param tool with an output schema, the description covers selection modes, defaults, aggregate restrictions, null handling, and mixed-period/base flagging. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all 11 parameters in detail (defaults, enums, patterns, limits). The description adds framing about the slice concept (sex plus breakdown codes defaulting to totals) but little parameter syntax beyond what the schema carries, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb (compare) and resource (reference areas on one ILOSTAT dataset and one slice), and spells out the scope: values at a common or latest non-projected period, optional change over N years, and a rank. An agent can distinguish this from ilostat_query_indicator (single indicator extraction) or ilostat_get_country_profile without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly establishes the operating context: select areas by code list, by group, or both, and X-coded aggregates require a dataset with aggregates. That is strong contextual guidance, but it never explicitly names a sibling tool as the alternative or states when NOT to use this in favor of ilostat_query_indicator or ilostat_list_reference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ilostat_dataframe_describeDescribe staged ILOSTAT dataframesARead-onlyIdempotentInspect
Describe the df_ dataframes staged by ilostat_query_indicator and ilostat_compare_geographies or stored by ilostat_dataframe_query register_as: the tool and parameters that produced each, the datasets it holds (label, unit, last update), coverage, basis counts, attribution, creation and expiry times, row count, and column schema. Pass name for one dataframe. Without it, every staged dataframe is listed, except on a deployment whose callers share one canvas, where listing is off and only the exact name works. Read the schema here before writing SQL for ilostat_dataframe_query.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | One dataframe name as the producing tool returned it (df_XXXXX_XXXXX: letters and digits, five in each part; case-insensitive, as in SQL). Omit to list every staged dataframe; a deployment whose callers share one canvas refuses the listing and needs the name. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| notice | No | Guidance when the named dataframe does not exist. |
| dataframes | No | Staged dataframes, newest first; empty when none. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and idempotentHint, so safety is covered; the description goes further by disclosing what the payload contains (attribution, creation and expiry times, coverage, basis counts) and a deployment-dependent quirk: on a shared-canvas deployment, omission-based listing is off and only an exact name works. That is real behavioral context annotations could not convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The usage constraint (read the schema before writing SQL) is front-loaded in the final sentence and the operational rule about name versus listing is clear. The first sentence is a long enumerated field list that is dense but largely informative rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-optional-parameter read tool with annotations and an output schema, the description is complete: it covers scope, argument behavior, deployment caveat, and the handoff to ilostat_dataframe_query. It spends words enumerating return fields that the output schema already defines, which is redundant rather than missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for the single name parameter, so the pattern, case-insensitivity, and omission semantics are already documented in the schema. The description restates them ('Pass name for one dataframe. Without it, every staged dataframe is listed') without adding format or syntax beyond the schema, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Describe) and a precisely scoped resource (df_<id> dataframes staged by ilostat_query_indicator / ilostat_compare_geographies or registered via ilostat_dataframe_query), and enumerates what is returned. It names the producing siblings explicitly, so an agent can distinguish it from ilostat_dataframe_query or ilostat_describe_indicator without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use routing: 'Read the schema here before writing SQL for ilostat_dataframe_query.' It also states the condition that selects the name argument (one dataframe) versus omitting it (list everything), and flags the shared-canvas exception where listing is refused.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ilostat_dataframe_queryQuery staged ILOSTAT dataframesARead-onlyIdempotentInspect
Run a single-statement SELECT against the df_ dataframes staged by ilostat_query_indicator and ilostat_compare_geographies or stored by an earlier register_as. Inspect a dataframe with ilostat_dataframe_describe first; its column schema is what the SQL has to match. Read-only: writes, DDL, DROP, COPY, PRAGMA, ATTACH, and file-reading table functions are rejected, and system catalogs (information_schema, pg_catalog, sqlite_master, duckdb_*) are denied. Breakdown versions overlap (AGE_YTHADULT_*, AGE_AGGREGATE_*, AGE_10YRBANDS_*), so filter to one version before summing. Optional register_as stores the result as a new dataframe with a fresh TTL.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | One SELECT over df_<id> tables (DuckDB SQL: joins, aggregates, window functions, CTEs), at most 20,000 characters. BIGINT results such as COUNT or SUM of integers serialize as strings; CAST to DOUBLE for inline arithmetic. | |
| preview | No | Rows returned inline; defaults to row_limit. Set lower when register_as keeps the full result. | |
| row_limit | No | Hard cap on rows materialized (1–10,000). A query matching more stops at the cap and row_count_capped is true; register_as keeps the full result. | |
| register_as | No | Store the result as a new dataframe under this name (df_XXXXX_XXXXX: letters and digits, five in each part; stored uppercased after df_) with a fresh TTL, to chain analyses. A result over 1,000,000 rows is refused, and storing one can evict the oldest dataframes, which evicted names. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cap | No | The row cap that bound: preview when lower than row_limit, else row_limit. |
| rows | No | Result rows keyed by the names in columns, bounded by preview and row_limit; BIGINT values arrive as strings. |
| error | No | Present when the call failed. Absent on success. |
| shown | No | Rows returned inline. |
| notice | No | Guidance when the query returned no rows or a cap withheld some. |
| columns | No | Column names in projection order. |
| evicted | No | Dataframes dropped, oldest first, to keep this tenant within 1,000,000 staged rows and 100 dataframes; present only when storing the result evicted any. |
| row_count | No | Rows the query produced. With register_as this is the exact count of the stored dataframe, which row_limit does not bound; otherwise at most row_limit, and when row_count_capped is true it is the cap, not a total. |
| truncated | No | True when a cap withheld rows from this response. |
| expires_at | No | ISO 8601 expiry of the new dataframe. |
| registered_as | No | The new dataframe name, when register_as stored the result. |
| row_count_capped | No | True when the query matched more rows than row_limit; never true with register_as, which stores every row. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint/openWorldHint/idempotentHint, but the description adds real operational detail beyond them: the exact rejected statement classes (writes, DDL, DROP, COPY, PRAGMA, ATTACH, file-reading table functions), the denied system catalogs, the overlapping breakdown-version trap (AGE_YTHADULT_*/AGE_AGGREGATE_*/AGE_10YRBANDS_*), and that register_as creates a fresh TTL. This is exactly the behavioral context an agent needs to write a valid query.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Information is front-loaded: purpose first, then prerequisite, then the rejection list, then the semantic pitfall, then the optional output mode. Every sentence carries distinct operational value with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not explain return values, and it covers what it must: prerequisites, allowed statement surface, and the analysis trap that would silently corrupt sums. Nothing needed to invoke the tool correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so each of the four parameters (sql, preview, row_limit, register_as) is already documented in detail, including the BIGINT-as-string caveat and the 1,000,000-row register limit. The description's mention of register_as storing with a fresh TTL largely repeats the schema, so it adds little beyond the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
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: 'Run a single-statement SELECT against the df_<id> dataframes.' It goes further by naming which sibling tools produce those dataframes (ilostat_query_indicator, ilostat_compare_geographies, register_as) and which sibling inspects them (ilostat_dataframe_describe), so the agent can separate this from ilostat_query_indicator without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly states the precondition — data must already be staged by ilostat_query_indicator or ilostat_compare_geographies — and directs the agent to run ilostat_dataframe_describe first because 'its column schema is what the SQL has to match.' That is strong contextual routing, though it never explicitly says when to prefer querying an indicator directly via ilostat_query_indicator instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ilostat_describe_indicatorDescribe an ILOSTAT datasetARead-onlyIdempotentInspect
Explain one ILOSTAT dataset before comparing numbers: its definition, unit and multiplier, frequency variants and coverage, the sex and breakdown codes in use across its frequencies (the total code of each breakdown marked), the reference areas it covers, whether it carries World/regional/income-group aggregates, and how its observations are classed as reported, modelled, or projected. Accepts a dataset ID (UNE_DEAP_SEX_AGE_RT_A) or a bare indicator code (UNE_DEAP_SEX_AGE_RT), which describes every frequency. An unknown code returns found: false with guidance.
| Name | Required | Description | Default |
|---|---|---|---|
| dataset_id | Yes | One dataset ID (indicator code plus _A, _Q, or _M, e.g. UNE_DEAP_SEX_AGE_RT_A) or a bare indicator code (UNE_DEAP_SEX_AGE_RT), as ilostat_search_indicators returns them. Case-insensitive; a DF_ prefix (the SDMX dataflow form) is stripped. |
Output Schema
| Name | Required | Description |
|---|---|---|
| unit | No | Unit of the values, already in the multiplier scale; absent when unresolved. |
| error | No | Present when the call failed. Absent on success. |
| found | No | False when no dataset or indicator has the code. |
| label | No | Indicator label as ILOSTAT publishes it. |
| notice | No | Where to find breakdown codes and units when the structure service did not supply them. |
| measure | No | Measure (the quantity measured, shared by breakdown variants) code and label. |
| subject | No | Subject code and label. |
| database | No | Source database code and label. |
| datasets | No | Every frequency variant of the indicator, annual first. |
| guidance | No | On a miss: how to find a valid dataset ID. |
| indicator | No | Indicator code. |
| ref_areas | No | Reference areas the indicator covers across its frequencies, from ILOSTAT's structure service; absent when structure_status is unavailable. |
| basis_rule | No | How observations are classed reported, modelled_estimate, or projection. |
| breakdowns | No | Breakdown codes in use, from ILOSTAT's structure service; absent when structure_status is unavailable. |
| dataset_id | No | The dataset requested, when a dataset ID (not a bare indicator code) was given. |
| definition | No | ILOSTAT definition of the indicator, HTML stripped; links kept as "text (url)". |
| attribution | No | Citation to keep with any use of the data. |
| catalog_as_of | No | ISO timestamp the catalog was last confirmed current. |
| default_slice | No | The dataset's total codes from its default view — the slice ilostat_compare_geographies uses when sex, classif1, or classif2 is omitted; a breakdown with no total (deciles) is left out. |
| has_aggregates | No | Whether the requested dataset (or, for an indicator code, any of its datasets) carries World, regional, or income-group rows. |
| related_datasets | No | Up to 20 other indicators sharing this measure under other breakdowns. |
| structure_status | No | unavailable when ILOSTAT's structure service has no entry for the indicator or cannot be reached; breakdowns, default_slice, unit, and ref_areas are then absent. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, openWorld, so the safety profile is covered by structured data. The description adds real behavioral context beyond that: an unknown code returns found: false with guidance, and a bare indicator code describes every frequency variant. It does not discuss rate limits or the output shape in depth, 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
The content is dense but front-loaded: the purpose verb and the list of what is explained lead, and the accepted-input and error behavior follow. Every clause maps to a real aspect of the response, though the long enumerations make it heavier than a minimal definition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, yet the description still summarizes what the agent will get (definitions, units, codes, aggregates, classification), plus the input forms and the not-found behavior. For a single-parameter, well-schema'd read tool this is complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema by clarifying that a bare indicator code expands to every frequency (schema only calls it 'a bare indicator code'). It also reinforces the accepted forms and lists a concrete example, though it largely parallels the schema's own guidance.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb+resource (explain/describe one ILOSTAT dataset) and enumerates exactly what the explanation contains: definition, unit/multiplier, frequency variants, breakdown codes, coverage, aggregates, and observation classification. It explicitly positions itself against the comparison/query siblings with 'before comparing numbers', so an agent can place it without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Explain one ILOSTAT dataset before comparing numbers' gives a clear when-to-use signal that routes the agent away from ilostat_compare_geographies and ilostat_query_indicator. It does not explicitly name those alternatives or state exclusions, so it stops short of the top band.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ilostat_get_country_profileGet an ILOSTAT labour-market profileARead-onlyIdempotentInspect
Build a headline labour-market profile for one reference area: labour force participation, employment-to-population ratio, unemployment and youth unemployment rates, youth NEET rate, informal employment rate, employment level, labour income share, and working poverty rate. Each indicator shows its latest reported value (from a national or institutional source, with its source and notes) and, separately, its latest ILO modelled estimate that is not a projection, each with its dataset, period, and status — a missing reported value stays missing and is never filled from the model. Accepts a country (ISO3, e.g. KEN) or an X-coded aggregate (X01 World, regions, income groups), for which only modelled values exist.
| Name | Required | Description | Default |
|---|---|---|---|
| sex | No | SEX_T (default), SEX_M, or SEX_F; T/M/F and total/both/male/female are accepted. Indicators without a sex breakdown (labour income share) are unaffected. | SEX_T |
| ref_area | Yes | One reference area with annual data: an ISO3 country code (KEN) or an X-coded aggregate (X01 World, X06, X02); ILO_GEO_ forms accepted, case-insensitive. ilostat_list_reference topic ref_areas lists them. |
Output Schema
| Name | Required | Description |
|---|---|---|
| sex | No | Sex code profiled. |
| error | No | Present when the call failed. Absent on success. |
| notice | No | Which indicators have no reported value, and which of those have an ILO modelled estimate instead. |
| ref_area | No | The area profiled. |
| indicators | No | The headline indicators, in a fixed order. |
| attribution | No | Citation to keep with any use of the data. |
| catalog_as_of | No | ISO timestamp the catalog was last confirmed current. |
| reported_missing | No | Keys with no reported value, including those that have no reported dataset. |
| modelled_cutoff_year | No | Latest year the modelled values could come from; later modelled years are projections. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent and open-world behaviour, so the bar is lower. The description nonetheless adds real behavioural context beyond them: each indicator shows latest reported value plus separately the latest non-projection ILO modelled estimate, without imputing missing reported values, and aggregates carry only modelled values. That is substantive disclosure of data-provenance semantics.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three long sentences carry dense but relevant content, and the indicator inventory plus scope are front-loaded. The first sentence's indicator list is heavy but every element is load-bearing for a profile tool, so there is little waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and full schema coverage, the description needn't explain return values, and it covers the non-obvious behavioural points an agent needs: reported vs modelled values, missing-value handling, and aggregate-only modelling. It stops short of routing guidance among the seven sibling tools, which is the only material gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are already documented, and the baseline of 3 applies. The description reinforces ref_area semantics by naming ISO3 and X-coded aggregate forms with examples and noting that aggregates only have modelled values, but says nothing about the sex parameter beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb ('Build a headline labour-market profile') and resource (one reference area), and enumerates the nine indicators returned, so the agent knows exactly what the tool produces. It is clearly a bundled multi-indicator snapshot, which implicitly separates it from single-indicator query tools, but it never names a sibling to make the contrast explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by scope: 'one reference area' with country or X-coded aggregate accepted, which tells the agent the input shape but not when to prefer this over ilostat_query_indicator or ilostat_compare_geographies. There are no explicit when-to-use or when-not conditions and no named alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ilostat_list_referenceList ILOSTAT reference codesARead-onlyIdempotentInspect
Decode ILOSTAT's code vocabulary: reference areas (ISO3 countries and X-coded aggregates, with World Bank income group and ILO region), the groups that area_group accepts (X01 for every country, ILO regions and subregions, World Bank income groups; exact-code lookups list their member countries), databases, subjects, sex codes, breakdown codes for classif1/classif2 with their classification types, per-country data sources, observation status flags, note codes, and frequencies. Filter by text or look up exact codes; long topics page with a cursor. These are ILOSTAT-wide vocabularies; ilostat_describe_indicator lists the sex and breakdown codes one dataset actually uses.
| Name | Required | Description | Default |
|---|---|---|---|
| codes | No | Exact codes to look up (up to 100; case-insensitive, and ILO_GEO_ forms accepted for ref_areas and area_groups). Codes the topic lacks are listed in not_found. With topic area_groups, each group found also lists its member countries. | |
| limit | No | Entries per page (1–500). | |
| topic | Yes | Vocabulary to list: ref_areas, area_groups (the X codes area_group accepts), databases, subjects, sexes, classifications (classif1/classif2 codes), classification_types, sources, obs_status, notes, or frequencies. | |
| cursor | No | Opaque continuation token: the previous page's next_cursor, passed unchanged. | |
| filter | No | Text filter: every word must match a word or word prefix of the code or label (case, accents, and punctuation ignored; labor matches labour). Omit to list the whole topic. | |
| ref_area | No | Topic sources only: list the sources of this reference area (ISO3 or X code; case-insensitive, ILO_GEO_ forms accepted). | |
| classification_type | No | Topic classifications only: keep codes of this classification type, the code prefix (AGE, ECO, EDU, …). |
Output Schema
| Name | Required | Description |
|---|---|---|
| cap | No | The limit applied to this page. |
| error | No | Present when the call failed. Absent on success. |
| shown | No | Entries returned on this page. |
| topic | No | The topic listed. |
| total | No | Entries matching the filters, across all pages. |
| notice | No | Why a filter with no searchable word was not applied, why nothing matched, that the cursor starts past the last entry, and how to reach the remaining pages — whichever apply, joined. |
| entries | No | This page of decoded codes, ordered by code — except sexes, which keep the ILOSTAT dictionary's order (SEX_T first), and frequencies, listed annual, quarterly, monthly. |
| not_found | No | Requested codes the topic does not contain; present only when codes missed. |
| truncated | No | True when more entries remain beyond this page. |
| next_cursor | No | Pass as cursor to get the next page; absent on the last page. |
| catalog_as_of | No | ISO timestamp the in-memory catalog was last confirmed current. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and openWorldHint=false, so the safety profile is covered. The description adds genuine behavior beyond that: pagination via cursor, that missing codes surface in not_found, that area_group exact lookups expand to member countries, and that matching is case/accents/punctuation-insensitive. It omits nothing critical and adds real context on a lower bar.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and the enumeration of topics are front-loaded, and the second sentence's routing to ilostat_describe_indicator is high-value. The long comma-separated topic list overlaps with the schema enum, which is mild redundancy, but every clause is informative and no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a rich 7-parameter schema, full coverage descriptions, and an output schema, the description need not explain return values. It covers topics, filtering, exact-code lookup, pagination, and sibling routing, leaving only minor gaps such as how next_cursor is returned.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description nonetheless adds meaning beyond the schema: the X01 aggregate convention for area_group, the ILO_GEO_ form tolerance, and which topics accept which lookup codes — useful disambiguation that the enum alone does not convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Decode ILOSTAT's code vocabulary') and enumerates exactly what gets listed (ref areas, groups, databases, subjects, sexes, breakdown codes, sources, flags, notes, frequencies). It explicitly distinguishes itself from the sibling ilostat_describe_indicator by contrasting ILOSTAT-wide vocabularies with the codes one dataset uses.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the two operating modes ('Filter by text or look up exact codes') and flags that long topics paginate with a cursor, plus the alternative tool for dataset-specific codes. It stops short of explicit when-not-to-use conditions (e.g., when a numeric query is the right call instead), so it falls just 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.
ilostat_query_indicatorQuery ILOSTAT observationsARead-onlyIdempotentInspect
Fetch observations for up to 3 ILOSTAT datasets, filtered by reference area or area group, sex, breakdown codes (classif1, classif2), source, and period. Rows keep their source, observation status, decoded notes, and a basis — reported, modelled_estimate, or projection — and the response echoes every filter applied, including the best-source default. Codes are checked against ILOSTAT's dictionaries before the request is sent: ilostat_list_reference lists valid codes and ilostat_describe_indicator lists the codes a dataset actually uses. A result larger than the inline preview is staged in full as a df_ dataframe for SQL through ilostat_dataframe_describe and ilostat_dataframe_query when this deployment enables dataframes. A request with no filters at all is refused when the dataset exceeds the row ceiling, and a filtered request that still exceeds it is refused with guidance to narrow it.
| Name | Required | Description | Default |
|---|---|---|---|
| sex | No | Sex codes SEX_T, SEX_M, SEX_F, SEX_O; T/M/F/O and total/both/male/female/other are accepted. | |
| time | No | One exact period: YYYY (on a quarterly or monthly dataset, every period of that year), YYYYQn, or YYYYMmm; 2024-Q2, 2024 Q2, and 2025-03 are normalized. Not combinable with time_from, time_to, or latest_only. | |
| sources | No | Source codes (e.g. BA:453); ilostat_list_reference topic sources with ref_area lists an area's sources. Without source_selection, setting sources switches it to all, since a secondary source matches nothing under best. | |
| time_to | No | Last year (YYYY), not before time_from. | |
| classif1 | No | Codes of the first breakdown (e.g. AGE_YTHADULT_YGE15); case-insensitive. ilostat_describe_indicator lists the codes a dataset uses. | |
| classif2 | No | Codes of the second breakdown, for datasets that have one; case-insensitive. ilostat_describe_indicator lists them. | |
| ref_areas | No | Reference areas (up to 300): ISO3 country codes (USA) or X-coded aggregates (X01 World); case-insensitive, ILO_GEO_ forms accepted. Aggregates need a dataset with has_aggregates true. Omit for every area. | |
| time_from | No | First year (YYYY); upstream filters by year only. | |
| area_group | No | X01 for every country, an ILO region or subregion, or a World Bank income group (X06, X56, X02, …); expands to its member countries, unioned with ref_areas. ilostat_list_reference topic area_groups lists the codes. | |
| dataset_ids | Yes | One to three dataset IDs — an indicator code plus _A, _Q, or _M (UNE_DEAP_SEX_AGE_RT_A), as ilostat_search_indicators returns them. Case-insensitive; a DF_ prefix (the SDMX dataflow form) is stripped, a bare indicator code resolves when it has one frequency, and an element holding + or , joined IDs is split. | |
| latest_only | No | Only the latest period per reference area and dataset (the latest quarter or month on sub-annual datasets); combines with time_from/time_to. | |
| source_selection | No | best (default): the preferred source per area and period; all: secondary sources too, each row flagged best_source; secondary: secondary sources only. Defaults to all when sources is set. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cap | No | Inline preview budget, in serialized characters. |
| rows | No | Inline preview rows; the staged dataframe holds every row when the result is larger. |
| error | No | Present when the call failed. Absent on success. |
| shown | No | Rows returned inline. |
| legend | No | Labels for every code in rows. |
| notice | No | Filters that could not narrow a dataset, a unit the structure service could not supply, why nothing matched, where the full result is staged, or why reading stopped early. |
| summary | No | Summary over every row read, not just the preview. |
| datasets | No | The requested datasets, in request order. |
| dataframe | No | The staged dataframe holding the full result; present only when staged. |
| row_count | No | Rows the request returned — exact when the result is inline or staged; when reading stopped early (truncated), the rows read. |
| truncated | No | True when reading stopped at the inline preview and more rows exist. |
| attribution | No | Citation to keep with any use of the data. |
| applied_filters | No | Every parameter sent upstream, defaults included. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/idempotent/openWorld annotations: it discloses row content (source, observation status, decoded notes, reported/modelled_estimate/projection basis), filter echo semantics, code pre-validation against ILOSTAT dictionaries, dataframe staging for oversized results, and two distinct refusal conditions (unfiltered over ceiling, filtered still over ceiling). That is unusually rich behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and scope, and each subsequent sentence carries distinct information (row shape, validation, staging, refusals). It is dense as a single paragraph, but virtually no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be spelled out, yet the description still explains the meaningful row attributes and filter echo. Combined with refusal behavior and dataframe hand-off, an agent has everything needed to call this correctly in a complex, 12-parameter, multi-dataset query tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema itself documents all 12 parameters in detail, including the sources/source_selection interaction and normalization rules. The description's summary of filter dimensions and the 'best-source default' echo adds reinforcement but no new parameter syntax beyond what the schema provides, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Fetch observations for up to 3 ILOSTAT datasets') with explicit scope limits and the filter dimensions it accepts. It also distinguishes itself from siblings by naming ilostat_list_reference and ilostat_describe_indicator as code-resolution tools and the dataframe tools as the path for large results.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly routes the agent: consult ilostat_list_reference / ilostat_describe_indicator for valid codes before calling, and use ilostat_dataframe_describe / ilostat_dataframe_query when a result is staged. It does not explicitly contrast this tool with ilostat_compare_geographies or ilostat_get_country_profile, so it stops short of full when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ilostat_search_indicatorsSearch ILOSTAT indicatorsARead-onlyIdempotentInspect
Search ILOSTAT's catalog of labour-statistics indicators by plain-language terms and filters. Each hit is one indicator with its datasets — one per available frequency (annual, quarterly, monthly) — plus breakdowns, coverage years, number of reference areas, source database, and last update; pass a dataset ID to ilostat_describe_indicator for its units and breakdown codes, then to ilostat_query_indicator or ilostat_compare_geographies for values. Every search term must match a word or word prefix in the indicator's label, subject, database, breakdown names, code, or definition; British and American spellings (labour/labor) match alike. Facet counts reflect all applied filters.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Hits per page (1–50). | |
| query | No | Plain-language terms, e.g. "youth unemployment" or "informal employment rate". Case, accents, and punctuation are ignored, labor matches labour, and a trailing plural s is tolerated. Omit to browse by filters (results then order by indicator code). | |
| cursor | No | Opaque continuation token: the previous page's next_cursor, passed unchanged. | |
| subject | No | Subject code, e.g. LUU (unemployment and labour underutilization); case-insensitive. ilostat_list_reference topic subjects lists them. | |
| database | No | Source database code, e.g. LFS or ILOEST (the ILO modelled estimates); case-insensitive. ilostat_list_reference topic databases lists them. | |
| breakdown | No | Classification type the indicator is broken down by, e.g. AGE, ECO, GEO, SEX; case-insensitive. ilostat_list_reference topic classification_types lists them. | |
| frequency | No | Keep only datasets of this frequency: A annual, Q quarterly, M monthly. Narrows each hit's datasets; an indicator with none left drops out. | |
| aggregates_only | No | Keep only datasets carrying World, regional, or income-group rows, dropping indicators with none. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cap | No | The limit applied to this page. |
| hits | No | This page of hits. With a query: tier, then more reference areas first, then code. Without: by code. |
| error | No | Present when the call failed. Absent on success. |
| shown | No | Hits returned on this page. |
| total | No | Indicators matched after all filters. |
| facets | No | Counts over the fully filtered match set, not just this page. |
| notice | No | Why the query was browsed by filters alone, how to widen a search that matched nothing, that the cursor starts past the last match, and how to reach the remaining pages — whichever apply, joined. |
| truncated | No | True when more hits remain beyond this page. |
| next_cursor | No | Pass as cursor to get the next page; absent on the last page. |
| catalog_as_of | No | ISO timestamp the searched catalog was last confirmed current. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/closed-world, and the description adds substantive behavioral detail beyond them: matching is word/prefix based across label, subject, database, breakdown names, code, and definition; British and American spellings match alike; facet counts reflect all applied filters. These are non-obvious search semantics the agent could not infer from annotations or schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose and return shape, then the workflow, then matching semantics. The first sentence is long and packs several clauses, but every sentence carries information with no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter, zero-required search tool with an output schema, the description covers the non-obvious behavior: return shape, matching rules, spelling tolerance, filter-as-query fallback, and downstream tool routing. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds meaning beyond the schema: it clarifies the AND semantics of multiple terms, prefix matching, the frequency-to-datasets relationship ('an indicator with none left drops out'), and that filters can substitute for a query. This is value beyond the parameter descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Search ILOSTAT's catalog of labour-statistics indicators') and immediately describes what a hit contains. It distinguishes itself from siblings by naming ilostat_describe_indicator, ilostat_query_indicator, and ilostat_compare_geographies as the downstream steps, so an agent knows this is the entry-point search, not a query tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit workflow guidance: pass a dataset ID to describe_indicator, then to query_indicator or compare_geographies for values, and 'Omit to browse by filters'. It does not name exclusions (e.g. use ilostat_list_reference for code discovery) beyond the schema hints, so it stops short of full when/when-not coverage.
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.
8 tool updates
- First observed
ilostat_compare_geographies - First observed
ilostat_dataframe_describe - First observed
ilostat_dataframe_query - First observed
ilostat_describe_indicator - First observed
ilostat_get_country_profile - First observed
ilostat_list_reference - First observed
ilostat_query_indicator - First observed
ilostat_search_indicators
Related MCP Connectors
Search and query the Eurostat catalogue — EU economy, demography, trade, and NUTS regional data.
Search and query 1,500+ OECD statistical datasets via SDMX. Keyless.
Labour market data from the ILO (ILOSTAT) by country, year, sex and age, with provenance.
Query 29,500+ World Bank development indicators for 200+ countries across 60+ years.
Related MCP Servers
- AlicenseAqualityAmaintenanceMCP server for accessing ILOSTAT (ILO statistical database) with tools to search indicators, retrieve metadata, list dimension values, and fetch data, with full provenance tracking.6686 npm1MIT
- AlicenseNot gradedqualityBmaintenanceEnables access to global labour statistics from ILOSTAT via the Pipeworx gateway.647 npmMIT
- AlicenseNot gradedqualityAmaintenanceEnables searching, exploring, and querying over 1,500 OECD statistical datasets via SDMX, covering national accounts, employment, trade, PISA, health, and more.95 npm2Apache 2.0
- AlicenseNot gradedqualityCmaintenanceEnables keyword search and retrieval of observations, dimensions, and code lists from Stats NZ's published datasets, covering censuses, earnings, business demography, population projections, household expenditure, and justice statistics.96 npmMIT
Glama MCP Gateway
Add one secure layer between your agents and this server.