Koskamo

oecd-mcp-server

An MCP server that allows agents to search, explore, and query over 1,500 OECD statistical datasets via the SDMX API. It provides tools to list agencies, search dataflows, get dataset dimensions, fetch dimension values, and query observations, supporting both STDIO and Streamable HTTP transports without requiring an API key.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

oecd-mcp-server logo, by cyanheadsCommunity listingStreamable HTTPNo sign-inEndpoint checked 2026-11-06Published by cyanheads
MCP endpoint (Streamable HTTP)
https://oecd.caseyjhand.com/mcp
Vendor documentation

What its tools do

7 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.

7 of 7 have a description · 7 of 7 declare behavior hints · 6 of 6 with parameters document them all

Checks and signals

Each line is separate evidence, not a trust score.

  • Passed Endpoint answered the live check ·
  • Availability 1 of 1 checks passed in 30 days

What you can do with it

  • Search OECD dataflows by keyword or theme
  • List OECD SDMX agencies and their directorates
  • Fetch valid codes and labels for dataflow dimensions
  • Query observations filtered by dimension key and time range

Source and maintenance

Community listingRegistry 0.6.1
Maintenance checked

Protocol and capabilities

Server
oecd-mcp-server 0.6.1
MCP protocol negotiated in check
2025-11-25
Tools
7 advertised
Resources
1 advertised
Resource templates
2 advertised
Prompts
0 advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": true
  },
  "logging": {},
  "prompts": {
    "listChanged": true
  },
  "resources": {
    "subscribe": true,
    "listChanged": true
  },
  "extensions": {
    "io.modelcontextprotocol/skills": {
      "directoryRead": true
    }
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

OECD Statistics MCP server — keyless access to 1,500+ OECD dataflows via SDMX 2.1. Workflow: oecd_list_agencies → oecd_search_datasets → oecd_get_dataset_info → oecd_get_dimension_values → oecd_query_dataset. Large results (multi-country time-series) spill to DataCanvas; use oecd_dataframe_describe + oecd_dataframe_query for SQL analytics. The oecd-guide skill (skill://oecd-guide/SKILL.md) covers key construction, confirming which series a dataflow carries, and reading results without mixing breakdowns or aggregates. All data is attributed to OECD per their terms of use.

Tools

7 advertised

oecd_list_agencies — Oecd List Agencies
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

List OECD SDMX agencies, the directorate each belongs to, and the number of dataflows each publishes. Use to discover agency IDs before filtering oecd_search_datasets by department.

oecd_list_agencies input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {},
  "additionalProperties": false
}
oecd_list_agencies output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "agencies",
        "total_agencies",
        "total_dataflows",
        "source"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "rate_limited",
                "upstream_timeout",
                "upstream_unavailable",
                "upstream_redirect",
                "upstream_error"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `rate_limited`: OECD throttled the request rate and was still refusing after the retries. `upstream_timeout`: OECD did not finish responding before OECD_TIMEOUT_MS elapsed. `upstream_unavailable`: OECD returned a server fault or was unreachable once the retries ran out. `upstream_redirect`: The configured OECD host answered with a redirect, which this server never follows. `upstream_error`: OECD refused the request with a status this server does not model — an authorization challenge, a rejection from something sitting in front of the API, or a request read as malformed. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "source": {
      "type": "string",
      "const": "OECD",
      "description": "Data source attribution — always \"OECD\"."
    },
    "agencies": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "agency_id",
          "dataflow_count"
        ],
        "properties": {
          "agency_id": {
            "type": "string",
            "description": "Agency identifier — e.g. OECD.SDD.NAD."
          },
          "directorate": {
            "type": "string",
            "description": "Name of the OECD directorate the agency sits in, resolved from the directorate segment of the identifier — OECD.SDD.NAD is \"Statistics and Data Directorate\". Absent for a publisher outside OECD and when the agency scheme could not be reached."
          },
          "dataflow_count": {
            "type": "number",
            "description": "Number of dataflows published by this agency."
          }
        },
        "description": "An agency, its directorate, and its dataflow count.",
        "additionalProperties": false
      },
      "description": "Agencies and their dataflow counts, sorted descending by count."
    },
    "total_agencies": {
      "type": "number",
      "description": "Total number of distinct agencies."
    },
    "total_dataflows": {
      "type": "number",
      "description": "Total number of dataflows across all agencies."
    }
  },
  "additionalProperties": false
}
oecd_list_agencies annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true
}
oecd_search_datasets — Oecd Search Datasets
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Search OECD dataflows by keyword or theme, matching against dataflow names and descriptions. Returns flow_ref identifiers, names, and agency IDs for use with oecd_get_dataset_info.

