---
summary: "Add openalex_get_citation_graph for one-hop citation traversal; polish analyze_trends (per_page, chronological year sort, broader recovery hint); redact polite-pool mailto from error messages."
breaking: false
security: true
---

# 0.6.11 — 2026-05-20

## Added

- **`openalex_get_citation_graph`** ([#13](https://github.com/cyanheads/openalex-mcp-server/issues/13)) — one-hop citation graph traversal from a seed work. `direction` picks the edge: `cites` (incoming citations), `cited_by` (the seed's reference list), or `related_to` (OpenAlex algorithmic related works). Wraps the underlying `cites`/`cited_by`/`related_to` filters so callers do not have to know their names. Accepts OpenAlex IDs, DOIs, PMIDs, PMCIDs as `seed_id`; non-W-IDs resolve via a singleton `/works/{id}` lookup because the citation filters reject anything other than a bare W-ID. Stacks with `filters`/`sort`/`select` to narrow the graph.
- **`per_page`** on `openalex_analyze_trends` ([#16](https://github.com/cyanheads/openalex-mcp-server/issues/16)) — caps groups per page (1-200, default 200). Useful when only the top-N groups are relevant.
- **Response metrics logging** ([#16](https://github.com/cyanheads/openalex-mcp-server/issues/16)) — service emits OpenAlex's per-request `cost_usd` and `db_response_time_ms` at debug level via `logResponseMetrics()`. Stays out of the wire shape; per-tool output schemas don't declare these fields.

## Changed

- **`openalex_analyze_trends` `format()`** ([#15](https://github.com/cyanheads/openalex-mcp-server/issues/15)) — time-series groupings (year or `YYYY-MM-DD` keys) now render in chronological order; non-time-series groupings keep upstream count-desc order. `structuredContent` stays in upstream order regardless.
- **`openalex_analyze_trends` `upstream_invalid_params` recovery hint** ([#18](https://github.com/cyanheads/openalex-mcp-server/issues/18)) — points at both `group_by` AND `filters`, and names concrete full-text filter keys (`abstract.search`, `title.search`, `default.search`) so callers stop reaching for the non-existent bare `search` filter. `filters` arg description carries the same idiom.
- **`renderEntityRecord`** extracted from `search-entities.tool.ts` into `src/mcp-server/tools/render-entity-record.ts` so `openalex_get_citation_graph` shares the same markdown formatter.
- **`normalizeId`** now exported from `openalex-service.ts` for the citation-graph seed pre-trim.

## Fixed

- **`throwNormalizedRequestError`** falls back to upstream `error` when `message` is missing and handles non-JSON 4xx bodies without dropping classification.

## Security

- **Polite-pool `mailto` redaction** — strip operator-injected query params from URLs before they surface to MCP clients via thrown error text. Framework fetch errors format messages as `Fetch failed for <URL>. Status: …`, and the URL carries the polite-pool `mailto` (and any future internal additions). New `src/services/openalex/url-redaction.ts` runs an allowlist over caller-controlled params (`q`, `search`, `filter`, `sort`, `select`, `per_page`, `cursor`, `group_by`, `sample`, `seed`) so a future internal param won't silently leak.

## Maintenance

- `@types/node` `^25.8.0 → ^25.9.1`, `tsx` `^4.22.0 → ^4.22.3`, `vitest` `^4.1.6 → ^4.1.7` (devDeps).
