---
summary: "crossref_search_journals and crossref_search_funders page both the name-search and works lists by offset; crossref_search_funders rejects ambiguous include_works targets instead of silently picking one; funder_doi accepts bare registry IDs"
breaking: true
security: false
---

# 0.3.0 — 2026-08-06

## Added

- **`crossref_search_journals` / `crossref_search_funders` paging** — both tools now page independently: `offset` pages the name-search list, `works_offset` pages the `include_works` list. `journalsTotal`/`fundersTotal` enrichment reports the full upstream match count; `nextOffset`/`nextWorksOffset` carry the input for the next page. A page stopped by a route's offset ceiling carries a `notice` naming the cap, the true total, and the escape hatch, rather than reading as the end of the list ([#33](https://github.com/cyanheads/crossref-mcp-server/issues/33)).
- **`offset_too_large` / `works_offset_too_large`** error reasons on both tools — the name-search ceiling (`NAME_SEARCH_OFFSET_CAP` = 100,000) and the works sub-resource ceiling (`WORKS_OFFSET_CAP` = 10,000) are enforced ahead of the upstream call, matching Crossref's own per-route limits ([#33](https://github.com/cyanheads/crossref-mcp-server/issues/33)).
- **`nextPageOffset()`** — exported from `crossref-service.ts`, classifies a page's continuation as `next` / `end` / `ceiling` (`PageContinuation`) rather than an offset-or-nothing, so a ceiling-truncated page can't collapse into an exhausted one ([#33](https://github.com/cyanheads/crossref-mcp-server/issues/33)).

## Changed

- **`ambiguous_journal` / `ambiguous_funder` recovery** — candidate identifiers (ISSN / registry ID) are now named in both the error message text and `error.data.candidates`, and the message states the full match total alongside the size of the listed page, so a content-only client isn't left needing an exploratory call ([#36](https://github.com/cyanheads/crossref-mcp-server/issues/36)).
- **`CrossrefService.searchJournals` / `searchFunders`** — return `{ totalResults, items }` instead of a bare array; `getJournalWorks` / `getFunderWorks` take a `{ rows, offset }` options object instead of a positional `rows` argument. `normalizeFunderId` is now exported.
- **Tool descriptions** — `crossref_search_journals` and `crossref_search_funders` no longer describe results in terms of upstream call count ("second call" / "second upstream call"); the `fundedWorks` output field's "paginated" claim is now backed by `works_offset` / `nextWorksOffset`; "first matched funder/journal" language is gone from both tools' output descriptions now that `include_works` resolves the matched record, not the first of several ([#35](https://github.com/cyanheads/crossref-mcp-server/issues/35)).

## Fixed

- **`ambiguous_funder`** — `crossref_search_funders` with `include_works: true` now throws when a name query matches more than one funder, instead of silently returning the first match's works with no attribution, mirroring the existing `crossref_search_journals` guard. The check is against the upstream match total, not the returned page length, so `rows: 1` or an offset landing on the tail of a list can't defeat it. **Breaking:** a call that previously succeeded by silently picking the first match now throws — pass `funder_doi` to disambiguate ([#36](https://github.com/cyanheads/crossref-mcp-server/issues/36)).
- **`funder_doi` validator** — accepts the bare Funder Registry ID (`100000001`) in addition to the full DOI (`10.13039/100000001`), matching what `GET /funders/{id}` itself resolves and what the field's description already documented ([#34](https://github.com/cyanheads/crossref-mcp-server/issues/34)).
- **Empty-page notices** — an `offset` landing past the end of a match list that did match now gets a distinct notice from a query that matched nothing, for both `crossref_search_journals` and `crossref_search_funders` — matching what `crossref_get_references` already did ([#33](https://github.com/cyanheads/crossref-mcp-server/issues/33)).