oecd_search_datasets input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "query"
  ],
  "properties": {
    "limit": {
      "type": "integer",
      "default": 20,
      "maximum": 100,
      "minimum": 1,
      "description": "Maximum number of results to return (1–100, default 20)."
    },
    "query": {
      "type": "string",
      "description": "Keyword or phrase to search for in dataflow names and descriptions — e.g. \"GDP\", \"employment\", \"education\". Every whitespace-separated token must appear somewhere in the name or description."
    },
    "offset": {
      "type": "integer",
      "default": 0,
      "maximum": 9007199254740991,
      "minimum": 0,
      "description": "Zero-based index of the first match to return, applied before limit. Page through results past the limit by advancing it; an offset at or past total_matches returns an empty list."
    },
    "agency_id": {
      "type": "string",
      "description": "Optional agency identifier to restrict the search scope — e.g. \"OECD.SDD.NAD\". Obtain valid agency IDs from oecd_list_agencies."
    }
  },
  "additionalProperties": false
}
oecd_search_datasets output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "dataflows",
        "result_count",
        "total_matches",
        "offset",
        "source"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "no_match",
                "agency_not_found",
                "rate_limited",
                "upstream_timeout",
                "upstream_unavailable",
                "upstream_redirect",
                "upstream_error"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `no_match`: No dataflows matched the search query. `agency_not_found`: The supplied agency_id does not exist in the OECD SDMX catalog. `rate_limited`: OECD throttled the request rate and was still refusing after the retries. `upstream_timeout`: OECD did not finish responding before OECD_TIMEOUT_MS elapsed. `upstream_unavailable`: OECD returned a server fault or was unreachable once the retries ran out. `upstream_redirect`: The configured OECD host answered with a redirect, which this server never follows. `upstream_error`: OECD refused the request with a status this server does not model — an authorization challenge, a rejection from something sitting in front of the API, or a request read as malformed. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "offset": {
      "type": "number",
      "description": "Zero-based index of the first returned result within the full match list."
    },
    "source": {
      "type": "string",
      "const": "OECD",
      "description": "Data source attribution — always \"OECD\"."
    },
    "dataflows": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "flow_ref",
          "agency_id",
          "name",
          "matched_in",
          "non_production"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Human-readable dataflow name."
          },
          "flow_ref": {
            "type": "string",
            "description": "Full flow reference — {agencyID},{dsd_id}@{df_id}, or {agencyID},{df_id} for the few dataflows OECD publishes without a datastructure prefix. Pass through unchanged to oecd_get_dataset_info or oecd_query_dataset."
          },
          "agency_id": {
            "type": "string",
            "description": "Publishing agency identifier."
          },
          "matched_in": {
            "enum": [
              "name",
              "description",
              "both"
            ],
            "type": "string",
            "description": "Which field carried every query token — \"name\" or \"description\" when only that one did, \"both\" when each did on its own or the tokens were split across the two."
          },
          "description": {
            "type": "string",
            "description": "Plain-text abstract of what the dataset covers, truncated to 240 characters. Matching runs against the full abstract, so a term reported in matched_in may sit past the cut. Absent when OECD publishes no description for the dataflow."
          },
          "non_production": {
            "type": "boolean",
            "description": "True if flagged as experimental or deprecated by OECD."
          }
        },
        "description": "A matching OECD dataflow entry.",
        "additionalProperties": false
      },
      "description": "Matching dataflows for the requested page, up to the requested limit."
    },
    "totalCount": {
      "type": "number",
      "description": "Total dataflows matching the query, disclosed when matches remain beyond the returned page."
    },
    "result_count": {
      "type": "number",
      "description": "Number of results returned (may be less than total_matches)."
    },
    "total_matches": {
      "type": "number",
      "description": "Total dataflows matching the query before applying offset and limit."
    }
  },
  "additionalProperties": false
}
oecd_search_datasets annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true
}
oecd_get_dataset_info — Oecd Get Dataset Info
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Fetch a dataflow's dimensions, their order, and how to construct a query key. Returns per-dimension names, codelist references, and position in the dot-delimited key. Required before calling oecd_query_dataset to understand key structure.

