Skip to main content
Glama

faostat-mcp-server: query observations

faostat_query_observations
Read-only

Query a FAOSTAT domain's data cube by area(s), item(s), element(s), sources, and year range, returning values with units and data-quality flags. Resolve numeric codes or exact alphanumeric item identities with faostat_resolve_codes; element resolution accepts item selectors and returns units. Empty queries with explicit items and elements list available elements for those items across the domain, without establishing area/year/source coverage. Aggregate regions are excluded by default; include_aggregates=true returns roll-ups, and explicit area_codes are honored verbatim. Item groups can overlap their members even with matching units; they remain included, and kind=null does not establish safe-to-sum. Keep source methodologies separate. Small results return inline; large ones spill to a DataCanvas table (canvas_id + table_name); call faostat_dataframe_describe for columns, then faostat_dataframe_query for analysis. Honor every row's flag: commonly A=Official, B=time-series break, E=Estimated, I=Imputed, M=Missing, T=Unofficial, X=international organization; unrecognized flags never establish official status.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "domain": "<domain>"
    },
    "name": "faostat_query_observations"
  }
}

Input Schema

NameRequiredDescriptionDefault
limitNoMax observations returned inline — also the preview size when the result stages to a canvas table. Rows past it are never dropped silently: a match larger than limit stages in full to a DataCanvas table (canvas_id + table_name), and when no table is staged the notice reports how many matched so you can raise limit or narrow the filters. Max 1000.
domainYesFAOSTAT domain code (e.g. "QCL"). Must be indexed locally.
year_endNoInclusive end year (e.g. 2022).
canvas_idNoCanvas ID to stage onto, as returned by a prior faostat_query_observations / faostat_commodity_profile call — exactly 10 characters of letters, digits, hyphens, and underscores. Omit to stage onto this session’s canvas, created on the first spill and reused by every later call, so tables staged earlier in the session sit alongside this one.
area_codesNoArea codes from faostat_resolve_codes. When set, aggregates are NOT auto-excluded — the codes are honored verbatim.
item_codesNoItem codes from faostat_resolve_codes.
year_startNoInclusive start year (e.g. 2000).
source_codesNoExact source codes, such as 3050 or 3051 in GLE. Omit to return every methodology; choose or group sources before summing.
element_codesNoElement codes from faostat_resolve_codes (e.g. 5510 Production).
item_codes_textNoExact alphanumeric item identities from resolver code_text; mutually exclusive with item_codes. Numeric codes use item_codes.
include_aggregatesNoWhen false (default), exclude aggregate-region rows (codes ≥ 5000 plus a few curated sub-threshold roll-ups such as China=351) so sums are not double-counted. Set true for World/continent/grouping roll-ups. Ignored when explicit area_codes are passed.

Output Schema

