protogrid

Search / io.github.cyanheads/faostat-mcp-server

faostat-mcp-server

R0· no sign-in

UN FAOSTAT global food & agriculture statistics over a local SQLite mirror, via MCP.

v0.4.0 · active · repository · descriptor JSON · versions

An agent can connect right now, no human step.Remote endpoint, no authentication, reachable on the last probe.
Quality86good
Trust94of 100
Uptime, 30 days100%
Latency p50187 ms

Connect

8 clients · secrets stay placeholders
{
  "mcpServers": {
    "faostat-mcp-server": {
      "type": "http",
      "url": "https://faostat.caseyjhand.com/mcp"
    }
  }
}
claude mcp add --transport http faostat-mcp-server https://faostat.caseyjhand.com/mcp
[mcp_servers.faostat-mcp-server]
url = "https://faostat.caseyjhand.com/mcp"
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "faostat-mcp-server": {
      "type": "remote",
      "url": "https://faostat.caseyjhand.com/mcp",
      "enabled": true
    }
  }
}
{
  "mcpServers": {
    "faostat-mcp-server": {
      "type": "http",
      "url": "https://faostat.caseyjhand.com/mcp"
    }
  },
  "deeplink": "cursor://anysphere.cursor-deeplink/mcp/install?name=faostat-mcp-server&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vZmFvc3RhdC5jYXNleWpoYW5kLmNvbS9tY3AifQ%3D%3D"
}
{
  "servers": {
    "faostat-mcp-server": {
      "type": "http",
      "url": "https://faostat.caseyjhand.com/mcp"
    }
  }
}
{
  "mcpServers": {
    "faostat-mcp-server": {
      "httpUrl": "https://faostat.caseyjhand.com/mcp"
    }
  }
}
extensions:
  "faostat-mcp-server":
    enabled: true
    name: "faostat-mcp-server"
    type: streamable_http
    uri: "https://faostat.caseyjhand.com/mcp"
    timeout: 300

Quality 86 / 100good

protocol88 · weight 25
  • pass
    protocol.modernsupports 2026-07-28 (server/discover)
  • pass
    protocol.statelessanswers without a session
  • pass
    protocol.transportstreamable HTTP
  • warn
    protocol.list_ttltools/list declares ttlMs 0, so clients re-fetch it on every use
authorizationn/a · weight 15
  • n/a
    auth.prm, auth.as_metadata, auth.cimdno remote uses OAuth
  • n/a
    auth.secret_in_urlno templated URL
tool hygiene79 · weight 30
  • pass
    tools.descriptionsevery tool has a description
  • warn
    tools.description_length2 tools have descriptions over 1,024 characters, which crowds the context
  • pass
    tools.schemasevery tool has an object input schema
  • pass
    tools.annotations6 of 6 tools declare readOnlyHint or destructiveHint
  • fail
    tools.directory_hintsno tool declares all four of readOnlyHint, destructiveHint, idempotentHint and openWorldHint; missing: faostat_list_domains (destructiveHint); faostat_dataframe_describe (destructiveHint); faostat_resolve_codes (destructiveHint); …
  • pass
    tools.token_costabout 3,615 tokens to load every tool
  • pass
    tools.api_dumptools are not a one-to-one API dump
stability100 · weight 15
  • pass
    stability.changes5 tool changes in 30 days
  • pass
    stability.rug_pullno tool changed its meaning under the same name
dependenciesn/a · weight 15

6 tools, about 3,615 tokens to load them all · tool set 99c530d8770f · tools last changed 2026-10-18 · checked 2026-10-20 13:17 UTC