oecd_get_dataset_info input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "flow_ref"
  ],
  "properties": {
    "flow_ref": {
      "type": "string",
      "description": "Full flow reference, either {agencyID},{dsd_id}@{df_id} — e.g. \"OECD.SDD.NAD,DSD_NAAG@DF_NAAG_I\" — or the bare {agencyID},{df_id} form OECD uses for the few dataflows published without a datastructure prefix. Obtain from oecd_search_datasets."
    }
  },
  "additionalProperties": false
}
oecd_get_dataset_info output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "flow_ref",
        "dimensions",
        "key_example",
        "non_production",
        "source"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "invalid_flow_ref",
                "dataflow_not_found",
                "rate_limited",
                "upstream_timeout",
                "upstream_unavailable",
                "upstream_redirect",
                "upstream_error"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `invalid_flow_ref`: The flow_ref parameter matches neither the {agencyID},{dsd_id}@{df_id} nor the {agencyID},{df_id} format. `dataflow_not_found`: No datastructure was found for the provided flow_ref. `rate_limited`: OECD throttled the request rate and was still refusing after the retries. `upstream_timeout`: OECD did not finish responding before OECD_TIMEOUT_MS elapsed. `upstream_unavailable`: OECD returned a server fault or was unreachable once the retries ran out. `upstream_redirect`: The configured OECD host answered with a redirect, which this server never follows. `upstream_error`: OECD refused the request with a status this server does not model — an authorization challenge, a rejection from something sitting in front of the API, or a request read as malformed. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "source": {
      "type": "string",
      "const": "OECD",
      "description": "Data source attribution — always \"OECD\"."
    },
    "flow_ref": {
      "type": "string",
      "description": "The resolved flow reference."
    },
    "dimensions": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "id",
          "name",
          "position"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Dimension identifier — e.g. REF_AREA."
          },
          "name": {
            "type": "string",
            "description": "Concept name for the dimension — e.g. \"Reference area\" for REF_AREA. Repeats the id when OECD publishes no concept for it."
          },
          "position": {
            "type": "number",
            "description": "1-based position in the dot-delimited key. Segment at this position corresponds to this dimension."
          },
          "codelist_ref": {
            "type": "string",
            "description": "Codelist reference in the form {agencyID},{codelistID} — use with oecd_get_dimension_values."
          }
        },
        "description": "A dataflow dimension with its key position and codelist reference.",
        "additionalProperties": false
      },
      "description": "Dimensions in ascending position order."
    },
    "key_example": {
      "type": "string",
      "description": "Example dot-delimited key with wildcards — each dot corresponds to one dimension in position order. Empty segments are wildcards. Replace with actual codes from oecd_get_dimension_values."
    },
    "non_production": {
      "type": "boolean",
      "description": "True if OECD flagged this dataflow as experimental or deprecated."
    },
    "time_dimension": {
      "type": "object",
      "required": [
        "id",
        "name",
        "position"
      ],
      "properties": {
        "id": {
          "type": "string",
          "description": "Time dimension identifier — typically TIME_PERIOD."
        },
        "name": {
          "type": "string",
          "description": "Concept name for the time dimension, repeating the id when none is published."
        },
        "position": {
          "type": "number",
          "description": "Position after all regular dimensions."
        }
      },
      "description": "Time dimension — used for startPeriod/endPeriod filtering in oecd_query_dataset.",
      "additionalProperties": false
    }
  },
  "additionalProperties": false
}
oecd_get_dataset_info annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true
}
oecd_get_dimension_values — Oecd Get Dimension Values
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Fetch the valid codes and labels for one dimension of a dataflow. Use to resolve human-readable names (countries, measures) to SDMX codes before querying with oecd_query_dataset. Pass query to match a code or label by substring — codelists run to a thousand-plus entries, and the response is a page of at most limit codes either way.