NameRequiredDescriptionDefault
errorNoPresent when the call failed. Absent on success.
domainNoThe domain code echoed back.
noticeNoGuidance on empty results, aggregate exclusion, or how to reach the spilled set.
spilledNoTrue when the full result was staged on a DataCanvas table.
canvas_idNoCanvas ID holding the staged table (present when spilled) — pass it with table_name to faostat_dataframe_describe for the columns and types, then to faostat_dataframe_query for SQL.
truncatedNoTrue when the staged table hit the 50,000-row staging cap — the staged set is a PREFIX of the match, not the complete result. Partition the query by year or code ranges to capture the rest.
table_nameNoCanvas table holding the staged result set (present when spilled; a PREFIX of the match when truncated) — pass it as name to faostat_dataframe_describe, then reference it in faostat_dataframe_query SQL.
totalCountNoObservations matched. Exact when the result was returned inline or fully staged. A floor — more matched — in two cases, both named by the notice: the match exceeded the 50,000-row staging cap (truncated is then true), or staging failed and the response fell back to an inline page.
observationsNoInline observations (preview when the full set spilled to a canvas table).
staged_row_countNoRows actually staged on the canvas table (present when spilled). Equals the full match count unless truncated, in which case it is the 50,000-row cap.
available_elementsNoOn an empty query with explicit items and elements: all elements available for those items across the domain. Does not establish coverage for requested area/year/source filters.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed13 schema fields changed
    • addedInput schema / properties / item_codes_text
      Added value: +{
      +  "description": "Exact alphanumeric item identities from resolver code_text; mutually exclusive with item_codes. Numeric codes use item_codes.",
      +  "items": {
      +    "description": "Exact alphanumeric item code.",
      +    "pattern": "^\\d+[A-Za-z][A-Za-z0-9]*$",
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedInput schema / properties / source_codes
      Added value: +{
      +  "description": "Exact source codes, such as 3050 or 3051 in GLE. Omit to return every methodology; choose or group sources before summing.",
      +  "items": {
      +    "maximum": 9007199254740991,
      +    "minimum": -9007199254740991,
      +    "type": "integer"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / available_elements
      Added value: +{
      +  "description": "On an empty query with explicit items and elements: all elements available for those items across the domain. Does not establish coverage for requested area/year/source filters.",
      +  "items": {
      +    "additionalProperties": false,
      +    "description": "An element observed for the selected items.",
      +    "properties": {
      +      "code": {
      +        "description": "Element code available for the selected items.",
      +        "type": "number"
      +      },
      +      "name": {
      +        "description": "Element label.",
      +        "type": "string"
      +      },
      +      "units": {
      +        "description": "Distinct specified units for these items in this domain.",
      +        "items": {
      +          "description": "Observed unit.",
      +          "type": "string"
      +        },
      +        "type": "array"
      +      }
      +    },
      +    "required": [
      +      "code",
      +      "name",
      +      "units"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `domain_not_indexed`: The domain is not in the local mirror selection (FAOSTAT_DOMAINS) — whether a valid FAOSTAT code or not. `index_not_ready`: The domain mirror is cold — its initial sync has never completed. `canvas_disabled`: The result is too large to inline but DataCanvas is off, so it cannot be staged for SQL. `canvas_not_found`: The result is large enough to stage and canvas_id does not resolve to a live canvas — unknown, expired, or owned by another tenant. A result that fits inline stages nothing and never consults canvas_id. `invalid_year_range`: year_start is greater than year_end — a self-contradictory range that can never match. `query_timeout`: The call's mirror reads — time queued behind other calls plus execution — ran past the 45-second per-call ceiling. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `conflicting_item_selectors`: Both numeric item_codes and exact item_codes_text are supplied. `domain_not_indexed`: The domain is not in the local mirror selection (FAOSTAT_DOMAINS) — whether a valid FAOSTAT code or not. `index_not_ready`: The domain mirror requires an initial sync or an ingest upgrade. `canvas_disabled`: The result is too large to inline but DataCanvas is off, so it cannot be staged for SQL. `canvas_not_found`: The result is large enough to stage and canvas_id does not resolve to a live canvas — unknown, expired, or owned by another tenant. A result that fits inline stages nothing and never consults canvas_id. `invalid_year_range`: year_start is greater than year_end — a self-contradictory range that can never match. `query_timeout`: The call's mirror reads — time queued behind other calls plus execution — ran past the 45-second per-call ceiling. Other values are possible when a failure originates below the handler."
    • changedOutput schema / properties / error / properties / data / properties / reason / examples
      Previous value: -[
      -  "domain_not_indexed",
      -  "index_not_ready",
      -  "canvas_disabled",
      -  "canvas_not_found",
      -  "invalid_year_range",
      -  "query_timeout"
      -]New value: +[
      +  "conflicting_item_selectors",
      +  "domain_not_indexed",
      +  "index_not_ready",
      +  "canvas_disabled",
      +  "canvas_not_found",
      +  "invalid_year_range",
      +  "query_timeout"
      +]
    • changedOutput schema / properties / observations / items / properties / item_code / description
      Previous value: -"Item code."New value: +"Numeric item code; null for alphanumeric identities."
    • changedOutput schema / properties / observations / items / properties / item_code / type
      Previous value: -"number"New value: +[
      +  "number",
      +  "null"
      +]
    • addedOutput schema / properties / observations / items / properties / item_code_text
      Added value: +{
      +  "description": "Exact alphanumeric item code; null for numeric identities.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / observations / items / properties / period
      Added value: +{
      +  "description": "Original multi-year period label; null for annual rows. Year is the integer midpoint.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / observations / items / properties / source
      Added value: +{
      +  "description": "Source methodology label; null when absent.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / observations / items / properties / source_code
      Added value: +{
      +  "description": "Source methodology code; null when the domain has none.",
      +  "type": [
      +    "number",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / observations / items / properties / value_qualifier
      Added value: +{
      +  "description": "Bound operator such as <; value is a bound rather than an exact observation when present.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • changedOutput schema / properties / observations / items / required
      Previous value: -[
      -  "area_code",
      -  "area",
      -  "item_code",
      -  "item",
      -  "element_code",
      -  "element",
      -  "year",
      -  "value",
      -  "unit",
      -  "flag"
      -]New value: +[
      +  "area_code",
      +  "area",
      +  "item_code",
      +  "item_code_text",
      +  "period",
      +  "value_qualifier",
      +  "source_code",
      +  "source",
      +  "item",
      +  "element_code",
      +  "element",
      +  "year",
      +  "value",
      +  "unit",
      +  "flag"
      +]
  2. Changed4 schema fields changed
    • changedOutput schema / properties / canvas_id / description
      Previous value: -"Canvas ID holding the staged result — pass to faostat_dataframe_query / _describe."New value: +"Canvas ID holding the staged table (present when spilled) — pass it with table_name to faostat_dataframe_describe for the columns and types, then to faostat_dataframe_query for SQL."
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `domain_not_indexed`: The domain is not in the local mirror selection (FAOSTAT_DOMAINS) — whether a valid FAOSTAT code or not. `index_not_ready`: The domain mirror is cold — its initial sync has never completed. `canvas_disabled`: The result is too large to inline but DataCanvas is off, so it cannot be staged for SQL. `invalid_year_range`: year_start is greater than year_end — a self-contradictory range that can never match. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `domain_not_indexed`: The domain is not in the local mirror selection (FAOSTAT_DOMAINS) — whether a valid FAOSTAT code or not. `index_not_ready`: The domain mirror is cold — its initial sync has never completed. `canvas_disabled`: The result is too large to inline but DataCanvas is off, so it cannot be staged for SQL. `canvas_not_found`: The result is large enough to stage and canvas_id does not resolve to a live canvas — unknown, expired, or owned by another tenant. A result that fits inline stages nothing and never consults canvas_id. `invalid_year_range`: year_start is greater than year_end — a self-contradictory range that can never match. `query_timeout`: The call's mirror reads — time queued behind other calls plus execution — ran past the 45-second per-call ceiling. Other values are possible when a failure originates below the handler."
    • changedOutput schema / properties / error / properties / data / properties / reason / examples
      Previous value: -[
      -  "domain_not_indexed",
      -  "index_not_ready",
      -  "canvas_disabled",
      -  "invalid_year_range"
      -]New value: +[
      +  "domain_not_indexed",
      +  "index_not_ready",
      +  "canvas_disabled",
      +  "canvas_not_found",
      +  "invalid_year_range",
      +  "query_timeout"
      +]
    • changedOutput schema / properties / table_name / description
      Previous value: -"Canvas table name holding the full result set (present when spilled)."New value: +"Canvas table holding the staged result set (present when spilled; a PREFIX of the match when truncated) — pass it as name to faostat_dataframe_describe, then reference it in faostat_dataframe_query SQL."
  3. Changed8 schema fields changed
    • changedInput schema / properties / canvas_id / description
      Previous value: -"Canvas ID from a prior call to stage onto. Omit to start a fresh canvas (a new id is returned)."New value: +"Canvas ID to stage onto, as returned by a prior faostat_query_observations / faostat_commodity_profile call — exactly 10 characters of letters, digits, hyphens, and underscores. Omit to stage onto this session’s canvas, created on the first spill and reused by every later call, so tables staged earlier in the session sit alongside this one."
    • addedInput schema / properties / canvas_id / pattern
      Added value: +"^[A-Za-z0-9_-]{10}$"
    • removedOutput schema / properties / observations / items / properties / flag / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / observations / items / properties / flag / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / observations / items / properties / unit / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / observations / items / properties / unit / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / observations / items / properties / value / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / observations / items / properties / value / type
      Added value: +[
      +  "number",
      +  "null"
      +]
  4. Changed6 schema fields changed
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedInput schema / additionalProperties
      Added value: +false
    • changedOutput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedOutput schema / anyOf
      Added value: +[
      +  {
      +    "not": {
      +      "required": [
      +        "error"
      +      ]
      +    },
      +    "required": [
      +      "domain",
      +      "observations",
      +      "spilled",
      +      "truncated",
      +      "totalCount"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • addedOutput schema / properties / error
      Added value: +{
      +  "additionalProperties": {},
      +  "description": "Present when the call failed. Absent on success.",
      +  "properties": {
      +    "code": {
      +      "description": "JSON-RPC error code for this failure.",
      +      "maximum": 9007199254740991,
      +      "minimum": -9007199254740991,
      +      "type": "integer"
      +    },
      +    "data": {
      +      "additionalProperties": {},
      +      "properties": {
      +        "reason": {
      +          "description": "Machine-readable failure mode. Declared by this tool: `domain_not_indexed`: The domain is not in the local mirror selection (FAOSTAT_DOMAINS) — whether a valid FAOSTAT code or not. `index_not_ready`: The domain mirror is cold — its initial sync has never completed. `canvas_disabled`: The result is too large to inline but DataCanvas is off, so it cannot be staged for SQL. `invalid_year_range`: year_start is greater than year_end — a self-contradictory range that can never match. Other values are possible when a failure originates below the handler.",
      +          "examples": [
      +            "domain_not_indexed",
      +            "index_not_ready",
      +            "canvas_disabled",
      +            "invalid_year_range"
      +          ],
      +          "type": "string"
      +        },
      +        "recovery": {
      +          "additionalProperties": {},
      +          "description": "Actionable next step for the caller.",
      +          "properties": {
      +            "hint": {
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "hint"
      +          ],
      +          "type": "object"
      +        },
      +        "retryable": {
      +          "description": "Whether retrying may succeed.",
      +          "type": "boolean"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "message": {
      +      "description": "Human-readable description of what went wrong.",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "code",
      +    "message"
      +  ],
      +  "type": "object"
      +}
    • removedOutput schema / required
      Removed value: -[
      -  "domain",
      -  "observations",
      -  "spilled",
      -  "truncated",
      -  "totalCount"
      -]
  5. Changed2 schema fields changed
    • changedInput schema / properties / limit / description
      Previous value: -"Max observations returned inline when the result does not spill. Max 1000."New value: +"Max observations returned inline — also the preview size when the result stages to a canvas table. Rows past it are never dropped silently: a match larger than limit stages in full to a DataCanvas table (canvas_id + table_name), and when no table is staged the notice reports how many matched so you can raise limit or narrow the filters. Max 1000."
    • changedOutput schema / properties / totalCount / description
      Previous value: -"Observations matched. Exact when the result was returned inline or fully staged; when the match set exceeded the 50,000-row staging cap this is that cap — a floor, not the exact count (truncated is then true)."New value: +"Observations matched. Exact when the result was returned inline or fully staged. A floor — more matched — in two cases, both named by the notice: the match exceeded the 50,000-row staging cap (truncated is then true), or staging failed and the response fell back to an inline page."
  6. Changed2 schema fields changed
    • changedInput schema / properties / include_aggregates / description
      Previous value: -"When false (default), exclude aggregate-region rows (codes ≥ 5000) so sums are not double-counted. Set true for World/continent/grouping roll-ups. Ignored when explicit area_codes are passed."New value: +"When false (default), exclude aggregate-region rows (codes ≥ 5000 plus a few curated sub-threshold roll-ups such as China=351) so sums are not double-counted. Set true for World/continent/grouping roll-ups. Ignored when explicit area_codes are passed."
    • changedOutput schema / properties / observations / items / properties / flag / description
      Previous value: -"Data-quality flag (A=Official, E=Estimated, I=Imputed, B=break, X=external); null when unflagged."New value: +"Data-quality flag — commonly A=Official, B=time-series break, E=Estimated, I=Imputed, M=Missing (value cannot exist), T=Unofficial, X=from an international organization, plus others FAOSTAT defines per domain; treat any unrecognized flag as informational, never assume official. Null when unflagged."
  7. Changed1 schema field changed
    • changedOutput schema / properties / totalCount / description
      Previous value: -"Total observations matched before any inline cap."New value: +"Observations matched. Exact when the result was returned inline or fully staged; when the match set exceeded the 50,000-row staging cap this is that cap — a floor, not the exact count (truncated is then true)."
  8. Changed3 schema fields changed
    • addedOutput schema / properties / staged_row_count
      Added value: +{
      +  "description": "Rows actually staged on the canvas table (present when spilled). Equals the full match count unless truncated, in which case it is the 50,000-row cap.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / truncated
      Added value: +{
      +  "description": "True when the staged table hit the 50,000-row staging cap — the staged set is a PREFIX of the match, not the complete result. Partition the query by year or code ranges to capture the rest.",
      +  "type": "boolean"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "domain",
      -  "observations",
      -  "spilled",
      -  "totalCount"
      -]New value: +[
      +  "domain",
      +  "observations",
      +  "spilled",
      +  "truncated",
      +  "totalCount"
      +]
  9. First observed

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare readOnly/openWorld=false, but the description adds substantial behavior beyond them: aggregate regions excluded by default unless include_aggregates=true, explicit area_codes honored verbatim, overlapping item groups and kind=null not establishing safe-to-sum, source methodologies must be kept separate before summing, and unrecognized flags never establishing official status. It also discloses the inline-vs-canvas spill threshold behavior, which is exactly the kind of operational trait an agent needs.

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

Conciseness4/5

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

Front-loaded with purpose, then workflow guidance, then behavioral caveats, and every clause carries signal. It is dense with semicolons and slightly long, and the canvas spill mechanics duplicate what the limit and canvas_id schema descriptions already say, so it is not maximally tight.

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

Completeness5/5

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

For an 11-parameter analytic tool with an output schema, the description covers the missing pieces an agent cannot infer: prerequisite resolution, aggregate default behavior, the spill-to-canvas handoff workflow, and data-quality flag interpretation. The output schema handles return shape, so nothing material is left unstated.

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

Parameters4/5

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

Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema: element resolution accepts item selectors and returns units, item_codes_text must be exact alphanumeric identities and is mutually exclusive with item_codes, and source_codes omission returns every methodology (with a warning to separate before summing). Year range and include_aggregates interaction are also clarified, though limit/canvas_id details largely restate the schema.

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

Purpose5/5

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

States a specific verb and resource ('Query a FAOSTAT domain's data cube') and enumerates the filter axes and return payload (values with units and data-quality flags). It also names the sibling resolvers it depends on, so an agent can distinguish it from faostat_resolve_codes and the dataframe tools without opening schemas.

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

Usage Guidelines5/5

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

Gives explicit routing guidance: resolve codes or alphanumeric item identities with faostat_resolve_codes, and after a canvas spill call faostat_dataframe_describe for columns then faostat_dataframe_query for analysis. It also explains the empty-query semantics (pass items and elements to list available elements) and when to set include_aggregates, so the agent knows both when to use it and how to vary the call.

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.