# Reported issues for bls-mcp-server

Pod holds 23 of 72 problems reported by people outside the maintainer team. Issues filed by the project's own owners, members and collaborators are excluded entirely — a maintainer's release checklist is not a warning to a prospective user.

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

## Most discussed

### bug(bls_get_series): one unknown SeriesID discards the whole batch's data

## Summary

`parseSeriesResponse` currently throws as soon as any upstream message says a series does not exist or has no data. BLS can return those per-series advisories with `REQUEST_SUCCEEDED` and usable observations for other requested IDs, so one unresolved ID discards the rest of a successful batch.

## Reproduction

```json
{"name":"bls_get_series","arguments":{"series_ids":["LNS14000000","LNS99999999"],"start_year":2025,"end_year":2025}}
```

BLS returns observations for `LNS14000000` an

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/59) · 2026-08-02 · open · 4 comments

### chore(canvas): remove vestigial dataframe truncation metadata

### Use case

`bls_get_series` and `bls_dataframe_describe` advertise dataframe-materialization truncation metadata that this server never produces. `CanvasBridge.registerDataframe()` sends every supplied row to the framework's `registerTable()`, and its only production caller supplies neither a row cap nor a truncation flag. The exposed fields therefore add permanent `false`/absent values to two tool contracts without describing a real outcome.

Related: #46

### Proposed behavior

Remove the u

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/54) · 2026-07-17 · closed · 4 comments

### bug(bls_list_surveys): AP and CW capability flags deny calculations the API returns

### Server version

0.4.2

### mcp-ts-core version

0.9.21

### Runtime

Bun (hosted)

### Runtime version

n/a — black-box via claude.ai connector

### Transport

http (Streamable HTTP)

### Description

`bls_list_surveys` reports `allowsNetChange: false, allowsPercentChange: false` for **AP** (Average Price Data) and **CW** (CPI-W), but `bls_get_series` with `calculations: true` returns calculations for both. The flags — and the `bls_get_series` guidance to "check `bls_list_surveys` first" — a

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/39) · 2026-06-08 · closed · 3 comments

### feat(bls_get_series): add request_echo and spill notice to structuredContent output

`bls_get_series` is the highest-value tool in this server — it fetches time-series data for the agent's chosen series. When results look wrong (unexpected year range, missing series data, wrong number of observations), there is no structured signal in `structuredContent` confirming what the server actually requested from the BLS API. Agents can only re-read the input schema and retry blind.

## Status

Partial. Shipped in 0.2.3: `bls_get_series` got an `enrichment` block (`totalObservations`, `n

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/30) · 2026-05-29 · closed · 3 comments

### feat(responses): surface query echo and filter echo in structuredContent output

Three tools — `bls_search_series`, `bls_list_surveys`, and `bls_get_latest` — return results with no structured record of what parameters were actually applied. When an agent gets fewer results than expected, it has no way to confirm via `structuredContent` whether its filters were interpreted as intended (e.g., was `survey: 'ce'` treated as `CE`? was the `category` filter active?). Without parameter echo, the only debugging path is re-reading the input schema and retrying blind.

## Status

Par

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

### bug(bls_get_series): BLS missing-value sentinel "-" passed through undeclared — breaks float parsing and canvas SQL

## Summary

BLS uses the literal string `-` when an observation is unavailable or suppressed. `bls_get_series` and `bls_get_latest` currently expose that value as if it were numeric, count it without qualification, and write it to DataCanvas as text that fails ordinary numeric casts.

## Reproduction

```json
{"name":"bls_get_series","arguments":{"series_ids":["LNS14000000"],"start_year":2025,"end_year":2025}}
```

The October 2025 row has `value: "-"` and a lapse-in-appropriations footnote. The

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/58) · 2026-08-02 · open · 2 comments

### bug(bls-api-service): an invalid BLS_API_KEY is reported as quota_exceeded

### Server version

0.4.9

### mcp-ts-core version

0.10.14

### Runtime

Bun

### Runtime version

Bun 1.3.x

### Transport

stdio

### Description

BLS returns `status: "REQUEST_NOT_PROCESSED"` for at least two distinct causes: a key that has exhausted its 500/day quota, and a key the API rejects as invalid. `parseSeriesResponse` (`src/services/bls-api/bls-api-service.ts`) attributes the status to quota unconditionally:

```ts
if (parsed.status === 'REQUEST_NOT_PROCESSED') {
  throw serviceUna

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/56) · 2026-07-17 · closed · 2 comments

### bug(responses): get_latest double-lists failed series; dataframe_query notice cites wrong cap param

### Server version

0.4.2

### mcp-ts-core version

0.9.21

### Runtime

Bun (hosted)

### Runtime version

n/a — black-box via claude.ai connector

### Transport

http (Streamable HTTP)

### Description

Two minor output-shape papercuts found while field-testing.

### Steps to reproduce

1. `bls_get_latest({ series_ids: ["LNS14000000", "BOGUS999"] })`
2. `bls_dataframe_query({ sql: "<a 20-row SELECT>", preview: 3 })` (`row_limit` defaults to 1000)

### Actual behavior

1. **`bls_get_latest` dou

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/42) · 2026-06-08 · closed · 2 comments