oecd_get_dimension_values input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "flow_ref",
    "dimension_id"
  ],
  "properties": {
    "limit": {
      "type": "integer",
      "default": 50,
      "maximum": 500,
      "minimum": 1,
      "description": "Maximum codes to return (1–500, default 50)."
    },
    "query": {
      "type": "string",
      "description": "Case-insensitive substring matched against both the code and its label, so \"PA\" and \"percent\" each reach the code \"PA\" / \"Percent per annum\". Omit to page the whole codelist."
    },
    "offset": {
      "type": "integer",
      "default": 0,
      "maximum": 9007199254740991,
      "minimum": 0,
      "description": "Zero-based index of the first code to return within the matching list, applied before limit. Advance it to page; an offset past the last match returns an empty page."
    },
    "flow_ref": {
      "type": "string",
      "description": "Full flow reference — e.g. \"OECD.SDD.NAD,DSD_NAAG@DF_NAAG_I\", or the bare \"OECD.TAD.ARP,DF_AEI2024_DASHBOARD\" form for a dataflow published without a datastructure prefix. Obtain from oecd_search_datasets."
    },
    "dimension_id": {
      "type": "string",
      "description": "Dimension identifier to fetch codes for — e.g. \"REF_AREA\" or \"MEASURE\". Obtain valid dimension IDs from oecd_get_dataset_info."
    }
  },
  "additionalProperties": false
}
oecd_get_dimension_values output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "flow_ref",
        "dimension_id",
        "codes",
        "code_count",
        "source"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "codes": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "SDMX code — use in the dimension key for oecd_query_dataset."
          },
          "name": {
            "type": "string",
            "description": "Human-readable label for the code."
          }
        },
        "description": "A valid SDMX code and its human-readable label.",
        "additionalProperties": false
      },
      "description": "The requested page of codes, after query, offset, and limit are applied."
    },
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "invalid_flow_ref",
                "dataflow_not_found",
                "dimension_not_found",
                "rate_limited",
                "upstream_timeout",
                "upstream_unavailable",
                "upstream_redirect",
                "upstream_error"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `invalid_flow_ref`: The flow_ref parameter matches neither the {agencyID},{dsd_id}@{df_id} nor the {agencyID},{df_id} format. `dataflow_not_found`: The flow_ref does not correspond to a known dataflow. `dimension_not_found`: The dimension_id is not present in this dataflow's structure. `rate_limited`: OECD throttled the request rate and was still refusing after the retries. `upstream_timeout`: OECD did not finish responding before OECD_TIMEOUT_MS elapsed. `upstream_unavailable`: OECD returned a server fault or was unreachable once the retries ran out. `upstream_redirect`: The configured OECD host answered with a redirect, which this server never follows. `upstream_error`: OECD refused the request with a status this server does not model — an authorization challenge, a rejection from something sitting in front of the API, or a request read as malformed. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "notice": {
      "type": "string",
      "description": "Present when the page needs explaining — the dimension has no codelist, the query matched nothing, or codes remain beyond the page. States how to reach the rest."
    },
    "source": {
      "type": "string",
      "const": "OECD",
      "description": "Data source attribution — always \"OECD\"."
    },
    "flow_ref": {
      "type": "string",
      "description": "The flow reference this dimension belongs to."
    },
    "code_count": {
      "type": "number",
      "description": "Number of codes in this page — not the size of the dimension's codelist."
    },
    "totalCount": {
      "type": "number",
      "description": "Codes matching before offset and limit, disclosed when the page does not cover them all."
    },
    "dimension_id": {
      "type": "string",
      "description": "The dimension whose codes are listed."
    },
    "effectiveQuery": {
      "type": "string",
      "description": "The substring filter as applied. Absent when the whole codelist was paged."
    }
  },
  "additionalProperties": false
}
oecd_get_dimension_values annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true
}
oecd_query_dataset — Oecd Query Dataset
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Fetch observations from an OECD dataflow filtered by a dimension key and optional time range. Returns decoded rows (one per observation) with dimension and attribute labels, and values already scaled by the observation unit multiplier. Large multi-country time-series spill to a DataCanvas table — inspect columns with oecd_dataframe_describe, then query the full table with SQL using oecd_dataframe_query; without DataCanvas every row still comes back, but the rendered table stops at a preview slice. Call oecd_get_dataset_info first to learn the dimension order for constructing the key.

