Skip to main content

metadata_only

Function metadata_only 

Source
pub async fn metadata_only(
    ref_: &Ref,
    profile: &CapabilityProfile,
    ctx: &FetchContext,
) -> Result<MetadataOnlyOutcome, FetchError>
Expand description

Resolve a Ref to metadata WITHOUT triggering a publisher PDF fetch.

Binding spec: docs/MCP_TOOLS.md §11 (NORMATIVE — this function MUST NOT call crate::http::HttpClient::fetch_pdf under any code path). The posture-lint workflow greps for that pattern; the test suite additionally exercises the DOI and arXiv branches end-to-end against wiremock to assert the OA URL is reported, not followed.

§Dispatch

  • Ref::Doi(_) → Crossref first (bibliographic metadata + OA URL via message.link[]). If Crossref returns a usable payload the call returns immediately; Unpaywall is consulted only as a fallback when Crossref fails. The Unpaywall fallback surfaces a license string and may overwrite oa_url with the best_oa_location channel.
  • Ref::Arxiv(_)ArxivSource::fetch_metadata_only: ONLY the Atom feed (https://export.arxiv.org/api/query?id_list=<id>) is consulted; the PDF endpoint is NOT touched. license is set to the platform-wide "arxiv-default" token, oa_url is None (the arXiv abstract page is not a PDF URL).

§Side effects

Each consulted source appends ONE LogEvent::Fetch row to ctx.log (arXiv emits its row under Capability::Metadata; the DOI sources emit under Capability::Oa — they pre-date this distinction and a follow-up slice may unify them). The orchestrator itself does NOT bracket the call with SessionStart / SessionEnd rows — that is the MCP server’s responsibility (it owns the per-tool-call session boundary).

This function is the pure resolver: it consults the source(s) and emits provenance rows, but it does NOT write to the store. The docs/MCP_TOOLS.md §11 store-write SIDE EFFECT is provided by metadata_only_to_store, which wraps this and persists the metadata TOML to <root>/.metadata/<safekey>.toml. Keeping the store-write in a separate entry point is exactly what lets resolve_only safely delegate here — its contract forbids any store write, and a pure metadata_only can never regress that invariant (#139).

§Errors

Returns FetchError from the underlying Source dispatch. The MCP boundary converts these to the closed crate::ErrorCode set via the existing From<FetchError> for ErrorCode impl.