## Most recent

### bug(bls_dataframe_drop): provider failures erase metadata and report success

### Server version

0.5.1

### mcp-ts-core version

^0.12.3

### Runtime

Bun 1.4.0

### Transport

DataCanvas service path

### Description

`CanvasBridge.drop()` deletes dataframe metadata before attempting the physical drop, then returns `true` when the provider operation throws. The caller is told the dataframe was dropped even though the table may still exist and its recovery metadata is gone.

### Steps to reproduce

1. Register a dataframe so its metadata exists in tenant state.
2. Make `

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/74) · 2026-08-31 · open · 0 comments

### bug(bls-observations): partial routing violates request-order and missing-series contracts

### Server version

0.5.1

### mcp-ts-core version

^0.12.3

### Runtime

Bun 1.4.0

### Transport

Observation-mirror routing

### Description

Partial observation-mirror routing can reorder `bls_get_series.series[]`, despite the output schema declaring request order. With live fallback disabled, a missed SeriesID is also omitted from `series[]`, contradicting the declared zero-observation entry contract.

Related: #25, #45

### Steps to reproduce

1. Configure a ready mirror that contains rows

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/73) · 2026-08-31 · open · 0 comments

### bug(bls-observations): sync subprocess never initializes the mirror service

### Server version

0.5.1

### mcp-ts-core version

^0.12.3

### Runtime

Node.js 26.5.0

### Transport

Direct observation-mirror worker invocation

### Description

The documented observation-mirror init and scheduled refresh worker exits before syncing because the child entry calls `getBlsObservationsService()` without initializing the service.

Related: #26

### Steps to reproduce

1. Run `bun run rebuild`.
2. Set `BLS_OBSERVATIONS_MIRROR_ENABLED=true` and a writable `BLS_OBSERVATIONS_MIRROR

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/72) · 2026-08-31 · open · 0 comments

### bug(bls_dataframe_query): registered schemas report every column as VARCHAR

### Server version

0.5.1

### mcp-ts-core version

^0.12.3

### Runtime

Bun 1.4.0

### Transport

HTTP (Streamable HTTP), `CANVAS_PROVIDER_TYPE=duckdb`

### Description

`bls_dataframe_describe` reports every table registered by `bls_dataframe_query` as `VARCHAR`, regardless of the DuckDB result types. A client following the documented describe-before-query workflow receives a false schema for numeric and boolean expressions.

### Steps to reproduce

1. Materialize any `bls_get_series` spill t

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/71) · 2026-08-31 · open · 0 comments

### bug(bls_search_series): blank filters execute unfiltered searches

### Server version

0.5.1

### mcp-ts-core version

^0.12.3

### Runtime

Bun 1.4.0

### Transport

HTTP (Streamable HTTP)

### Description

`bls_search_series` accepts blank `survey` and `area` filters, echoes them as applied, and silently executes an unfiltered search. This makes malformed input look like a successful filtered query.

Related: #18, #64

### Steps to reproduce