oecd_query_dataset input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "flow_ref",
    "key"
  ],
  "properties": {
    "key": {
      "type": "string",
      "description": "Dot-delimited dimension key matching the dimension order from oecd_get_dataset_info. Empty segments are wildcards; \"+\" separates multiple values per segment. Example: \"A.USA+DEU.B1GQ..\" — Annual, USA or Germany, GDP, all remaining dimensions."
    },
    "flow_ref": {
      "type": "string",
      "description": "Full flow reference — e.g. \"OECD.SDD.NAD,DSD_NAAG@DF_NAAG_I\", or the bare \"OECD.TAD.ARP,DF_AEI2024_DASHBOARD\" form for a dataflow published without a datastructure prefix. Obtain from oecd_search_datasets and pass it through unchanged."
    },
    "canvas_id": {
      "type": "string",
      "pattern": "^[A-Za-z0-9_-]{10}$",
      "description": "Canvas ID from a prior oecd_query_dataset call — exactly 10 characters of letters, digits, hyphens, and underscores — to stage this result alongside that one if it spills; a result that fits inline comes back inline and leaves that canvas unchanged. Omit to let the server mint a canvas if this result needs one; a canvas_id comes back only when the result was large enough to spill."
    },
    "end_period": {
      "type": "string",
      "description": "End of the time range — ISO period code such as \"2023\" or \"2023-Q4\". Omit to include up to the latest available period."
    },
    "start_period": {
      "type": "string",
      "description": "Start of the time range — ISO period code such as \"2010\", \"2010-Q1\", or \"2010-01\". Omit to include all history (may produce very large results)."
    }
  },
  "additionalProperties": false
}
oecd_query_dataset output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "rows",
        "row_count",
        "query_flow_ref",
        "query_key",
        "source"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "rows": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {},
        "description": "Decoded observation row. One key per dataflow dimension (e.g. REF_AREA, TIME_PERIOD) and per observation attribute (e.g. UNIT_MULT, OBS_STATUS, PRICE_BASE), each holding a human-readable label; attributes absent from this slice are omitted. Plus \"value\" — the observation already multiplied by \"value_scale\", the power of ten from UNIT_MULT (1 when the dataflow declares no multiplier; divide value by it for the figure as OECD published it) — and \"source\" (\"OECD\").",
        "additionalProperties": {}
      },
      "description": "Observation rows. Every row of the result when truncated is absent; the leading preview slice when truncated is true — query the canvas table for the rest."
    },
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "invalid_flow_ref",
                "dataflow_not_found",
                "no_results",
                "invalid_key",
                "invalid_period",
                "rate_limited",
                "download_limit",
                "canvas_not_found",
                "upstream_timeout",
                "upstream_unavailable",
                "upstream_redirect",
                "upstream_error"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `invalid_flow_ref`: The flow_ref parameter matches neither the {agencyID},{dsd_id}@{df_id} nor the {agencyID},{df_id} format. `dataflow_not_found`: The flow_ref does not correspond to a known OECD dataflow. `no_results`: The dataflow exists but no observations matched the key and time range. `invalid_key`: OECD rejected the dimension key — wrong number of segments, or an unsupported format. `invalid_period`: OECD could not parse start_period or end_period. `rate_limited`: OECD throttled the request rate and was still refusing after the retries. `download_limit`: OECD refused the query for exceeding its data-download or data-range limit. `canvas_not_found`: The canvas_id has expired or was never created. It is checked before anything is fetched from OECD. `upstream_timeout`: OECD did not finish responding before OECD_TIMEOUT_MS elapsed. `upstream_unavailable`: OECD returned a server fault or was unreachable once the retries ran out. `upstream_redirect`: The configured OECD host answered with a redirect, which this server never follows. `upstream_error`: OECD refused the request with a status this server does not model — an authorization challenge, a rejection from something sitting in front of the API, or a request read as malformed. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "notice": {
      "type": "string",
      "description": "How to inspect and query the staged result, including its canvas_id and table name; present only after a spill."
    },
    "source": {
      "type": "string",
      "const": "OECD",
      "description": "Data source attribution — always \"OECD\"."
    },
    "canvas_id": {
      "type": "string",
      "description": "Canvas handle for the staged result. Present only when DataCanvas is configured and the result exceeded the inline budget; absent when DataCanvas is off, and absent when it is on but the result fit inline. Pass to oecd_dataframe_query or oecd_dataframe_describe."
    },
    "query_key": {
      "type": "string",
      "description": "Dimension key used in this query."
    },
    "row_count": {
      "type": "number",
      "description": "Total rows in the result (or on the canvas when truncated)."
    },
    "truncated": {
      "type": "boolean",
      "description": "True when rows is a preview slice and the full result was staged on DataCanvas; omitted entirely (never false) when rows holds the complete result. Use oecd_dataframe_query with the canvas_id for analytics over the full set. A complete rows never means a complete rendered table — content_table_capped reports that separately."
    },
    "table_name": {
      "type": "string",
      "description": "Canvas table name holding the full result — present when canvas_id is set. Inspect columns with oecd_dataframe_describe, then query this table with SQL using oecd_dataframe_query."
    },
    "query_flow_ref": {
      "type": "string",
      "description": "Flow reference used in this query."
    },
    "query_end_period": {
      "type": "string",
      "description": "End period filter applied in this query, if any."
    },
    "content_table_rows": {
      "type": "number",
      "description": "Rows the rendered table shows when content_table_capped is true."
    },
    "query_start_period": {
      "type": "string",
      "description": "Start period filter applied in this query, if any."
    },
    "content_table_capped": {
      "type": "boolean",
      "description": "True when the rendered table shows only the leading rows of the result. Distinct from truncated: nothing was staged anywhere, and structuredContent.rows still holds every row. To shrink the result itself, name fewer values per key segment or set a narrower start_period / end_period; to reach the full set as a queryable table instead, run with CANVAS_PROVIDER_TYPE=duckdb and follow up with oecd_dataframe_query."
    }
  },
  "additionalProperties": false
}
oecd_query_dataset annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true
}
oecd_dataframe_describe — Oecd Dataframe Describe
Advertised by the server during the last successful anonymous check.
Advertised read-only

