---
summary: "Pagination cursors bind to query identity, rejecting cross-query replay (#15, #20) and adding descending sort variants for itemized search (#10); mcp-ts-core ^0.11.0, TypeScript ^7, Socket supply-chain scanning"
breaking: false
security: false
---

# 0.4.14 — 2026-07-26

## Added

- **`.github/SECURITY.md` and `.github/FUNDING.yml`** — vulnerability disclosure policy and sponsorship links.
- **Socket supply-chain scanner** — `@socketsecurity/bun-security-scanner` wired into `bunfig.toml` as `install.security.scanner`, paired with a 3-day `minimumReleaseAge` guard on installed package versions (`@cyanheads/mcp-ts-core` excluded — framework releases adopt same-day).

## Changed

- **`decodeCursor` binds cursors to query identity** — the encoded payload now carries `{ scope, args }` (issuing tool name plus caller arguments minus `cursor`/`per_page`); replaying a cursor under a changed sort or filter is rejected as `cursor_query_mismatch`, naming the changed arguments, instead of OpenFEC silently ignoring the mismatched keyset keys and restarting at page one. Cursors minted before this release no longer decode — callers holding one across the upgrade get a clear `invalid_cursor` restart error rather than silent breakage. ([#20](https://github.com/cyanheads/openfec-mcp-server/issues/20))
- **Descending sort variants for itemized search** — `openfec_search_contributions`, `openfec_search_disbursements`, and `openfec_search_expenditures` accept a `-`-prefixed descending form of every existing `sort` value (e.g. `-contribution_receipt_amount`); `.describe()` on each field documents the prefix and OpenFEC's own default sort for that endpoint. ([#10](https://github.com/cyanheads/openfec-mcp-server/issues/10))
- **Docker build hardening** — build and production stages pin `oven/bun:1.3.14` (was floating `1`/`1-slim`), install steps add `--ignore-scripts`, and both stages use BuildKit cache mounts for Bun's install cache.
- **`package.json` author / `LICENSE` copyright** — attributed to Casey Hand.

## Fixed

- **`decodeCursor` rejects malformed cursors** — a non-base64, non-JSON, or wrong-shape `cursor` value now throws `validationError` (`reason: 'invalid_cursor'`) with a restart hint, instead of being merged into the outbound FEC request unchecked. ([#15](https://github.com/cyanheads/openfec-mcp-server/issues/15))
- **Numeric `last_indexes` values no longer rejected** — `FecSeekPagination.last_indexes` accepts `string | number` (Schedule E's `office_total_ytd` returns as a raw number); the new cursor shape guard was stringifying only string values and rejecting the rest as invalid.
- **`-office_total_ytd` no longer returns null rows first** — descending Schedule E sorts now pass `sort_nulls_last: true`, since OpenFEC orders nulls first on a plain descending sort and most rows carry a null `office_total_ytd`.

## Dependencies

- `@cyanheads/mcp-ts-core` ^0.10.9 → ^0.11.0
- `typescript` ^6.0.3 → ^7.0.2
- `@biomejs/biome` ^2.5.0 → ^2.5.5
- `@types/node` ^26.0.0 → ^26.1.1
- `ignore` ^7.0.5 → ^7.0.6
- `tsc-alias` ^1.8.17 → ^1.9.1
- `vitest` ^4.1.9 → ^4.1.10
- `@socketsecurity/bun-security-scanner` ^1.1.2 (new)
