# Reported issues for faostat-mcp-server

Pod holds 14 of 14 GitHub reports that passed its relevance review. This can include external user reports, maintainer-confirmed bugs, and concrete feature gaps. Treat them as evidence to inspect, not a count of distinct defects.

Back to [faostat-mcp-server](/mcp/faostat-mcp-server).

## Most discussed

### bug(faostat-mirror): synchronous cube reads stall every request, /healthz included, for their full duration

### Server version

0.2.2

### mcp-ts-core version

0.11.0

### Runtime

Bun

### Runtime version

Bun 1.3.x

### Transport

HTTP (Streamable HTTP)

### Description

Every cube read in `FaostatMirror` (`queryObservations`, `streamObservations`, `rankAreaTotals`, `sumByYear`, `domainDimensionCodes`) is a synchronous `bun:sqlite` / `better-sqlite3` call on the process's only JS thread. While one runs, `/healthz` and every other request wait for it. Ordinary tool calls still read 10⁴–10⁶ scattered…

[Read the thread](https://github.com/cyanheads/faostat-mcp-server/issues/3) · 2026-06-29 · closed · 5 comments

### bug(resolve_codes): under Node, a domain-scoped query match returns codes outside the domain

### Server version

0.2.4

### mcp-ts-core version

0.13.6

### Runtime

Node.js

### Runtime version

Node 26.5.0 (better-sqlite3, SQLite 3.53.4)

### Transport

stdio

### Description

`DimensionsStore.resolve` (`src/services/faostat-mirror/dimensions-store.ts`) scopes a `query` match to a domain with `<fts> MATCH ? AND rowid IN (<domain codes>)`. When the domain has a single code for the dimension, SQLite rewrites the IN list to `rowid = ?`. FTS5 claims that constraint and applies it through…

[Read the thread](https://github.com/cyanheads/faostat-mcp-server/issues/36) · 2026-09-30 · closed · 2 comments

### bug(commodity_profile): an unselected QCL is reported as a retryable index_not_ready

### Server version

0.2.4

### mcp-ts-core version

0.13.6

### Runtime

Bun

### Runtime version

Bun 1.4.2

### Transport

stdio

### Description

When QCL is not in `FAOSTAT_DOMAINS`, `faostat_commodity_profile` throws `index_not_ready`, the same reason it uses for a QCL mirror that hasn't finished its initial sync. That reason is declared `retryable` with the recovery "Wait for the initial sync to finish, or run the mirror init script, then retry shortly." A caller told to wait and retry…

[Read the thread](https://github.com/cyanheads/faostat-mcp-server/issues/37) · 2026-09-30 · closed · 1 comment

### bug(query_observations, commodity_profile): an unknown or expired canvas_id degrades to "staging failed" instead of canvas_not_found

### Server version

0.2.4

### mcp-ts-core version

0.13.6

### Runtime

Node.js

### Runtime version

Node 26.5.0

### Transport

stdio

### Description

When a caller passes `canvas_id` to `faostat_query_observations` or `faostat_commodity_profile`, `stageObservations` (`src/services/canvas-staging.ts`) acquires that canvas inside the same `try` whose `catch` turns any failure into a degraded, unstaged result. A well-formed id that is unknown or has expired makes the framework throw…

[Read the thread](https://github.com/cyanheads/faostat-mcp-server/issues/35) · 2026-09-30 · closed · 1 comment

### bug(faostat-mirror): multi-item observation reads walk the whole element slice instead of the item index

### Server version

0.2.4

### mcp-ts-core version

0.13.6

### Runtime

Bun

### Runtime version

Bun 1.4.2 (SQLite 3.54.0)

### Transport

stdio

### Description

`streamObservations` and `queryObservations` (`src/services/faostat-mirror/faostat-mirror.ts`) end in `ORDER BY year`. With several item codes plus an element filter, SQLite satisfies that ordering from `obs_<D>_element_code_year_idx`, then walks every row of the element slice and tests `item_code` per row. On QCL element 5510 that…

[Read the thread](https://github.com/cyanheads/faostat-mcp-server/issues/33) · 2026-09-30 · closed · 1 comment

### bug(commodity_profile): staged query_params record yearStart/yearEnd instead of the input names

### Server version

0.2.4

### mcp-ts-core version

0.13.6

### Runtime

Bun

### Runtime version

Bun 1.4.0

### Transport

stdio

### OS

macOS

### Description

`faostat_commodity_profile` records the staged table's provenance under internal filter names: its `query_params` read `{ item_query, item_codes, yearStart, yearEnd }` because the handler spreads its camelCase `yearRange` filter object into them. `faostat_query_observations` records the input names (`year_start`, `year_end`), and…

[Read the thread](https://github.com/cyanheads/faostat-mcp-server/issues/32) · 2026-09-30 · closed · 1 comment

### bug(commodity_profile): a failed canvas staging tells the caller to enable a canvas that is already on

### Server version

0.2.4

### mcp-ts-core version

0.13.6

### Runtime

Bun

### Runtime version

Bun 1.4.0

### Transport

stdio

### OS

macOS

### Description

Related: #1, #20

When the canvas is enabled but staging the merged set fails (`stageObservations` returns `undefined`, e.g. on a canvas capacity or DuckDB error), `faostat_commodity_profile` leaves `canvas_id` unset and `format()` falls through to its canvas-disabled branch (`commodity-profile.tool.ts`, the last `else` of the…

[Read the thread](https://github.com/cyanheads/faostat-mcp-server/issues/31) · 2026-09-30 · closed · 1 comment

### bug(canvas-staging): staged value column is typed from the preview rows, truncating later fractional values

### Server version

0.2.4

### mcp-ts-core version

0.13.6

### Runtime

Bun

### Runtime version

Bun 1.4.0

### Transport

stdio

### OS

macOS

### Description

Related: #15

`stageObservations()` (`src/services/canvas-staging.ts`) registers observation rows without a `schema`, so column types come from the framework sniffer over the preview window (the rows inlined before the spill, up to 100,000 characters). Only `value` depends on that window: all whole numbers types it `BIGINT`, all null…

[Read the thread](https://github.com/cyanheads/faostat-mcp-server/issues/30) · 2026-09-30 · closed · 1 comment

## Most recent

### bug(faostat-mirror): a single-area observation page reads and sorts every row of the area

### Server version

0.2.4

### mcp-ts-core version

0.13.6

### Runtime

Bun

### Runtime version

Bun 1.4.2 (SQLite 3.54.0)

### Transport

stdio

### Description

`faostat_query_observations` with a single `area_codes` entry and no item filter seeks `obs_<D>_area_code_idx`, then sorts every row of that area for `ORDER BY year` before the page returns. TCL area 231 has 101,823 rows scattered through a 4 GB file, so a 201-row page means 101,823 random table reads.

### Steps to reproduce

Call…

[Read the thread](https://github.com/cyanheads/faostat-mcp-server/issues/34) · 2026-09-30 · open · 0 comments

### bug(faostat-mirror): bulk-host fetches map every non-2xx to ServiceUnavailable, so a manifest 4xx is retried as an outage

### Server version

0.2.3

### mcp-ts-core version

0.13.6

### Runtime

Bun

### Runtime version

Bun 1.4.0

### Transport

stdio

### OS

macOS

### Description

`fetchManifest` (`src/services/faostat-mirror/manifest.ts:57`) and the per-domain ZIP download (`ingester.ts:216`) throw `serviceUnavailable(...)` for any `!response.ok`, so every status reads as an outage. The manifest fetch runs inside `withRetry` (`baseDelayMs: 1500`, 3 retries), so a permanent 4xx is retried through the full…

[Read the thread](https://github.com/cyanheads/faostat-mcp-server/issues/28) · 2026-09-19 · closed · 1 comment

### bug(query_observations, commodity_profile): Markdown table rows interpolate values without escaping

### Server version

0.2.3

### mcp-ts-core version

0.13.6

### Runtime

Bun

### Runtime version

Bun 1.4.0

### Transport

stdio

### OS

macOS

### Description

Related: #26

Two `format()` functions build Markdown table rows by interpolating mirror values with no escaping: `faostat_query_observations` (`query-observations.tool.ts:373`: area, item, element, unit, flag) and the production-trend table of `faostat_commodity_profile` (`commodity-profile.tool.ts:458`: unit, flags). A `|` splits…

[Read the thread](https://github.com/cyanheads/faostat-mcp-server/issues/27) · 2026-09-19 · closed · 1 comment

### bug(faostat_dataframe_query): Markdown table cells escape pipes but not backslashes

### Server version

0.2.3

### mcp-ts-core version

0.12.3

### Runtime

Bun

### Transport

Any

### Description

The `faostat_dataframe_query` table formatter (`dataframe-query.tool.ts`, string and serialized-object cells) escapes `|` as `\|` but leaves existing backslashes untouched. When the table renders, a backslash before ASCII punctuation is consumed as an escape, so the `content[]` text loses characters: `x\|y` renders as `x|y` and `a\*b` as `a*b`. `structuredContent` is unaffected.…

[Read the thread](https://github.com/cyanheads/faostat-mcp-server/issues/26) · 2026-09-16 · closed · 1 comment

### bug(query_observations): canvas_id description promises a fresh canvas per call, but omitting it reuses the session canvas

### Server version

0.2.3

### mcp-ts-core version

0.12.3

### Runtime

Bun

### Runtime version

Bun 1.4.0

### Transport

stdio

### Description

`faostat_query_observations`'s `canvas_id` field is described as: *"Canvas ID from a prior call to stage onto. Omit to start a fresh canvas (a new id is returned)."*

The second sentence is only true for the first spill of a session. After that, omitting `canvas_id` reuses the stored session canvas — every subsequent staged table lands on the same…

[Read the thread](https://github.com/cyanheads/faostat-mcp-server/issues/25) · 2026-08-25 · closed · 1 comment

### bug(faostat-mirror): ANALYZE runs on the serving thread — a cold domain's first data read stalls every request

### Server version

0.2.3

### mcp-ts-core version

0.12.3

### Runtime

Bun

### Runtime version

Bun 1.4.0

### Transport

stdio

### Description

`ANALYZE` still runs on the serving thread. #22 took it off the discovery path, but the first data read of a domain with no `sqlite_stat1` (`openAnalyzedDomain()` → `ensureQueryStatistics()`) still blocks every request for the full pass, which on TCL takes minutes. `runDomainSync()` → `refreshQueryStatistics()` also runs it in-process when a…

[Read the thread](https://github.com/cyanheads/faostat-mcp-server/issues/24) · 2026-08-25 · closed · 1 comment

The remaining reports are on [the project's issue tracker](https://github.com/cyanheads/faostat-mcp-server/issues).