List tables and columns staged on a DataCanvas by a prior oecd_query_dataset spill. Call this before oecd_dataframe_query to discover exact table and column names for SQL. Unavailable when the server runs with DataCanvas disabled.

oecd_dataframe_describe input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "canvas_id"
  ],
  "properties": {
    "canvas_id": {
      "type": "string",
      "pattern": "^[A-Za-z0-9_-]{10}$",
      "description": "Canvas ID returned by oecd_query_dataset — exactly 10 characters of letters, digits, hyphens, and underscores. Identifies the DataCanvas session holding the staged observation tables."
    }
  },
  "additionalProperties": false
}
oecd_dataframe_describe output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "canvas_id",
        "tables",
        "table_count"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "canvas_disabled",
                "canvas_not_found"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `canvas_disabled`: DataCanvas is not configured — CANVAS_PROVIDER_TYPE=none. `canvas_not_found`: The canvas_id has expired or was never created. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "tables": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "name",
          "kind",
          "row_count",
          "columns"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "description": "Object kind: \"table\" or \"view\"."
          },
          "name": {
            "type": "string",
            "description": "Table name — use in SQL FROM clauses."
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "name",
                "type"
              ],
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Column name."
                },
                "type": {
                  "type": "string",
                  "description": "DuckDB column type — e.g. VARCHAR, DOUBLE, BIGINT."
                }
              },
              "description": "A column in the table with its DuckDB type.",
              "additionalProperties": false
            },
            "description": "Columns in the table."
          },
          "row_count": {
            "type": "number",
            "description": "Number of rows in the table."
          }
        },
        "description": "A canvas table or view with row count and column schema.",
        "additionalProperties": false
      },
      "description": "Tables and views staged on this canvas."
    },
    "canvas_id": {
      "type": "string",
      "description": "The canvas ID whose tables are listed."
    },
    "table_count": {
      "type": "number",
      "description": "Total number of tables and views."
    }
  },
  "additionalProperties": false
}
oecd_dataframe_describe annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
oecd_dataframe_query — Oecd Dataframe Query
Advertised by the server during the last successful anonymous check.
Advertised read-only

