# Reported issues for doiget

Pod holds 20 of 45 problems reported by people outside the maintainer team. Issues filed by the project's own owners, members and collaborators are excluded entirely — a maintainer's release checklist is not a warning to a prospective user.

Back to [doiget](/mcp/doiget).

## Most discussed

### Discovery-oriented features for agent-driven literature search (paper_search, paper_text, survey macro, MCP loop)

## Motivation — agent-driven research-question *discovery*, not just DOI→PDF

Using doiget from an LLM agent to actually *find the question* (not just fetch a known DOI), the
loop I want to self-complete is:

> **search → triage → expand(citations) → fetch → read → map/gap-analysis**

Today doiget is excellent at the back half (`fetch`/`batch`/`graph`/`bib`/`csl`/`serve`/`capabilities`),
but the front half assumes you already know the DOIs. The gaps below are what would let an agent run
the whol

[Read the thread](https://github.com/QAtlasHub/doiget/issues/281) · 2026-06-04 · closed · 3 comments

### mcp: align tool output shapes with the CLI --mode json bodies (#204 / #205 mirror)

## Purpose

#204 added `--mode json` bodies for the six human-table CLI commands and #205 added the ERRORS.md §3 JSONL shape for `batch`. The `doiget-mcp` tools (`doiget_info`, `doiget_search`, `doiget_audit_log`, `doiget_batch_fetch`, etc.) each have their own output schema today; they predate the CLI JSON bodies and may diverge in field names / nesting from the CLI surface.

Consistency matters because a single LLM agent often consults *both* (`doiget serve` for in-session work and `doiget cli

[Read the thread](https://github.com/QAtlasHub/doiget/issues/212) · 2026-05-20 · closed · 3 comments

### bug(cli): the human denial help suggests both trust flags unconditionally, while the machine path computes which one actually covers the host

Observed on `doiget 0.8.9` against the #443/#461 case:

```
$ doiget fetch 10.1109/tsp.2018.2812747
error[CAPABILITY_DENIED]: … redirect target strathprints.strath.ac.uk not in allowlist …
  = help: that host is not on the allowlist yet; widen it in …/config.toml
          [network] trust_academic_repos = true   # 15 curated academic suffixes
          [network] trust_oa_registries  = true   # DOAJ, SciELO, Zenodo, OSF, HAL
          [[network.additional_hosts]] host = "strathprints.strath.ac.uk

[Read the thread](https://github.com/QAtlasHub/doiget/issues/478) · 2026-08-25 · closed · 2 comments

### test: an end-to-end use-case suite driven through the real entry points, because every "unreachable source" bug passed its unit tests

Four bugs this cycle share one shape: a source was implemented, gated, allowlisted and unit-tested,
and did not work.

| | found by | passed its unit tests |
|---|---|---|
| #413 | five Tier-2 sources never called | yes |
| #442 | three Tier-3 sources never called | yes |
| #454 | Tier-3 allowlists never registered in the client | yes |
| #458 | Tier-3 chain skipped whenever Crossref answers | yes |

In every case the unit test drove the `Source` impl directly, or asserted that a builder returne

[Read the thread](https://github.com/QAtlasHub/doiget/issues/462) · 2026-08-24 · open · 2 comments

### oa-publisher allowlist omits major physics OA hosts (APS, SciPost, IOP) — 7/30 niche papers fall to metadata-only

## Summary

Dogfooding a real **finite-temperature MPS** literature collection on a
university box (via the now-working citation graph, #187) batch-fetched 30
DOIs that OpenAlex reports as Open Access. **24 succeeded; 7 were denied**
with `error[CAPABILITY_DENIED]` — the OA PDF *was discovered* but its host
is not in `oa_publisher_allowlist()`
(`crates/doiget-core/src/http.rs`) / `docs/REDIRECT_ALLOWLIST.md` §3.4.

Denied hosts (real Unpaywall `best_oa_location` targets):

| host | count | natur

[Read the thread](https://github.com/QAtlasHub/doiget/issues/193) · 2026-05-18 · closed · 2 comments

### cleanup batch (LOW): s2 dead api_key, dry_run .expect() panics, missing serde(deny_unknown_fields), SCOPE.md count mismatch

**Category: F/D — low-severity cleanup batch** (grouped like #123)

1. **core** `crates/doiget-core/src/sources/s2.rs:52-53` — `api_key` is `#[allow(dead_code)]`, never sent. Users with a Semantic Scholar key are silently rate-limited to the anonymous tier. Wire the header like APS, or document + warn.
2. **core** `crates/doiget-core/src/dry_run.rs:143,163` — `.expect()` on allowlist lookups panics `doiget plan` if a source key is ever renamed. Convert to `Result<FetchPlan, FetchError>`.
3. **mc

[Read the thread](https://github.com/QAtlasHub/doiget/issues/156) · 2026-05-17 · closed · 2 comments

### Four shipped MCP tools have no entry in MCP_TOOLS.md

Four tools ship in every release binary and have no entry in `docs/MCP_TOOLS.md`:

- `doiget_annotate`
- `doiget_batch_from_bibliography`
- `doiget_paper_tex_source`
- `doiget_tag`

## How this was measured

`doiget serve` run from an installed npm package, `tools/list` compared against the
tool table in `MCP_TOOLS.md` (the rows matching `^| \`doiget_[a-z_]+\``):

```
live in a shipped oa-only,citation build : 21   (22 after #552)
documented in the tool table             : 18
explicitly refused,

[Read the thread](https://github.com/QAtlasHub/doiget/issues/553) · 2026-08-27 · closed · 1 comment

### `doiget_paper_search` answers an over-long query with `{ok: true, total_results: 0}`, which an agent reads as "no such paper exists"

## Observed

`doiget 0.8.9`, MCP path. Eleven `doiget_paper_search` calls in one session returned
`{"ok": true, "count": 0, "total_results": 0}`. A shorter query for the **same target** then
returned it on the first try:

```
"lithium refractoriness after discontinuation kindling sensitization course of illness Post"
  → total_results: 0

"lithium discontinuation-induced refractoriness preliminary observations"
  → total_results: 1
     Post RM, Leverich GS, Altshuler L, Mikalauskas K.
     Am J

[Read the thread](https://github.com/QAtlasHub/doiget/issues/534) · 2026-08-26 · open · 1 comment

## Most recent

### bug(mcp): after #517 `oa_url` is effectively always null on the DOI path, while MCP_TOOLS.md still advertises it as the field to act on

Consequence of #517 / ADR-0052, filed rather than folded into that PR because it is a contract question rather than part of the fix.

## What #517 established

Crossref `message.link[]` is **programme-scoped**. Measured on 12 live entries across six publishers and eight captured fixtures: every entry is `text-mining`, `similarity-checking` or `syndication`, and **none** is `unspecified`. So `extract_crossref_publisher_url` — correctly — returns `None` for all of them.

## What that does to `oa_u

[Read the thread](https://github.com/QAtlasHub/doiget/issues/539) · 2026-08-26 · open · 0 comments

### A 0.5 token-overlap near-miss and a 1.0 exact match come back in the same shape, so #372's "let the calling agent judge" leaves the agent nothing to judge with

## Two calls from one session

`doiget 0.8.9`, MCP. Same tool, same session, minutes apart.

**Exact match — correct, score 1.0:**

```
doiget_resolve_citation(
  "Coryell, Lithium discontinuation and subsequent effectiveness, American Journal of Psychiatry, 1998")
```
```json
{"doi": "10.1176/ajp.155.7.895", "score": 1,
 "title": "Lithium Discontinuation and Subsequent Effectiveness",
 "author": "Coryell, William", "year": 1998, "source": "crossref"}
```

**Near-miss — wrong paper, score 0.5:**

[Read the thread](https://github.com/QAtlasHub/doiget/issues/536) · 2026-08-26 · open · 0 comments

### `redirect_not_in_allowlist` adjudicates a resolver hop as if it were a content host, so a gold-OA cc-by paper is refused unless the user allowlists doi.org itself

## Reproduction

`doiget 0.8.9`, tier-1 only (`arxiv`, `crossref`, `unpaywall`; `tdm_enabled: false`).

Harada & Kato, *Psychiatry and Clinical Neurosciences Reports* (2024) — **cc-by, gold OA**:

```
doiget_fetch_paper(ref="10.1002/pcn5.205")
```

```json
{
  "ok": true,
  "license": "cc-by",
  "oa_status": "gold",
  "source": "unpaywall",
  "resolver_profile": "unpaywall",
  "size_bytes": 0,
  "pdf": {
    "status": "blocked",
    "code": "NETWORK_ERROR",
    "message": "network error: redirec

[Read the thread](https://github.com/QAtlasHub/doiget/issues/533) · 2026-08-26 · open · 0 comments

### bug(transport): in a `metadata`-without-`citation` build, every Tier-2 optional source fails UnknownSource

Found while wiring OpenAlex into the optional chain for #461. Not fixed there because it is a different defect with its own blast radius.

## The gates disagree

The Tier-2 sources are gated on `metadata`:

```toml
# crates/doiget-core/Cargo.toml
metadata = []
citation = ["metadata"]
```

`resolve_optional_chain` is `#[cfg(feature = "metadata")]`, and so are DataCite, Europe PMC, OpenAIRE, HAL and CORE.

Their **transport** gate is not:

```rust
// crates/doiget-cli/src/commands/fetch.rs:267
#[c

[Read the thread](https://github.com/QAtlasHub/doiget/issues/516) · 2026-08-26 · closed · 0 comments

### Ship doiget as a Claude Code plugin: self-hosted marketplace first, then the community catalog

Mechanics verified 2026-08-26 against the installed `claude-plugins-official` marketplace on disk and the official docs.

## Why this and not just `claude mcp add`

A plugin makes installation two lines with no binary handling, and it can carry skills, agents and commands alongside the MCP server — which is where domain workflows (systematic review / PRISMA, etc.) would eventually be delivered.

```
/plugin marketplace add QAtlasHub/doiget
/plugin install doiget@doiget
```

## Files to add

At t

[Read the thread](https://github.com/QAtlasHub/doiget/issues/513) · 2026-08-25 · open · 1 comment

### docs/INTEGRATION: all six host guides are Phase 3 placeholders that tell users to stop and wait — for a phase that shipped

A user who follows `README.md:51` to the host-integration guides is actively told not to proceed.

## Measured 2026-08-26

Every file in `docs/INTEGRATION/` carries the same banner and two unfilled TODOs:

```
claude-code.md         Status: PLACEHOLDER (Phase 3)   TODOs: 2
claude-desktop.md      Status: PLACEHOLDER (Phase 3)   TODOs: 2
cursor.md              Status: PLACEHOLDER (Phase 3)   TODOs: 2
codex.md               Status: PLACEHOLDER (Phase 3)   TODOs: 2
obsidian.md            Status: PLA

[Read the thread](https://github.com/QAtlasHub/doiget/issues/512) · 2026-08-25 · closed · 0 comments

### Publish doiget to npm so the MCP entry is one line — optionalDependencies, no postinstall, Trusted Publishing

The concrete build-out of #501's priority-1 channel. Registration mechanics verified 2026-08-26.

## Target

```
claude mcp add doiget -- npx -y doiget serve
```

No binary handling, no C toolchain, no PATH edit. This is also the prerequisite for the Claude Code plugin route (sibling issue), whose `.mcp.json` is exactly `{"command":"npx","args":["-y","doiget@latest","serve"]}` — the same shape the official `firebase` plugin ships.

## What exists to package

The workspace produces **one** binary

[Read the thread](https://github.com/QAtlasHub/doiget/issues/511) · 2026-08-25 · closed · 0 comments

### The MCP envelope says what happened but not what to do next, so an agent's only retry signal is the error code's name

The retry decision an agent has to make is currently encoded in a markdown table that the agent never reads.

## What already exists

This is not missing thinking — it is missing plumbing. `docs/ERRORS.md` §2 carries a **"Recoverable?"** column with per-code guidance, and it is good: `INVALID_REF` → "No (user must correct input)", `RATE_LIMITED` → "Retry after `Retry-After`", `NOT_IMPLEMENTED` → "**do not retry**". §6.1 pre-empts the worst misclassification by ruling that an off-allowlist or red

[Read the thread](https://github.com/QAtlasHub/doiget/issues/506) · 2026-08-25 · open · 1 comment

### feat(registry): the MCP Registry now documents cargo AND mcpb — the source-only entry can carry packages

`server.json` has no `packages` array, so `io.github.QAtlasHub/doiget` is discoverable in the registry but **not installable from it**. Verified live:

```
$ curl 'https://registry.modelcontextprotocol.io/v0/servers?search=doiget'
  name: io.github.QAtlasHub/doiget | version: 0.8.9 | packages: (none)
```

The reason is recorded in `release-plz.yml`:

> the live MCP Registry does not yet accept the `cargo` registry type (400 "unsupported registry type: cargo"), though the 2025-12-11 schema lists 

[Read the thread](https://github.com/QAtlasHub/doiget/issues/483) · 2026-08-25 · closed · 1 comment

### test: the batch --json and MCP diagnostic wiring points would survive being disconnected

Found in the #468 review. Same shape as #413 / #442 / #454 / #458: the component works, the wiring is untested, and disconnecting it leaves the suite green.

## batch `--json`

`crates/doiget-cli/src/commands/batch.rs:535` (inside `classify_joined`) is the only place that threads a real `FetchPaperOutcome`'s `attempts` into `build_jsonl_failure`.

Every test that asserts the JSONL record contains `attempts` / `remediation` calls `build_jsonl_failure` **directly** with hand-built arguments. The o

[Read the thread](https://github.com/QAtlasHub/doiget/issues/471) · 2026-08-25 · closed · 1 comment

### The MCP envelope and batch --json carry no resolution trace and no remediation hint, so an agent is told "blocked" and cannot find the one-line fix

Everything #443, #448 and #449 added to make a blocked fetch *actionable* is CLI text. The two
machine-readable surfaces — the MCP tool envelope and `batch --json` — get none of it.

## Evidence

Real `doiget serve`, `doiget_fetch_paper`, `10.1109/TSP.2018.2812747`:

```
KEYS        : [authors, license, oa_status, ok, path, pdf, ref,
               resolver_profile, schema_version, size_bytes, source, title, year]
has attempts: False
pdf         : { status: "blocked",
                code: "NETW

[Read the thread](https://github.com/QAtlasHub/doiget/issues/459) · 2026-08-24 · closed · 0 comments

### bug(transport): the Tier-3 allowlists are never registered in the production HTTP client, so every TDM fetch fails UnknownSource

`tier_3_aps_allowlist()`, `tier_3_elsevier_allowlist()` and `tier_3_springer_allowlist()` are
implemented, feature-gated and asserted by a registry guard. **Nothing calls them.** Neither
`build_http_client` (CLI) nor its MCP twin extends `allowlists` with them, so the production
client has no entry under the `tdm-*` source keys and `ctx.http.fetch_bytes("tdm-aps", ...)`
returns `UnknownSource`.

This is #442 one layer down. #444 made the orchestrator *reach* the three sources; the transport
gate

[Read the thread](https://github.com/QAtlasHub/doiget/issues/454) · 2026-08-24 · closed · 0 comments

The remaining reports are on [the project's issue tracker](https://github.com/sotashimozono/doiget/issues).