Tool changes

  • faostat_commodity_profilechangeddescription, input schema, output schema
    before

    Assemble a global profile for one commodity in a single call: top-producing countries, the annual production trend, and trade flows (top exporters and importers). Accepts a commodity name, resolves it to item codes, then queries the production (QCL) and trade (TCL) domains and merges the results. Each ranking is a per-country sum across the resolved items, taken at that country's own latest year with data and grouped by unit so incomparable quantities are never added. The trend is returned inline as year/value points. Country-level only (aggregates excluded). The production domain (QCL) is required. When the trade domain (TCL) is not indexed locally, returns a production-only profile with a notice naming the gap rather than failing. When the merged observation set is too large to inline, it spills to a DataCanvas table (canvas_id + table_name) — call faostat_dataframe_describe for its columns, then faostat_dataframe_query for deeper SQL.

    after · 59% of words in common

    Assemble a global profile for one QCL item in a single call: top-producing countries, the annual production trend, and trade flows (top exporters and importers). Supply item_code or item_query; code wins when both are supplied. A query selects a unique normalized exact label, otherwise a unique relevance match; ambiguous queries require an explicit code. Each ranking uses the selected item at each country's own latest year with data, grouped by unit. The trend is returned inline as year/value points. Country-level only (aggregates excluded). QCL is required; unavailable TCL yields a production-only profile with a notice. When the merged observation set is too large to inline, it spills to a DataCanvas table (canvas_id + table_name) — call faostat_dataframe_describe for its columns, then faostat_dataframe_query for deeper SQL.

  • faostat_dataframe_querychangedinput schema
  • faostat_commodity_profilechangeddescription, output schema
    before

    Assemble a global profile for one commodity in a single call: top-producing countries, the annual production trend, and trade flows (top exporters and importers). Accepts a commodity name, resolves it to item codes, then queries the production (QCL) and trade (TCL) domains and merges the results. Each ranking is a per-country sum across the resolved items, taken at that country's own latest year with data and grouped by unit so incomparable quantities are never added. The trend is returned inline as year/value points. Country-level only (aggregates excluded). When a required domain is not indexed locally, returns a partial profile with a notice naming the gap rather than failing. The full merged observation set spills to a DataCanvas table for deeper SQL via faostat_dataframe_query.

    after · 91% of words in common

    Assemble a global profile for one commodity in a single call: top-producing countries, the annual production trend, and trade flows (top exporters and importers). Accepts a commodity name, resolves it to item codes, then queries the production (QCL) and trade (TCL) domains and merges the results. Each ranking is a per-country sum across the resolved items, taken at that country's own latest year with data and grouped by unit so incomparable quantities are never added. The trend is returned inline as year/value points. Country-level only (aggregates excluded). The production domain (QCL) is required. When the trade domain (TCL) is not indexed locally, returns a production-only profile with a notice naming the gap rather than failing. When the merged observation set is too large to inline, it spills to a DataCanvas table (canvas_id + table_name) — call faostat_dataframe_describe for its columns, then faostat_dataframe_query for deeper SQL.

  • faostat_query_observationschangeddescription, output schema
    before

    Query a FAOSTAT domain's data cube by area(s), item(s), element(s), and year range, returning observations (area, item, element, year, value, unit, and the data-quality flag). Resolve codes first with faostat_resolve_codes — the cube is unqueryable without them. Aggregate regions (World, continents, economic groupings) are EXCLUDED by default so a naive SUM does not double-count a region with its member countries; set include_aggregates=true to get the regional roll-ups, or pass explicit area_codes to query exactly what you name. Small result sets return inline; large ones spill to a DataCanvas table (returned canvas_id + table_name) for GROUP BY / ranking / time-series analysis via faostat_dataframe_query. Every row carries its 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 — so honor it, treat any unrecognized flag as informational, and never assume an estimated, imputed, or unrecognized value is official.

    after · 96% of words in common

    Query a FAOSTAT domain's data cube by area(s), item(s), element(s), and year range, returning observations (area, item, element, year, value, unit, and the data-quality flag). Resolve codes first with faostat_resolve_codes — the cube is unqueryable without them. Aggregate regions (World, continents, economic groupings) are EXCLUDED by default so a naive SUM does not double-count a region with its member countries; set include_aggregates=true to get the regional roll-ups, or pass explicit area_codes to query exactly what you name. Small result sets return inline; large ones spill to a DataCanvas table (returned canvas_id + table_name) — call faostat_dataframe_describe for its columns, then faostat_dataframe_query for GROUP BY / ranking / time-series analysis. Every row carries its 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 — so honor it, treat any unrecognized flag as informational, and never assume an estimated, imputed, or unrecognized value is official.

  • faostat_resolve_codeschangedoutput schema

Full history: list_changes · trend: quality JSON.

Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed. How it is computed.

Trust 94 / 100

provenance80
liveness100
freshness100
hygiene100

+repository +namespace-matches-repo +reachable +uptime-100% +updated-2d-ago

Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed. How it is computed.

Dependencies

@cyanheads/[email protected] npmthis version is not known to the dependency resolver

@cyanheads/[email protected] npmthis version is not known to the dependency resolver

Dependency graphs from deps.dev; advisories from OSV.dev, including the GitHub Advisory Database and the PyPI Advisory Database; all CC BY 4.0. The graph is what a clean install of this version resolves today; nothing was installed or run. How it is checked.

Endpoints

remoteauthreachableuptime 30dp50protocollast ok
https://faostat.caseyjhand.com/mcp streamable-httpnoneyes100%187 ms2026-07-282026-10-20
packageregistryversionruntimesecrets
@cyanheads/faostat-mcp-servernpm0.4.0npx
@cyanheads/faostat-mcp-servernpm0.4.0npx

Tools (6)