Run a read-only SQL SELECT against OECD observation tables staged on a DataCanvas by oecd_query_dataset. Call oecd_dataframe_describe first to discover exact table and column names, then use this tool for aggregation, filtering, GROUP BY, JOIN, and window functions. Returns up to `limit` rows (default 100, at most 1,000 per call) and at most 1 MiB of row data; truncated: true marks a result with more rows than came back, and its notice says how to reach the rest. A query still running after 30 seconds is stopped. Unavailable when the server runs with DataCanvas disabled.

oecd_dataframe_query input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "canvas_id",
    "sql"
  ],
  "properties": {
    "sql": {
      "type": "string",
      "description": "Read-only SELECT statement. Reference tables by the names returned by oecd_dataframe_describe. Only SELECT statements are allowed — DDL, DML, and file-reading functions are rejected."
    },
    "limit": {
      "type": "integer",
      "default": 100,
      "maximum": 10000,
      "minimum": 1,
      "description": "Most rows to return. Default 100; served up to 1,000 per call, so a value from 1,001 to 10,000 returns at most 1,000 rows and a notice saying so. Fewer come back when the rows would pass 1 MiB of row data. For more rows than one call returns, aggregate in SQL or page with ORDER BY … LIMIT … OFFSET."
    },
    "canvas_id": {
      "type": "string",
      "pattern": "^[A-Za-z0-9_-]{10}$",
      "description": "Canvas ID returned by oecd_query_dataset — exactly 10 characters of letters, digits, hyphens, and underscores. Identifies the DataCanvas session holding the observation tables."
    }
  },
  "additionalProperties": false
}
oecd_dataframe_query output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "rows",
        "row_count",
        "column_names"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "rows": {
      "type": "array",
      "items": {
        "type": "object",
        "propertyNames": {
          "type": "string"
        },
        "additionalProperties": {}
      },
      "description": "Result rows in query order: at most limit rows (1,000 per call) and at most 1 MiB of row data. When truncated is true the result has more rows than these."
    },
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "canvas_disabled",
                "canvas_not_found",
                "table_not_found",
                "invalid_sql",
                "sql_execution_error",
                "query_timeout"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `canvas_disabled`: DataCanvas is not configured — CANVAS_PROVIDER_TYPE=none. `canvas_not_found`: The canvas_id has expired or was never created. `table_not_found`: The SQL names a table this canvas does not hold — it expired, was dropped, or the name is wrong. `invalid_sql`: The SQL is not a valid SELECT statement or contains disallowed operations. `sql_execution_error`: The SQL parsed and ran, then failed on the staged observation data — a conversion, an invalid input, or a value out of range. `query_timeout`: The query was still running after 30 seconds and was stopped. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "notice": {
      "type": "string",
      "description": "Present when a requested limit was above the per-call maximum (naming the limit requested and the one served), or when truncated is true (naming the ways to reach the rows not returned)."
    },
    "row_count": {
      "type": "number",
      "description": "Number of rows returned — the length of rows, never the size of the full result."
    },
    "truncated": {
      "type": "boolean",
      "description": "True when the result has more rows than this call returned — cut at limit or at the 1 MiB row-data budget; the notice says how to reach the rest. Omitted (never false) when rows is the complete result."
    },
    "column_names": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Column names in the result, in order."
    }
  },
  "additionalProperties": false
}
oecd_dataframe_query annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}