1. Call `bls_search_series` with `{"query":"employment","survey":""}`.
2. Observe a successful broad result (`totalCou

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/70) · 2026-08-31 · open · 0 comments

### bug(bls_search_series): area filtering after the FTS cap returns false-empty results

### Server version

0.5.1

### mcp-ts-core version

^0.12.3

### Runtime

Bun 1.4.0

### Transport

HTTP (Streamable HTTP)

### Description

`bls_search_series` applies `area` only after the FTS candidate query has already been capped at 1,000 rows. Broad national terms can fill that pool before any local series is considered, so a valid geographic workflow returns a false empty result.

Related: #7, #62

### Steps to reproduce

1. Call `bls_search_series` with `{"query":"unemployment rate","are

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/69) · 2026-08-31 · open · 0 comments

### feat(bls_get_series): spill response names only bls_dataframe_query — canvas column names unreachable

### Use case

When `bls_get_series` spills, the inline preview is not the canvas schema: it uses camelCase fields, while the dataframe contains snake_case columns and additional fields. A spill response that directs callers straight to `bls_dataframe_query` makes them guess the SQL columns.

Related: #66

### Proposed behavior

For an enabled canvas, every spill discovery surface must give the same two-step workflow: call `bls_dataframe_describe` with `dataset.name` to inspect `column_schema`, t

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

### bug(mirror): observation queries use limit 1,000,000 and fail the framework's mirror query bounds

## Validation result

The reported framework failure no longer exists on the server's pinned `@cyanheads/mcp-ts-core` 0.12.3.

The issue was filed while SQLite mirror stores applied a default query ceiling of 1,000 rows. `@cyanheads/mcp-ts-core` 0.11.3 changed mirror-store ceilings to opt-in: when `limits.limit` is omitted, any positive safe integer is accepted. `bls-labor-mcp-server` does not declare a limit ceiling, so both existing `limit: 1_000_000` calls pass current framework validation.

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

### feat(canvas): hide dataframe tools when DataCanvas is disabled

### Use case

On a deployment with `CANVAS_PROVIDER_TYPE=none` (the framework default), `bls_dataframe_describe` and `bls_dataframe_query` are advertised through `tools/list` even though the initialized canvas bridge is unavailable and both handlers return `canvas_unavailable`. `bls_dataframe_drop` has the same problem if `BLS_DATAFRAME_DROP_ENABLED=true` while canvas remains disabled.

The advertised server instructions also describe large results as spilling to a DataCanvas dataframe, although

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

### bug(bls_list_surveys): category map covers 36 of 70 surveys — CW, SU, EN, LE and 30 others unreachable

### Server version

0.4.11

### mcp-ts-core version

0.10.14

### Runtime

Bun

### Runtime version

1.3.14

### Transport

HTTP (Streamable HTTP)

### OS

macOS 25.1.0

### Description

`CATEGORY_MAP` in `bls-list-surveys.tool.ts` covers 36 of the 70 surveys the BLS `/surveys` endpoint returns. The other 34 are unreachable through any `category` value, and the omissions include the headline members of the categories that do exist — so a caller who filters by category concludes those surveys don

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/65) · 2026-08-02 · open · 0 comments

### bug(bls_search_series): survey filter dead-ends on un-indexed surveys; description advertises OE, which is off by default

### Server version

0.4.11

### mcp-ts-core version

0.10.14

### Runtime

Bun

### Runtime version

1.3.14

### Transport

HTTP (Streamable HTTP)

### OS

macOS 25.1.0

### Description

`bls_search_series` accepts any two-letter survey code, but the offline catalog indexes only 12 of the 70 surveys `bls_list_surveys` returns. Filtering on one of the other 58 yields an empty result whose notice blames the query, sending the caller to reword something that can never match.

The tool description m

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/64) · 2026-08-02 · open · 0 comments

### bug(bls-catalog): JOLTS, ECEC and productivity series all share one title — search cannot distinguish them

### Server version

0.4.11

### mcp-ts-core version

0.10.14

### Runtime

Bun

### Runtime version

1.3.14

### Transport

HTTP (Streamable HTTP)

### OS

macOS 25.1.0

### Description

For three indexed surveys, every catalog entry carries the identical synthesized title, so `bls_search_series` cannot distinguish one series from another within them:

| Survey | Series indexed | Distinct titles | Title on every row |
|:---|---:|---:|:---|
| JT — JOLTS | 2,060 | 1 | `JOLTS - Job Openings and Lab

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/63) · 2026-08-02 · open · 0 comments

### feat(bls_search_series): add offset paging — results past the 50-row limit are unreachable

`bls_search_series` returns at most 50 results with no way to reach the rest. `limit` is capped at 50 and there is no `offset` or `cursor`, so a query whose enrichment reports `totalCount: 1002` exposes 50 series and permanently hides the remainder. It is the anchor tool for resolving concepts to SeriesIDs, so a caller that cannot find the right series in the first page has no move except rewording the query.

The truncation is reported honestly — `truncated: true`, `shown`, `cap`, and a notice 

[Read the thread](https://github.com/cyanheads/bls-labor-mcp-server/issues/62) · 2026-08-02 · open · 0 comments

### bug(bls_get_latest): BLS "Invalid Series" reported as "series may exist but has no data"

## Summary

BLS reports malformed IDs as `Invalid Series for Series <id>`. The parser recognizes only `does not exist`, so `bls_get_latest` misreports malformed IDs as a possibly valid series with no current observation.

## Reproduction

```json
{"name":"bls_get_latest","arguments":{"series_ids":["BOGUS123"]}}
```

The upstream response is `REQUEST_SUCCEEDED` with an empty series block and the message `Invalid Series for Series BOGUS123`.

## Required behavior

- Classify `Invalid Series for Se

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

### bug(bls-api-service): declared recovery hints never reach the client for service-raised errors

## Summary

The tools declare recovery guidance for service-raised errors, but several `BlsApiService` throw sites omit `ctx.recoveryFor(reason)`. Those failures therefore lack `structuredContent.error.data.recovery.hint` and the formatted `Recovery:` line.

## Required behavior

- Every service throw whose reason is declared by the calling tool spreads `ctx.recoveryFor(reason)` into its error data.
- Cover the data paths for `quota_exceeded`, `series_locked`, `series_not_found`, `no_data_for_pe

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

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