faostat_commodity_profileread-onlyAssemble a global profile for one QCL item in a single call: top-producing countries, the annual production trend, and trade flows (top exporters and importers). Supply item_code or item_query; code wins when both are supplied. A query selects a unique normalized exact label, otherwise a unique relevance match; ambiguous queries require an explicit code. Each ranking uses the selected item at each country's own latest year with data, grouped by unit. The trend is returned inline as year/value points. Country-level only (aggregates excluded). QCL is required; unavailable TCL yields a production-only profile with a notice. When the merged observation set is too large to inline, it spills to a DataCanvas table (canvas_id + table_name) — call faostat_dataframe_describe for its columns, then faostat_dataframe_query for deeper SQL.
faostat_dataframe_describeread-onlyList the canvas tables (faostat_xxxxxxxx) staged by faostat_query_observations and faostat_commodity_profile, each with its source tool, the query parameters that produced it, creation/expiry timestamps, row count, and column schema. Call this before faostat_dataframe_query to discover the exact table and column names to reference in SQL. Tables are listed newest-first and paged: pass `name` to describe one table outright, or page with `offset` + `limit` — when the response reports `truncated`, pass the returned `nextOffset` to fetch the rest.
faostat_dataframe_queryread-onlyRun a single-statement SELECT against the canvas tables staged by faostat_query_observations and faostat_commodity_profile (table names look like faostat_xxxxxxxx). Use this for cross-country and cross-item aggregation, GROUP BY rankings, joins, and time-series analysis over the full result set the inline preview only sampled. Standard DuckDB SQL — joins, aggregates, window functions, CTEs all work. Read-only: writes, DDL, DROP, COPY, PRAGMA, ATTACH, and external-file table functions are rejected; system catalogs (information_schema, sqlite_master, duckdb_*) are denied — list staged tables via faostat_dataframe_describe. Every row carries its 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 — keep it in projections, treat any unrecognized flag as informational, and never assume it is official.
faostat_list_domainsread-onlyDiscover FAOSTAT statistical domains (production, trade, food balances, food security, land use, agri-emissions, prices, value) with their codes, descriptions, last-update date, upstream row count, and local index status. Every query keys on a domain code from here. The `indexed` flag tells you which domains are queryable right now; un-indexed domains exist in the catalog but must be added to FAOSTAT_DOMAINS and re-synced before faostat_query_observations can read them. The catalog runs to ~69 domains with long descriptions, so responses are paged: narrow with `topic` / `indexed_only`, pass `code` to fetch one domain outright, or page with `offset` + `limit` — when the response reports `truncated`, pass the returned `nextOffset` to fetch the rest.
faostat_query_observationsread-onlyQuery a FAOSTAT domain's data cube by area(s), item(s), element(s), and year range, returning observations (area, item, element, year, value, unit, and the data-quality flag). Resolve codes first with faostat_resolve_codes — the cube is unqueryable without them. Aggregate regions (World, continents, economic groupings) are EXCLUDED by default so a naive SUM does not double-count a region with its member countries; set include_aggregates=true to get the regional roll-ups, or pass explicit area_codes to query exactly what you name. Small result sets return inline; large ones spill to a DataCanvas table (returned canvas_id + table_name) — call faostat_dataframe_describe for its columns, then faostat_dataframe_query for GROUP BY / ranking / time-series analysis. Every row carries its 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 — so honor it, treat any unrecognized flag as informational, and never assume an estimated, imputed, or unrecognized value is official.
faostat_resolve_codesread-onlyResolve human terms to the opaque integer codes faostat_query_observations needs, within a dimension: areas (countries/regions), items (commodities), or elements (metrics like production, yield, import quantity). Pass `query` for fuzzy full-text matching ("maize" → item 56), `name_contains` for a substring filter, or `code` for an exact-code lookup; omit all three to list the whole dimension. Item and element results are scoped to the requested domain — only codes present in that domain's cube are returned, so a resolved code is always queryable there (areas are shared across domains). Page large listings with `offset` + `limit`: when the response reports `truncated`, pass the returned `nextOffset` to fetch the next page. Every area match is flagged `country` or `aggregate` — aggregates (World, continents, economic groupings — codes ≥ 5000 plus a few curated sub-threshold roll-ups such as China=351, which sums mainland + Taiwan + Hong Kong + Macao) double-count if summed with their member countries, so resolve before querying and exclude aggregates unless you want the regional roll-up.

Schemas: list_tools.

Similar MCP servers

More from io.github.cyanheads

And 140 more from this publisher.