Prompts

0 advertised

No prompt definitions available.

Resources

1 advertised

oecd-guide

Advertised by the server during the last successful anonymous check.

Build SDMX keys, confirm which series an OECD dataflow actually carries, and read oecd_* results without mixing units, breakdowns, or country aggregates. Use when calling oecd_* tools for cross-country statistics (GDP, growth, unemployment, labour, education, tax), when a query returns no_results or invalid_key, or when a result spills to SQL.

oecd-guide URI
skill://oecd-guide/SKILL.md

MIME type: text/markdown

oecd-dataflow — oecd-dataflow

Advertised by the server during the last successful anonymous check.

Dimension metadata for a single OECD dataflow — same content as oecd_get_dataset_info. {flow_id} is the combined {dsd_id}@{df_id} string with @ percent-encoded as %40 in the URI, or the bare {df_id} for the few dataflows OECD publishes without a datastructure prefix. Example: oecd://dataflow/OECD.SDD.NAD/DSD_NAAG%40DF_NAAG_I

oecd-dataflow URI template
oecd://dataflow/{agency_id}/{flow_id}

MIME type: application/json

io.modelcontextprotocol/skills

Advertised by the server during the last successful anonymous check.

io.modelcontextprotocol/skills URI template
skill://{+path}

90-day uptime

A lightweight connection check about every six hours, sampled on hosts with many listings. It shows the server answered, not that its tools work.

Too few checks for a percentage yet (1 of 1 answered).

  1. 2026-11-07: 1 of 1 checks answered

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
622 ms
95th percentile latency
622 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 622 ms · metadata changed · 7 tool(s), 1 resource(s), 2 resource template(s), 0 prompt(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http oecd-mcp-server-caseyjhand https://oecd.caseyjhand.com/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add oecd-mcp-server-caseyjhand --url https://oecd.caseyjhand.com/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable oecd-mcp-server-caseyjhand in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "oecd-mcp-server-caseyjhand": {
      "url": "https://oecd.caseyjhand.com/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "oecd-mcp-server-caseyjhand": {
      "type": "streamableHttp",
      "url": "https://oecd.caseyjhand.com/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start oecd-mcp-server-caseyjhand and inspect its tools.
VS Code configuration
{
  "servers": {
    "oecd-mcp-server-caseyjhand": {
      "type": "http",
      "url": "https://oecd.caseyjhand.com/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http oecd-mcp-server-caseyjhand https://oecd.caseyjhand.com/mcp

Claude Desktop

Open Claude Settings > Connectors > Add custom connector, enter this server URL and enable it for the conversation. This is a manual remote-connector handoff, not a desktop JSON configuration.
Claude Desktop configuration
https://oecd.caseyjhand.com/mcp

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "oecd-mcp-server-caseyjhand": {
      "serverUrl": "https://oecd.caseyjhand.com/mcp"
    }
  }
}

Let your agent find its tools

Find servers like oecd-mcp-server from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.