Centralizes NCBI/Unpaywall failure modes in src/services/error-contracts.ts
with a recoveryFor() helper so service throws and tool ctx.fail emit the
same wire-level recovery hint. All 9 tools now declare the baseline
NCBI_SERVICE_ERRORS surface.
Tool changes:
- pubmed_convert_ids: PMC ID Converter 400 → typed validationError with
idType-specific format hints; drops the leaky upstream HTML body.
- pubmed_find_related: ELink <ERROR> folded into the empty-LinkSet
ESummary disambiguation path; drops the misclassified elink_error
contract entry.
- pubmed_fetch_fulltext: empty-result format() notice; declares
UNPAYWALL_SERVICE_ERRORS in addition to NCBI.
Service-layer:
- response-handler: notFound() short-circuit for permanent "no such
record" responses; HTML-rate-limit detection moved before XML validator.
- citation-formatter: Unicode-aware author initials (\p{L}).
Deps: @cyanheads/mcp-ts-core ^0.8.19 → ^0.8.20, @biomejs/biome ^2.4.14
→ ^2.4.15 (dev). Skills resynced: api-auth 1.1, api-config 1.4,
security-pass 1.4, tool-defs-analysis 1.1.
539 tests pass; bun run devcheck clean.