---
summary: "ctx.content collector for image/audio blocks (bytes ride content[] only, never structuredContent); SQL gate classifies SELECT-shaped prepare failures as invalid_sql with DuckDB binder detail; OTEL_SERVICE_NAME-seeding docs corrected"
breaking: false
security: false
---

# 0.10.8 — 2026-06-19

## Added

- **`ctx.content`** — always-present collector on `Context` for non-text content blocks (image/audio bytes the calling model should see or hear). `ctx.content.image(data, mimeType)` / `.audio(data, mimeType)` push the conventional base64 media blocks; `ctx.content(block)` is the raw escape hatch for embedded resources and resource links. Collected blocks are **prepended to `content[]` after `format()` runs and never enter `structuredContent`**, so a handler emits media without the base64 also duplicating into the typed output field — `content[]` orders as `[...collected blocks, ...format()/JSON output, ...enrichment trailer]`. Mirrors `ctx.enrich`: callable from the handler and the service layer, a no-op when never called (output byte-identical), and dropped on the error path. `ContentCollect` is exported from the package root; assert collected blocks with `getContentBlocks(ctx)` from `/testing`. ([#239](https://github.com/cyanheads/mcp-ts-core/issues/239))

## Changed

- **`OTEL_SERVICE_NAME` documentation** — corrected the default across `docs/telemetry/observability.md`, `skills/api-config`, and `skills/api-telemetry`: `createApp({ name })` seeds `OTEL_SERVICE_NAME` when unset (`??=`), so the precedence is env → `createApp` `name` → `package.json` `name`. The `CreateAppOptions.name` JSDoc now names the seeding side effect and the precedence asymmetry (`MCP_SERVER_NAME` is overridden; `OTEL_SERVICE_NAME` only seeded when unset). `skills/polish-docs-meta` notes that identity-pair adoption renames `service.name` to the machine name on first boot — expect a one-time series split in telemetry backends keyed on the old scoped label. No behavior change. ([#233](https://github.com/cyanheads/mcp-ts-core/issues/233))

## Fixed

- **Canvas SQL gate prepare-failure classification** — a `SELECT`-shaped statement (starts with `SELECT` or `WITH`) that parses but fails to prepare for a reason other than a missing table — a mistyped column, unknown function, invalid expression — now throws `ValidationError` with `data.reason: 'invalid_sql'` and preserves the DuckDB binder detail in `data.binderMessage` (path-sanitized against the export root). Previously these fell through to `non_select_statement`, where both the reason and message pointed away from the real problem and the offending column was never named. `non_select_statement` is now reserved for statements that genuinely aren't `SELECT`s. ([#236](https://github.com/cyanheads/mcp-ts-core/issues/236))