Official server.json
{
  "name": "io.github.cyanheads/faostat-mcp-server",
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
  "remotes": [
    {
      "url": "https://faostat.caseyjhand.com/mcp",
      "type": "streamable-http"
    }
  ],
  "version": "0.4.0",
  "packages": [
    {
      "version": "0.4.0",
      "transport": {
        "type": "stdio"
      },
      "identifier": "@cyanheads/faostat-mcp-server",
      "runtimeHint": "npx",
      "registryType": "npm",
      "registryBaseUrl": "https://registry.npmjs.org",
      "environmentVariables": [
        {
          "name": "FAOSTAT_DOMAINS",
          "format": "string",
          "default": "QCL,TCL,FBS,FS,RL,GLE,RFN,QV",
          "description": "Comma-separated FAOSTAT domain codes to index into the local mirror."
        },
        {
          "name": "FAOSTAT_MIRROR_PATH",
          "format": "string",
          "default": "./.faostat-mirror",
          "description": "Directory holding the per-domain SQLite mirror databases and the shared dimension database."
        },
        {
          "name": "FAOSTAT_BULK_BASE_URL",
          "format": "string",
          "default": "https://bulks-faostat.fao.org/production",
          "description": "FAOSTAT bulk-download service base URL (manifest + per-domain ZIPs)."
        },
        {
          "name": "CANVAS_PROVIDER_TYPE",
          "format": "string",
          "default": "duckdb",
          "description": "Set to 'duckdb' to enable the DataCanvas SQL surface (default), or 'none' to disable analytical staging."
        },
        {
          "name": "FAOSTAT_DATAFRAME_DROP_ENABLED",
          "format": "boolean",
          "default": "false",
          "description": "Set to 'true' to make faostat_dataframe_drop callable, so a staged table can be dropped before its 2-hour TTL. Off by default: the tool is registered disabled."
        },
        {
          "name": "MCP_LOG_LEVEL",
          "format": "string",
          "default": "info",
          "description": "Sets the minimum log level for output (e.g., 'debug', 'info', 'warn')."
        }
      ]
    },
    {
      "version": "0.4.0",
      "transport": {
        "url": "http://localhost:3010/mcp",
        "type": "streamable-http"
      },
      "identifier": "@cyanheads/faostat-mcp-server",
      "runtimeHint": "npx",
      "registryType": "npm",
      "registryBaseUrl": "https://registry.npmjs.org",
      "environmentVariables": [
        {
          "name": "MCP_TRANSPORT_TYPE",
          "value": "http",
          "format": "string",
          "description": "Selects the HTTP transport."
        },
        {
          "name": "MCP_HTTP_HOST",
          "format": "string",
          "default": "127.0.0.1",
          "description": "The hostname for the HTTP server."
        },
        {
          "name": "MCP_HTTP_PORT",
          "format": "string",
          "default": "3010",
          "description": "The port to run the HTTP server on."
        },
        {
          "name": "MCP_HTTP_ENDPOINT_PATH",
          "format": "string",
          "default": "/mcp",
          "description": "The endpoint path for the MCP server."
        },
        {
          "name": "MCP_AUTH_MODE",
          "format": "string",
          "default": "none",
          "description": "Authentication mode to use: 'none', 'jwt', or 'oauth'."
        },
        {
          "name": "FAOSTAT_DOMAINS",
          "format": "string",
          "default": "QCL,TCL,FBS,FS,RL,GLE,RFN,QV",
          "description": "Comma-separated FAOSTAT domain codes to index into the local mirror."
        },
        {
          "name": "FAOSTAT_MIRROR_PATH",
          "format": "string",
          "default": "./.faostat-mirror",
          "description": "Directory holding the per-domain SQLite mirror databases and the shared dimension database."
        },
        {
          "name": "FAOSTAT_BULK_BASE_URL",
          "format": "string",
          "default": "https://bulks-faostat.fao.org/production",
          "description": "FAOSTAT bulk-download service base URL (manifest + per-domain ZIPs)."
        },
        {
          "name": "FAOSTAT_REFRESH_CRON",
          "format": "string",
          "description": "Cron expression for the in-process incremental mirror refresh (HTTP transport only). Omit to disable."
        },
        {
          "name": "CANVAS_PROVIDER_TYPE",
          "format": "string",
          "default": "duckdb",
          "description": "Set to 'duckdb' to enable the DataCanvas SQL surface (default), or 'none' to disable analytical staging."
        },
        {
          "name": "FAOSTAT_DATAFRAME_DROP_ENABLED",
          "format": "boolean",
          "default": "false",
          "description": "Set to 'true' to make faostat_dataframe_drop callable, so a staged table can be dropped before its 2-hour TTL. Off by default: the tool is registered disabled."
        },
        {
          "name": "MCP_LOG_LEVEL",
          "format": "string",
          "default": "info",
          "description": "Sets the minimum log level for output (e.g., 'debug', 'info', 'warn')."
        }
      ]
    }
  ],
  "repository": {
    "url": "https://github.com/cyanheads/faostat-mcp-server",
    "source": "github"
  },
  "description": "UN FAOSTAT global food & agriculture statistics over a local SQLite mirror, via MCP."
}