{
  "markdown": "# Paper Chaser MCP\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/joshuasundance-swca/paper-chaser-mcp)\n\n> **Release status:** The repository, CLI, Docker image metadata, and public\n> MCP identity are now aligned on `paper-chaser-mcp`. GHCR images and GitHub\n> Release assets are the primary public distribution channels; PyPI remains\n> intentionally gated until account recovery and trusted-publisher setup are\n> complete.\n\nAn MCP server for academic research — search papers, chase citations, look up authors, repair broken references, explore species dossiers, and retrieve regulatory text, all from one FastMCP server that AI assistants can call directly.\n\n**Providers:** [Semantic Scholar](https://www.semanticscholar.org/product/api) · [arXiv](https://info.arxiv.org/help/api/user-manual.html) · [OpenAlex](https://developers.openalex.org/) · [CORE](https://api.core.ac.uk/docs/v3) · [SerpApi Google Scholar](https://serpapi.com/google-scholar-api) (opt-in, paid) · [Crossref](https://www.crossref.org/documentation/retrieve-metadata/rest-api/) · [Unpaywall](https://unpaywall.org/products/api) · [ECOS](https://ecos.fws.gov/) · [FederalRegister.gov](https://www.federalregister.gov/developers/documentation/api/v1) · [GovInfo](https://api.govinfo.gov/docs/)\n\n---\n\n## Contents\n\n- [What can it do?](#what-can-it-do)\n- [Guided vs expert profiles](#guided-vs-expert-profiles)\n- [Quick start](#quick-start)\n- [Quick tool decision guide](#quick-tool-decision-guide)\n- [Core workflows](#core-workflows)\n- [Agent response contract](#agent-response-contract)\n- [Deferred export design](#deferred-export-design)\n- [Migration note](#migration-note)\n- [Installation](#installation)\n- [Configuration](#configuration)\n- [Tools](#tools)\n- [Resources and prompts](#resources-and-prompts)\n- [Microsoft packaging assets](#microsoft-packaging-assets)\n- [Testing with MCP Inspector](#testing-with-mcp-inspector)\n- [Development](#development)\n- [Guides](#guides)\n- [License](#license)\n- [Links](#links)\n\n---\n\n## What can it do?\n\nPaper Chaser MCP is now guided-first: the default public surface is designed to\nbe hard to misuse and explicit about trust.\n\n- **Default research entrypoint**: `research` handles discovery, known-item\n  recovery, citation repair, and regulatory routing in one trust-graded path,\n  with a server-owned quality-first policy for guided use.\n- **Grounded follow-up**: `follow_up_research` answers against one saved\n  `searchSessionId`; if you omit it, the server only infers a session when the\n  choice is unique. Saved-session follow-up can classify mixed source sets into\n  on-topic evidence, weaker context, and off-target leads when the stored\n  metadata is already sufficient.\n- **Decision metadata**: guided responses surface `executionProvenance`, and\n  ambiguous follow-up or source-inspection flows return structured\n  `sessionResolution` / `sourceResolution` payloads instead of opaque errors.\n- **Reference-first recovery**: `resolve_reference` handles DOI/arXiv/URL,\n  citation fragments, and regulatory-style references, and exact DOI/arXiv/\n  paper-URL inputs resolve as exact anchors rather than falling through to fuzzy repair.\n  Ambiguous title-only or conflicting metadata matches can now return\n  `multiple_candidates` or `needs_disambiguation`; treat those as candidate\n  anchors, not citation-ready resolutions.\n- **Compact top-level answer**: guided `research` leads with a short\n  recommendation-first `summary`, while keeping the structured evidence,\n  leads, and provenance fields available below it.\n- **Source auditability**: `inspect_source` exposes one `sourceId` with\n  provenance, trust state, weak-match rationale, and quality-aware direct-read next steps; omitted `searchSessionId`\n  is only accepted when one compatible saved session exists.\n- **Runtime truth**: `get_runtime_status` surfaces active profile/transport and\n  provider-state warnings without requiring low-level diagnostics. `configuredSmartProvider`\n  is the configured smart bundle; `activeSmartProvider` is the latest effective execution path, cold-start snapshots emit an explicit provisional warning instead of claiming deterministic fallback before the first smart call settles, and the top-level provider sets now split `disabledProviderSet`, `suppressedProviderSet`, `degradedProviderSet`, and `quotaLimitedProviderSet` instead of collapsing them.\n- **Expert depth remains available**: raw/smart/provider-specific tools still\n  exist for operator workflows under the expert profile.\n\n## Guided vs expert profiles\n\nUse `PAPER_CHASER_TOOL_PROFILE` to choose the advertised surface:\n\n| Profile | Default | Exposed surface | Intended user |\n| --- | --- | --- | --- |\n| `guided` | yes | `research`, `follow_up_research`, `resolve_reference`, `inspect_source`, `get_runtime_status` | Low-context users and agents |\n| `expert` | no | Guided tools plus raw/provider-specific families (`search_papers*`, smart graph tools, regulatory direct tools, full diagnostics), subject to enabled features and disabled-tool visibility | Power users and operator workflows |\n\nPractical default: `PAPER_CHASER_TOOL_PROFILE=guided` with\n`PAPER_CHASER_HIDE_DISABLED_TOOLS=true`.\n\n## Quick start\n\nIf you want the fastest local path, install from source and add the server to your MCP client in stdio mode:\n\n```bash\npip install -e .\n```\n\n```json\n{\n  \"mcpServers\": {\n    \"paper-chaser\": {\n      \"command\": \"python\",\n      \"args\": [\"-m\", \"paper_chaser_mcp\"],\n      \"env\": {\n        \"PAPER_CHASER_TOOL_PROFILE\": \"guided\",\n        \"PAPER_CHASER_HIDE_DISABLED_TOOLS\": \"true\",\n        \"PAPER_CHASER_ENABLE_SEMANTIC_SCHOLAR\": \"true\",\n        \"PAPER_CHASER_ENABLE_ARXIV\": \"true\",\n        \"PAPER_CHASER_ENABLE_CORE\": \"false\"\n      }\n    }\n  }\n}\n```\n\nThen start with one of these prompts in your MCP client:\n\n- `Research retrieval-augmented generation for coding agents and return only trustworthy findings.`\n- `Use my last searchSessionId to answer one grounded follow-up question.`\n- `Resolve this citation fragment: Vaswani et al. 2017 Attention Is All You Need.`\n- `Research the regulatory history of California condor under 50 CFR 17.95.`\n\nIf you want a local env template for shell runs or Docker Compose, copy `.env.example` to `.env` and fill in only the providers you use.\n\n---\n\n## Quick tool decision guide\n\n| Goal | Start here |\n|---|---|\n| Discovery, literature review, or regulatory history | `research` |\n| Grounded follow-up over saved results | `follow_up_research` |\n| Citation/DOI/arXiv/URL/reference cleanup | `resolve_reference` |\n| Audit one returned source before relying on it | `inspect_source` |\n| Explain environment/runtime differences | `get_runtime_status` |\n| Need direct provider control or specialized pagination | switch to expert profile and use raw/provider-specific tools |\n\n## Core workflows\n\n### 1. Guided research first\n\n```text\nresearch(query=\"retrieval-augmented generation for coding agents\", limit=5)\n→ inspect resultStatus, answerability, summary, evidence, leads, routingSummary\n→ if resultStatus=needs_disambiguation with clarification.reason=underspecified_reference_fragment:\n  tighten the anchor or pivot to resolve_reference instead of forcing retrieval\n→ if resultStatus=abstained and sources are suppressed: inspect suppressedSourceSummaries before rerunning or escalating\n→ save searchSessionId for follow-up or source inspection\n```\n\n### 2. Ask one grounded follow-up\n\n```text\nfollow_up_research(searchSessionId=\"...\", question=\"What evaluation tradeoffs show up here?\")\n→ inspect answerStatus\n→ if answered: use answer + evidence (compact default: sources are identified by selectedEvidenceIds)\n→ if abstained/insufficient_evidence: use nextActions, suppressedSourceSummaries, and inspect_source\n→ mixed saved sessions can still answer relevance-triage questions such as which items are on-topic vs off-target\n→ uniquely anchored recommendation asks can also return a safe start-here answer plus topRecommendation\n→ if you omit searchSessionId and multiple saved sessions exist: provide it explicitly\n→ for full source records pass responseMode=\"standard\"; for diagnostics responseMode=\"debug\"\n→ for selection asks (\"where should I start?\", \"most recent?\"), read topRecommendation\n```\n\n### 3. Resolve references before broad search when possible\n\n```text\nresolve_reference(reference=\"10.1038/nrn3241\")\n→ exact DOI/arXiv/paper URL should resolve directly when supported\nresolve_reference(reference=\"Rockstrom et al planetary boundaries 2009 Nature 461 472\")\n→ inspect status and bestMatch/alternatives\n→ only treat bestMatch as citation-ready when status=resolved\n→ if status=multiple_candidates or needs_disambiguation: pick a candidate or add a stronger author/year/venue clue before citing it\n→ if resolved: run research with the resolved anchor\n```\n\n### 4. Inspect one source before citing it\n\n```text\ninspect_source(searchSessionId=\"...\", evidenceId=\"...\")\n→ inspect verificationStatus, topicalRelevance, whyClassifiedAsWeakMatch, confidenceSignals, canonicalUrl, directReadRecommendations\n→ if searchSessionId is omitted and inference is ambiguous, rerun with an explicit saved session id\n```\n\n### 5. Handle abstention and clarification explicitly\n\n- If `research.resultStatus` is `abstained` or `needs_disambiguation`, do not invent\n  synthesis. Narrow with a concrete anchor: DOI, exact title, species name,\n  agency, year, or venue.\n- When `research` returns `needs_disambiguation` with\n  `clarification.reason=underspecified_reference_fragment`, the server is\n  intentionally stopping before speculative retrieval on a vague\n  citation/reference fragment. Tighten the clue set or switch to\n  `resolve_reference`.\n- If `follow_up_research.answerStatus` is `abstained` or\n  `insufficient_evidence`, treat it as a safety signal. Use `inspect_source`\n  and rerun `research` with tighter scope.\n\n### 6. Expert fallback when you need fine control\n\n```text\nPAPER_CHASER_TOOL_PROFILE=expert\n→ search_papers_smart / ask_result_set / map_research_landscape / expand_research_graph\n→ search_papers / search_papers_bulk and provider-specific families\n→ search_federal_register / get_federal_register_document / get_cfr_text for direct regulatory primary-source control\n```\n\nFor expert smart tools, `deep` is the default quality-first mode. Use\n`balanced` only when lower latency matters enough to justify a narrower pass,\nand reserve `fast` for smoke tests or debugging.\n\nGuided `research` no longer accepts a public `latencyProfile` knob. The server\nowns that policy and currently applies a deep-backed quality-first path with\none bounded review escalation when the first pass is too weak.\n\n## Agent response contract\n\nTreat these as the main guided contracts:\n\n| Field or pattern | Where it appears | What to do with it |\n| --- | --- | --- |\n| `resultStatus` | `research` | `succeeded`, `partial`, `needs_disambiguation`, `abstained`, `failed` |\n| `answerability` | `research`, `follow_up_research` | `grounded`, `limited`, `insufficient` |\n| `evidence` | `research`, `follow_up_research` | Canonical grounded source records for inspection and citation |\n| `leads` | `research`, `follow_up_research`, expert smart tools | Review weak, filtered, or off-topic leads without promoting them into grounded evidence |\n| `evidenceGaps` | `research`, `follow_up_research` | Treat as explicit limits on the current answer, not hidden caveats |\n| `routingSummary` | `research`, `follow_up_research` | Check intent, anchor, provider plan, regulatory subtype or entity card when present, and why the result is partial |\n| `coverageSummary` | `research`, `follow_up_research` | Check provider coverage and completeness before relying on synthesis |\n| `executionProvenance` | guided tools | Inspect which server policy, latency defaults, and fallback path produced the result |\n| `confidenceSignals` | `research`, `follow_up_research`, `inspect_source` | Inspect additive trust cues such as evidence quality, synthesis mode, and source-scope labels without replacing `answerability` |\n| `evidenceUsePlan` | `follow_up_research` | For synthesis-style follow-ups, inspect answer subtype, directly responsive evidence ids, unsupported parts, and retrieval sufficiency before trusting the answer |\n| `sessionResolution` | `follow_up_research`, `inspect_source` | Use when a session was inferred, repaired, missing, or ambiguous |\n| `sourceResolution` | `inspect_source` | Use when the requested source id was matched, unresolved, or needs a retry with available ids |\n| `abstentionDetails` | guided tools on weak evidence | Treat as the actionable reason and recovery hint for abstention or insufficient evidence |\n| `nextActions` | guided tools | Treat as server-preferred recovery path on weak evidence |\n| `clarification` | `research` | Ask the user only when a bounded clarification request is provided |\n| `answerStatus` | `follow_up_research` | `answered`, `abstained`, `insufficient_evidence`. Grounded `answered` requires on-topic verified source + qa-readable text + non-deterministic provider + medium+ confidence; otherwise expect `insufficient_evidence`. |\n| `topRecommendation` | `follow_up_research` (comparative/selection asks) | Structured pick with `sourceId`, `recommendationReason`, `comparativeAxis` (e.g. `beginner_friendly`, `recency`, `authority`). Unique anchored \"where should I start?\" asks can safely answer through this path even when broader synthesis would stay limited. |\n| `responseMode` | `follow_up_research` input | `compact` (default, hides full sources and legacy fields), `standard`, `debug`. |\n| `includeLegacyFields` | `follow_up_research` input | Set `true` to restore legacy `verifiedFindings`/`unverifiedLeads` in compact mode. |\n| `fullTextUrlFound` / `bodyTextEmbedded` / `qaReadableText` | `inspect_source` | Distinguish URL discovery, embedded body text, and text actually available to QA synthesis. `fullTextObserved` may still appear as a compatibility alias, but the split fields are the durable contract. |\n| `evidenceId` | `evidence[*]` | Pass to `inspect_source` for per-source provenance checks |\n| `runtimeSummary` | `get_runtime_status` and expert diagnostics | Confirm effective profile, smart provider state, and warnings |\n\nFor broad agency-guidance discovery, guided routing stays on the\nregulatory primary-source path. Off-topic authority documents may still appear\nas `leads`, but they should not displace more relevant query-anchored guidance\nor policy documents from the top-level recommendation.\n\nFor source-level audits, treat `whyClassifiedAsWeakMatch` and\n`confidenceSignals.sourceScopeLabel` / `confidenceSignals.sourceScopeReason` as\nthe primary explanation of why an authoritative record was retained as a weak\nmatch or off-topic lead.\n\nAdditional trust and grounding signals landed in the `llm-guidance` phase-4\nwave. Guided responses can expose `confidenceSignals.evidenceQualityProfile`,\n`confidenceSignals.synthesisMode`, `confidenceSignals.evidenceProfileDetail`,\n`confidenceSignals.synthesisPath`, `confidenceSignals.trustRevisionNarrative`,\nand a `trustSummary.authoritativeButWeak` bucket for primary-source records\nthat are authoritative but not topically responsive. `searchStrategy` may\nsurface `regulatoryIntent`, `intentFamily`, a `subjectCard` for species and\nregulatory grounding, and `subjectChainGaps` describing missing subject-chain\nevidence. `inspect_source` pairs each direct-read suggestion with a\n`directReadRecommendationDetails` entry shaped as\n`{trustLevel, whyRecommended, cautions}` so agents can prioritize direct reads\nby quality. See [Paper Chaser Golden Paths](docs/golden-paths.md) and\n[Guided And Smart Robustness Notes](docs/guided-smart-robustness.md) for how\nto read and act on these signals.\n\n## Deferred export design\n\nSession export is intentionally deferred in this wave. The planned future shape is\n`export_search_session(searchSessionId, format)` with `format` in `ris`,\n`bibtex`, or `csv`, using the guided-v2 source/citation schema so export can land\nwithout another public-contract rewrite.\n\n## Migration note\n\nIf you previously used the smart/raw-first surface directly:\n\n1. Start with `research` instead of `search_papers_smart` or `search_papers`.\n2. Use `follow_up_research` instead of `ask_result_set` for default grounded QA.\n3. Use `resolve_reference` instead of `resolve_citation`/`search_papers_match`\n   as your first known-item recovery step.\n4. Keep expert tools for explicit operator workflows by setting\n   `PAPER_CHASER_TOOL_PROFILE=expert`.\n5. Do not send `latencyProfile` to guided `research`; the server now owns that\n  policy internally.\n6. For expert smart tools, `deep` is now the default. Choose `balanced`\n  explicitly when you want the lower-latency fallback.\n7. Expect guided wrappers to surface `executionProvenance`, `sessionResolution`,\n  `sourceResolution`, and `abstentionDetails`.\n\nFor the detailed breaking-change note, see [Guided Reset Migration Note](docs/guided-reset-migration-note.md).\n\n---\n\n## Installation\n\nCurrent distribution options:\n\n- Source checkout: the most direct local path today, especially for development and MCP desktop clients.\n- GHCR image: the primary container distribution channel for Docker-backed MCP clients.\n- GitHub Release assets: `v*` tags build wheel and sdist artifacts and attach them to a draft GitHub Release for review.\n- PyPI: intentionally gated for now; use source installs or GitHub Release artifacts until that path is re-enabled.\n\nFor local source installs:\n\n```bash\npip install -e .\n```\n\nOptional extras for the additive AI layer:\n\n- Shared smart-layer runtime only, including deterministic mode: `pip install -e \".[ai]\"`\n- OpenAI or Azure OpenAI provider support: `pip install -e \".[ai,openai]\"`\n- Hugging Face chat-router support: `pip install -e \".[ai,huggingface]\"`\n- NVIDIA provider support: `pip install -e \".[ai,nvidia]\"`\n- Anthropic provider support: `pip install -e \".[ai,anthropic]\"`\n- Google provider support: `pip install -e \".[ai,google]\"`\n- Mistral provider support: `pip install -e \".[ai,mistral]\"`\n- Azure AI Foundry eval publishing helpers: `pip install -e \".[eval-foundry]\"`\n- Hugging Face eval publishing helpers: `pip install -e \".[eval-huggingface]\"`\n- Both eval publishing helper surfaces: `pip install -e \".[eval]\"`\n- Add `,ai-faiss` to any of the commands above if you want the optional FAISS backend.\n\nAzure OpenAI uses the same `openai` extra.\nHugging Face uses a dedicated `huggingface` extra that installs the OpenAI-compatible SDK plus the LangChain OpenAI adapter; this repo documents it as a chat-only smart-provider path with embeddings disabled.\nThe eval publishing helpers use separate extras on purpose: `eval-foundry` is for Azure AI Foundry dataset upload support, and `eval-huggingface` is for Hugging Face dataset-repo or bucket publishing support. Those extras are independent from the smart-provider chat runtime.\n\n## Configuration\n\nThe full local environment-variable contract lives in `.env.example`. That file mirrors the public local knobs supported by `docker-compose.yaml`. Azure-specific identifiers, secrets, and Bicep parameters are intentionally documented separately in [docs/azure-deployment.md](docs/azure-deployment.md).\n\n### Desktop MCP clients\n\nUse stdio transport for desktop MCP clients unless you specifically need HTTP.\nSee the [Quick start](#quick-start) JSON example above for the server definition.\n\n- **Claude Desktop** config path:\n  - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`\n  - Windows: `%APPDATA%\\Claude\\claude_desktop_config.json`\n- **Cursor**: add the same MCP server definition in Cursor settings.\n\n### Search broker and feature flags\n\nGuided mode starts from `research`. The brokered and provider-specific controls\nbelow are expert-path controls.\n\n| Area | Default | Main variables | Notes |\n| --- | --- | --- | --- |\n| Tool profile | `guided` | `PAPER_CHASER_TOOL_PROFILE` | `guided` exposes the 5 low-context tools; `expert` exposes the broader raw/provider-specific surface, subject to enabled features and `PAPER_CHASER_HIDE_DISABLED_TOOLS` |\n| Guided policy | quality-first | `PAPER_CHASER_GUIDED_RESEARCH_LATENCY_PROFILE`, `PAPER_CHASER_GUIDED_FOLLOW_UP_LATENCY_PROFILE`, `PAPER_CHASER_GUIDED_ALLOW_PAID_PROVIDERS`, `PAPER_CHASER_GUIDED_ESCALATION_ENABLED`, `PAPER_CHASER_GUIDED_ESCALATION_MAX_PASSES`, `PAPER_CHASER_GUIDED_ESCALATION_ALLOW_PAID_PROVIDERS` | Guided `research` / `follow_up_research` use these server-owned defaults instead of honoring client `latencyProfile` knobs |\n| Search broker | `semantic_scholar,arxiv,core,serpapi_google_scholar` | `PAPER_CHASER_ENABLE_SEMANTIC_SCHOLAR`, `PAPER_CHASER_ENABLE_ARXIV`, `PAPER_CHASER_ENABLE_CORE`, `PAPER_CHASER_ENABLE_SERPAPI`, `PAPER_CHASER_PROVIDER_ORDER` | SerpApi is opt-in and paid; CORE is off by default |\n| OpenAlex tool family | enabled | `PAPER_CHASER_ENABLE_OPENALEX`, `OPENALEX_API_KEY`, `OPENALEX_MAILTO` | Explicit tool family, not a default broker hop |\n| ScholarAPI tool family | disabled | `PAPER_CHASER_ENABLE_SCHOLARAPI`, `SCHOLARAPI_API_KEY` | Explicit discovery, monitoring, full-text, and PDF family; also available as an opt-in broker target via `preferredProvider` or `providerOrder`. ScholarAPI-sourced paper results now include a separate `contentAccess` block for access/full-text metadata. |\n| Enrichment | enabled | `PAPER_CHASER_ENABLE_CROSSREF`, `CROSSREF_MAILTO`, `CROSSREF_TIMEOUT_SECONDS`, `PAPER_CHASER_ENABLE_UNPAYWALL`, `UNPAYWALL_EMAIL`, `UNPAYWALL_TIMEOUT_SECONDS`, `PAPER_CHASER_ENABLE_OPENALEX` | Used after you already have a paper or DOI |\n| ECOS | enabled | `PAPER_CHASER_ENABLE_ECOS`, `ECOS_BASE_URL`, `ECOS_TIMEOUT_SECONDS`, document timeout and size vars, TLS vars | Species and document workflows |\n| Federal Register / GovInfo | enabled | `PAPER_CHASER_ENABLE_FEDERAL_REGISTER`, `PAPER_CHASER_ENABLE_GOVINFO_CFR`, `GOVINFO_API_KEY`, GovInfo timeout and size vars | Federal Register search is keyless; authoritative CFR retrieval uses GovInfo |\n| Smart layer | disabled | `OPENAI_API_KEY`, `OPENROUTER_API_KEY`, `OPENROUTER_BASE_URL`, `OPENROUTER_HTTP_REFERER`, `OPENROUTER_TITLE`, `HUGGINGFACE_API_KEY`, `HUGGINGFACE_BASE_URL`, `NVIDIA_API_KEY`, `NVIDIA_NIM_BASE_URL`, `AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_API_VERSION`, `ANTHROPIC_API_KEY`, `GOOGLE_API_KEY`, `MISTRAL_API_KEY`, `PAPER_CHASER_ENABLE_AGENTIC`, model and index vars | Additive only; supports `openai`, `azure-openai`, `anthropic`, `nvidia`, `google`, `mistral`, `huggingface`, `openrouter`, and `deterministic`. OpenAI ships with checked-in model defaults, Anthropic, NVIDIA, Google, and Mistral auto-swap to provider defaults when those OpenAI defaults are left untouched, and Azure OpenAI can override both roles with deployment names. Hugging Face and OpenRouter are documented as OpenAI-compatible chat routers configured with `HUGGINGFACE_BASE_URL` and `OPENROUTER_BASE_URL`; both remain chat-only in this repo and do not enable embeddings. OpenRouter preserves explicit planner and synthesis model names such as provider-prefixed model IDs. `NVIDIA_NIM_BASE_URL` is optional for self-hosted NIMs; leave it empty for hosted NVIDIA API Catalog access. Embeddings remain disabled by default because they have been unreliable in this codebase, and improving them is out of scope for the current release. When ScholarAPI is enabled, smart discovery can also route through it and cap it via `providerBudget.maxScholarApiCalls`. |\n| Hide disabled tools | guided default `true`, expert default `false` | `PAPER_CHASER_HIDE_DISABLED_TOOLS` | Guided mode keeps this on to reduce dead-end tool picks; expert mode usually leaves it off for operator visibility |\n\n### Smart-layer model defaults\n\nThese are the effective planner/synthesis defaults when you enable `PAPER_CHASER_ENABLE_AGENTIC=true` and do not intentionally override the model vars.\n\n| `PAPER_CHASER_AGENTIC_PROVIDER` | Default planner | Default synthesis | Resolution rule |\n| --- | --- | --- | --- |\n| `openai` | `gpt-5.4-mini` | `gpt-5.4` | Uses the checked-in `PAPER_CHASER_PLANNER_MODEL` and `PAPER_CHASER_SYNTHESIS_MODEL` defaults directly |\n| `azure-openai` | `gpt-5.4-mini` | `gpt-5.4` | Uses the same model vars unless `AZURE_OPENAI_PLANNER_DEPLOYMENT` or `AZURE_OPENAI_SYNTHESIS_DEPLOYMENT` is set; when present, those deployment names win |\n| `anthropic` | `claude-haiku-4-5` | `claude-sonnet-4-6` | Runtime swaps to these provider defaults only when planner/synthesis are still set to the checked-in OpenAI defaults |\n| `nvidia` | `nvidia/nemotron-3-nano-30b-a3b` | `nvidia/nemotron-3-super-120b-a12b` | Runtime swaps to these provider defaults only when planner/synthesis are still set to the checked-in OpenAI defaults |\n| `google` | `gemini-2.5-flash` | `gemini-2.5-pro` | Runtime swaps to these provider defaults only when planner/synthesis are still set to the checked-in OpenAI defaults |\n| `mistral` | `mistral-medium-latest` | `mistral-large-latest` | Runtime swaps to these provider defaults only when planner/synthesis are still set to the checked-in OpenAI defaults |\n| `huggingface` | `moonshotai/Kimi-K2.5` | `moonshotai/Kimi-K2.5` | Runtime swaps to these provider defaults only when planner/synthesis are still set to the checked-in OpenAI defaults; requests are sent to `HUGGINGFACE_BASE_URL` and the path remains chat-only |\n| `openrouter` | none | none | Runtime preserves explicit planner/synthesis model values and sends requests to `OPENROUTER_BASE_URL`; the first-pass path remains chat-only |\n| `deterministic` | n/a | n/a | No external LLM calls; model selection metadata is reported as deterministic instead |\n\n`PAPER_CHASER_EMBEDDING_MODEL` defaults to `text-embedding-3-large`, but embeddings stay off until you set `PAPER_CHASER_DISABLE_EMBEDDINGS=false`. They remain off by default because embeddings have been unreliable in this codebase and improving them is outside the scope of the current guided-policy release. In the current provider surface, embeddings are only used by providers that explicitly support them, which means the documented Hugging Face path remains chat-only even though it uses an OpenAI-compatible router.\n\nRecommended baseline: enable Semantic Scholar, OpenAlex, Crossref, and Unpaywall for general scholarly workflows; enable ScholarAPI when you want explicit full-text or PDF retrieval; keep SerpApi opt-in because it is a paid recall-recovery path.\n\nBroker rules that matter most:\n\n- Default search fallback order is Semantic Scholar, then arXiv, then CORE, then SerpApi when enabled.\n- `preferredProvider`, `providerOrder`, and `PAPER_CHASER_PROVIDER_ORDER` accept `core`, `semantic_scholar`, `arxiv`, `scholarapi`, and `serpapi` or `serpapi_google_scholar`.\n- Semantic Scholar-only filters such as `publicationDateOrYear`, `fieldsOfStudy`, `publicationTypes`, `openAccessPdf`, and `minCitationCount` can force the broker to skip incompatible providers.\n- Broker responses surface `brokerMetadata.providerUsed`, `brokerMetadata.attemptedProviders`, and `brokerMetadata.recommendedPaginationTool` so agents can follow the right next step.\n\n### Transport and deployment modes\n\n| Mode | Default | Main variables | Use when |\n| --- | --- | --- | --- |\n| Desktop stdio | `stdio` | none required | Claude Desktop, Cursor, local MCP subprocess launches |\n| Direct HTTP run | opt in | `PAPER_CHASER_TRANSPORT`, `PAPER_CHASER_HTTP_HOST`, `PAPER_CHASER_HTTP_PORT`, `PAPER_CHASER_HTTP_PATH` | Local integration testing without the deployment wrapper |\n| HTTP wrapper | opt in | `PAPER_CHASER_HTTP_AUTH_TOKEN`, `PAPER_CHASER_HTTP_AUTH_HEADER`, `PAPER_CHASER_ALLOWED_ORIGINS` | Local parity with hosted HTTP deployments |\n| Docker Compose publish settings | localhost defaults | `PAPER_CHASER_PUBLISHED_HOST`, `PAPER_CHASER_PUBLISHED_PORT` | Control the host-side HTTP port mapping only |\n\nKey distinctions:\n\n- `PAPER_CHASER_HTTP_HOST` and `PAPER_CHASER_HTTP_PORT` control the direct shell and hosted deployments. Docker Compose keeps the container bind at `0.0.0.0:8080` and uses `PAPER_CHASER_PUBLISHED_HOST` / `PAPER_CHASER_PUBLISHED_PORT` for the host-side mapping.\n- `paper-chaser-mcp deployment-http` runs the deployment wrapper used by Compose and Azure. It adds `/healthz` plus optional auth and Origin enforcement in front of the MCP endpoint.\n\nExample direct local HTTP run:\n\n```bash\nPAPER_CHASER_TRANSPORT=streamable-http \\\nPAPER_CHASER_HTTP_HOST=127.0.0.1 \\\nPAPER_CHASER_HTTP_PORT=8000 \\\npython -m paper_chaser_mcp\n```\n\nIf you need the full Azure deployment story, including the `bootstrap` and `full` workflow modes, read [docs/azure-deployment.md](docs/azure-deployment.md), [docs/azure-architecture.md](docs/azure-architecture.md), and [docs/azure-security-model.md](docs/azure-security-model.md).\n\n### Docker MCP package (stdio)\n\nFor local MCP clients that launch servers as subprocesses, use the image in\nstdio mode. For unpublished local iteration, build and run `paper-chaser-mcp:local`.\nFor the reusable public package, use the published GHCR tag:\n\n```bash\ndocker run --rm -i ghcr.io/joshuasundance-swca/paper-chaser-mcp:latest\n```\n\nFor a locally built image:\n\n```bash\ndocker run --rm -i paper-chaser-mcp:local\n```\n\nA Docker-backed MCP client entry typically looks like:\n\n```json\n{\n  \"mcpServers\": {\n    \"paper-chaser\": {\n      \"command\": \"docker\",\n      \"args\": [\"run\", \"--rm\", \"-i\", \"ghcr.io/joshuasundance-swca/paper-chaser-mcp:latest\"]\n    }\n  }\n}\n```\n\nThis mode is ideal for local desktop MCP usage because the host launches and\nowns the server process lifecycle.\n\nThe repo also ships `server.json` so the public OCI image and MCP package\nmetadata stay aligned for registry/discovery tooling. The public-package\nworkflow is tag-driven for GHCR: a `v*` tag publishes the reusable container\nimage to `ghcr.io/joshuasundance-swca/paper-chaser-mcp`. MCP Registry\npublication is intentionally decoupled into a separate manual workflow so GHCR\nshipping does not depend on registry availability.\n\nPython package publishing is prepared separately in\n`.github/workflows/publish-pypi.yml`: pull requests build and `twine check` the\ndistribution, and the actual publish jobs stay dormant until the repository\nvariable `ENABLE_PYPI_PUBLISHING` is set to `true`. After PyPI/TestPyPI access\nis restored and the trusted publishers are registered, manual dispatch can\npublish to TestPyPI and a `v*` tag can publish to PyPI.\n\nGitHub Release assets are handled separately in\n`.github/workflows/publish-github-release.yml`: a `v*` tag or manual dispatch\nbuilds wheel and sdist artifacts, verifies them with `twine check`, generates\n`SHA256SUMS`, and uploads them to a draft GitHub Release page so Python\nartifacts can be reviewed before broader public promotion.\n\n### Docker Compose (HTTP wrapper mode)\n\nFor local HTTP testing, MCP Inspector, or bridge-style integrations, this repo\nships `docker-compose.yaml` with localhost-only defaults. Compose\nexplicitly starts the `deployment-http` subcommand, so HTTP wrapper behavior\ndoes not depend on the image's default transport.\n\nCompose keeps the container bind host and internal port fixed at\n`0.0.0.0:8080` and overrides the app default transport to `streamable-http`,\nso browser tools and bridge-style clients can connect over\n`http://127.0.0.1:8000/mcp` without extra shell flags. The compose file\nexposes the user-facing knobs: transport, MCP path, provider keys, provider\ntoggles, auth, and the published host port mapping.\n\n1. Copy `.env.example` to `.env`.\n2. Fill in any optional provider keys you want to use.\n3. Start the service:\n\n```bash\ndocker compose -f docker-compose.yaml up --build\n```\n\nThe service listens on `http://127.0.0.1:8000` by default, serves\n`/healthz` for probes, and exposes MCP over `http://127.0.0.1:8000/mcp`.\n\n```bash\ncurl http://127.0.0.1:8000/healthz\n```\n\nIf you set `PAPER_CHASER_HTTP_AUTH_TOKEN` and leave\n`PAPER_CHASER_HTTP_AUTH_HEADER=authorization`, the deployment wrapper expects\n`Authorization: Bearer <token>` on `/mcp`. The checked-in Azure scaffold\noverrides the header name to `x-backend-auth` and has API Management inject\nthat header for backend-only traffic. The published host defaults to\n`127.0.0.1`; only change `PAPER_CHASER_PUBLISHED_HOST` when you intentionally\nwant the container reachable beyond the local machine.\n\nIf you leave the provider key fields blank, local clients still work. The\nserver falls back to the free/default provider paths where supported, and\nSerpApi stays disabled by default.\n\n### Docker Compose Inspector sidecar\n\nFor browser-based debugging without installing Node locally, use the dedicated\nInspector stack:\n\n```bash\ndocker compose -f compose.inspector.yaml up --build\n```\n\nThis stack keeps Inspector separate from the MCP server image and binds the UI\nand proxy to localhost only:\n\n- Inspector UI: `http://127.0.0.1:6274`\n- Inspector proxy: `http://127.0.0.1:6277`\n\nInspector proxy authentication remains enabled by default. Use\n`docker compose -f compose.inspector.yaml logs mcp-inspector` to read the\nsession token that Inspector prints on startup.\n\nInside Inspector, connect using Streamable HTTP and set:\n\n- URL: `http://paper-chaser-mcp:8080/mcp`\n- Transport: `streamable-http`\n\n`compose.inspector.yaml` accepts `IMAGE` overrides, so you can test a specific\ntag without editing files:\n\n```bash\nIMAGE=ghcr.io/joshuasundance-swca/paper-chaser-mcp:latest docker compose -f compose.inspector.yaml up\n```\n\n## Tools\n\nFull tool reference. See the [Quick tool decision guide](#quick-tool-decision-guide) above for where to start.\n\n### Guided default tools\n\n| Tool | Description |\n| --- | --- |\n| `research` | Default trust-graded entrypoint for discovery, known-item recovery, citation repair, and regulatory routing. |\n| `follow_up_research` | Grounded follow-up over a saved `searchSessionId`; returns explicit abstention/insufficient-evidence states when needed. |\n| `resolve_reference` | Resolve citation-like input (citation, DOI, arXiv, URL, title fragment, regulatory reference) into the safest next anchor. |\n| `inspect_source` | Inspect one `sourceId` from a guided result set for provenance, trust state, and direct-read follow-through. |\n| `get_runtime_status` | Guided runtime summary for active profile, transport, smart-provider state, and warnings. |\n\n### Expert smart research layer\n\nThese tools are expert profile paths for deeper orchestration and provider\ncontrol.\n\n| Tool | Description |\n| --- | --- |\n| `search_papers_smart` | Concept-level discovery with query expansion, multi-provider fusion, reranking, reusable `searchSessionId`, and an evidence-first expert contract (`resultStatus`, `answerability`, `routingSummary`, `evidence`, `leads`, `evidenceGaps`, `structuredSources`, `coverageSummary`, `failureSummary`). Legacy trust fields remain available as compatibility views. In `auto` mode it can also route clearly regulatory asks into a primary-source timeline. `latencyProfile` defaults to `deep` for highest-quality expert work; use `balanced` for lower latency and reserve `fast` for smoke tests. Optional `providerBudget` remains available for advanced clients. |\n| `ask_result_set` | Grounded QA, claim checks, and comparisons over a saved `searchSessionId`. |\n| `map_research_landscape` | Cluster a saved result set into themes, gaps, disagreements, and next-search suggestions. |\n| `expand_research_graph` | Expand paper anchors or a saved session into a citation/reference/author graph with frontier ranking. |\n\n### Paper search\n\n| Tool | Description |\n| --- | --- |\n| `search_papers` | Brokered single-page search (default: Semantic Scholar → arXiv → CORE → SerpApi). Read `brokerMetadata.nextStepHint`; ScholarAPI is also available as an explicit opt-in broker target. |\n| `search_papers_bulk` | Paginated bulk search (Semantic Scholar) up to 1,000 papers/call with boolean query syntax. |\n| `search_papers_semantic_scholar` | Single-page Semantic Scholar-only search with full filter support. |\n| `search_papers_arxiv` | Single-page arXiv-only search. |\n| `search_papers_core` | Single-page CORE-only search. |\n| `search_papers_serpapi` | Single-page SerpApi Google Scholar search. **Requires SerpApi.** |\n| `search_papers_scholarapi` | Single-page ScholarAPI relevance-ranked search. **Requires ScholarAPI.** |\n| `search_papers_openalex` | Single-page OpenAlex-only search. |\n| `search_papers_openalex_bulk` | Cursor-paginated OpenAlex search. |\n| `list_papers_scholarapi` | Cursor-paginated ScholarAPI monitoring/list flow sorted by `indexed_at`. |\n| `search_papers_openalex_by_entity` | OpenAlex works constrained to one source, institution, or topic entity ID. |\n\n### Known-item lookup and citation repair\n\n| Tool | Description |\n| --- | --- |\n| `resolve_citation` | Citation-repair workflow for incomplete or malformed references. Abstains on regulatory references. |\n| `search_papers_match` | Known-item lookup for messy or partial titles with cross-provider confirmation. |\n| `get_paper_details` | Lookup by DOI, arXiv ID, Semantic Scholar ID, or URL. Optional `includeEnrichment`. |\n| `get_paper_details_openalex` | OpenAlex work lookup by W-id, URL, or DOI with abstract reconstruction. |\n| `paper_autocomplete` | Paper title typeahead completions. |\n| `paper_autocomplete_openalex` | OpenAlex work typeahead for known-item disambiguation. |\n\n### Citations, references, and authors\n\n| Tool | Description |\n| --- | --- |\n| `get_paper_citations` | Papers that cite the given paper (Semantic Scholar). Cursor-paginated. |\n| `get_paper_citations_openalex` | OpenAlex cited-by expansion. Cursor-paginated. |\n| `get_paper_references` | References behind the given paper (Semantic Scholar). Cursor-paginated. |\n| `get_paper_references_openalex` | OpenAlex backward-reference expansion. Cursor-paginated. |\n| `get_paper_authors` | Authors of the given paper (Semantic Scholar). |\n| `search_authors` | Search authors by name (Semantic Scholar). |\n| `search_authors_openalex` | Search OpenAlex authors by name. |\n| `get_author_info` | Author profile by Semantic Scholar author ID. |\n| `get_author_info_openalex` | OpenAlex author profile by A-id or URL. |\n| `get_author_papers` | Papers by Semantic Scholar author. Cursor-paginated. |\n| `get_author_papers_openalex` | Papers by OpenAlex author with `year` filter and cursor pagination. |\n| `batch_get_papers` | Details for up to 500 paper IDs in one call. |\n| `batch_get_authors` | Details for up to 1,000 author IDs in one call. |\n| `get_paper_recommendations` | Similar papers by single seed (GET). |\n| `get_paper_recommendations_post` | Similar papers from positive/negative seed sets (POST). |\n\n### Paper enrichment and OA discovery\n\n| Tool | Description |\n| --- | --- |\n| `enrich_paper` | Combined Crossref + Unpaywall + OpenAlex enrichment for one known paper or DOI. Query-only calls without an anchor abstain instead of resolving a paper. |\n| `get_paper_metadata_crossref` | Explicit Crossref enrichment for a known paper or DOI. |\n| `get_paper_open_access_unpaywall` | Unpaywall OA status, PDF URL, and license lookup by DOI. Requires `UNPAYWALL_EMAIL`. |\n\n### ScholarAPI text and PDF retrieval\n\n| Tool | Description |\n| --- | --- |\n| `get_paper_text_scholarapi` | Fetch one ScholarAPI plain-text full document by ScholarAPI paper id. |\n| `get_paper_texts_scholarapi` | Batch full-text retrieval for up to 100 ScholarAPI paper ids. Preserves order and null placeholders. |\n| `get_paper_pdf_scholarapi` | Fetch one ScholarAPI PDF as structured metadata plus base64-encoded content. |\n\n### OpenAlex entities\n\n| Tool | Description |\n| --- | --- |\n| `search_entities_openalex` | Search OpenAlex source, institution, or topic entities for pivot workflows. |\n\n### ECOS species dossiers\n\n| Tool | Description |\n| --- | --- |\n| `search_species_ecos` | ECOS species discovery by common or scientific name. |\n| `get_species_profile_ecos` | Full ECOS species dossier: listings, documents, and conservation plans. |\n| `list_species_documents_ecos` | Flatten one dossier into a sorted document inventory. |\n| `get_document_text_ecos` | Fetch and convert an ECOS document (PDF/HTML/text) to Markdown. |\n\n### Federal Register and CFR\n\n| Tool | Description |\n| --- | --- |\n| `search_federal_register` | Keyless Federal Register discovery for notices, rules, and proposed rules. |\n| `get_federal_register_document` | Retrieve one Federal Register document by number, FR citation, or GovInfo link. |\n| `get_cfr_text` | CFR part or section text from GovInfo. Requires `GOVINFO_API_KEY`. |\n\n### SerpApi extras *(opt-in, paid)*\n\n| Tool | Description |\n| --- | --- |\n| `search_papers_serpapi_cited_by` | Google Scholar cited-by expansion via SerpApi. |\n| `search_papers_serpapi_versions` | Google Scholar all-versions expansion via SerpApi cluster IDs. |\n| `get_author_profile_serpapi` | Google Scholar author profile via SerpApi. |\n| `get_author_articles_serpapi` | Paginated Google Scholar author articles via SerpApi. |\n| `get_paper_citation_formats` | Citation export (MLA, APA, BibTeX, etc.) from Google Scholar. **Requires SerpApi.** |\n| `get_serpapi_account_status` | SerpApi quota and throughput snapshot. |\n\n### Recovery and diagnostics\n\n| Tool | Description |\n| --- | --- |\n| `search_snippets` | Quote or phrase recovery when title/keyword search is weak. Last-resort tool. |\n| `get_provider_diagnostics` | Live provider health, throttling state, retries, and fallback reasons. |\n\n\n### ECOS walkthrough\n\nCalifornia least tern is a representative end-to-end ECOS flow:\n\n1. Call `search_species_ecos` with `query=\"California least tern\"` to get the ECOS species id `8104`.\n2. Call `get_species_profile_ecos` with `species_id=\"8104\"` to inspect the species dossier, grouped recovery documents, biological opinions, and conservation-plan links.\n3. Call `list_species_documents_ecos` with `species_id=\"8104\"` and, for example, `documentKinds=[\"recovery_plan\",\"five_year_review\",\"biological_opinion\"]` to flatten the document inventory.\n4. Call `get_document_text_ecos` on the 2025 five-year-review PDF or the revised recovery plan PDF to turn the source document into Markdown for downstream analysis.\n\n## Resources and prompts\n\n- Resource: `guide://paper-chaser/agent-workflows` - compact onboarding guide for choosing tools and following pagination safely\n- Resource: `paper://{paper_id}` - compact markdown + structured payload for a resolved paper\n- Resource: `author://{author_id}` - compact markdown + structured payload for a resolved author\n- Resource: `search://{searchSessionId}` - saved result set surfaced from tool outputs\n- Resource: `trail://paper/{paper_id}?direction=citations|references` - compact citation/reference trail resource\n- Prompt: `plan_paper_chaser_search` - reusable planning prompt with guided-first defaults and explicit expert fallback\n- Prompt: `plan_smart_paper_chaser_search` - planning prompt for intentional expert smart-mode workflows\n- Prompt: `triage_literature` - guided triage workflow for trust-aware theme mapping and next-step selection\n- Prompt: `plan_citation_chase` - citation-expansion planning prompt\n- Prompt: `refine_query` - bounded query-refinement prompt for broad or noisy searches\n\nPrimary read-tool responses also surface:\n\n- `agentHints` - recommended next tools, retry guidance, and warnings\n- `clarification` - bounded clarification fallback when the server cannot safely disambiguate on its own\n- `resourceUris` - follow-on resources that compatible clients can open directly\n- `searchSessionId` - reusable result-set handle for smart follow-up workflows and cached expansion/search trails\n\n## Microsoft packaging assets\n\nThis repository keeps one universal MCP server surface and ships additive\npackaging assets for Microsoft-oriented clients:\n\n- `mcp-tools.core.json` - guided low-context default surface (`research`, `follow_up_research`, `resolve_reference`, `inspect_source`, `get_runtime_status`)\n- `mcp-tools.full.json` - guided + expert package for environments intentionally running with `PAPER_CHASER_TOOL_PROFILE=expert`\n- `microsoft-plugin.sample.json` - sample declarative-agent / plugin-oriented metadata\n\nThese assets target Streamable HTTP and compact tool outputs. They are\npackaging guidance, not a separate runtime build.\n\n\n## Testing with MCP Inspector\n\nThe recommended local path is the Docker sidecar workflow:\n\n```bash\ndocker compose -f compose.inspector.yaml up --build\n```\n\nThis keeps Inspector out of the production MCP image and binds Inspector ports\nto localhost only.\n\nIf you prefer a host-installed Inspector, you can still run:\n\n```bash\nnpm install -g @modelcontextprotocol/inspector\nmcp-inspector python -m paper_chaser_mcp\n```\n\n## Development\n\nInstall the package with development extras:\n\n```bash\npip install -e \".[dev]\"\n```\n\nIf you also want the additive AI layer plus every hosted-provider integration in the same environment:\n\n```bash\npip install -e \".[all]\"\n```\n\n`all` expands to `ai,openai,huggingface,nvidia,anthropic,google,mistral,dev`, so Azure OpenAI still uses the same `openai` extra while Hugging Face remains a separate chat-only OpenAI-compatible install surface.\n\nIf you need the optional FAISS backend locally as well:\n\n```bash\npip install -e \".[all,ai-faiss]\"\n```\n\nProject dependencies are declared in `pyproject.toml`; there is no separate runtime `requirements.txt` to keep in sync.\n\nRun the local test suite:\n\n```bash\npytest\n```\n\nInstall and run the configured pre-commit hooks:\n\n```bash\npre-commit install\npre-commit run --all-files\n```\n\n`pre-commit install` installs both the fast `pre-commit` hooks and the\nheavier `pre-push` gates configured in `.pre-commit-config.yaml`. Manual-stage\nhooks are not invoked automatically; run `pre-commit run --hook-stage manual\n--all-files` (or the direct commands above) when you want the full local gate.\n\nThe development extras include `pytest`, `pytest-asyncio`, `pytest-cov`,\n`ruff`, `mypy`, `bandit`, `build`, `bumpver`, `pip-audit`,\n`shellcheck-py`, `types-defusedxml`, and `pre-commit`. GitHub dependency automation is configured for both Python\npackages and GitHub Actions via Dependabot, with pull requests checked by the\ndependency review workflow.\n\nFor local parity with CI on GitHub workflow files, keep `shellcheck` available\non `PATH` before running `pre-commit`. Installing `shellcheck-py` in the active\nrepo venv satisfies this for many setups; verify with `shellcheck --version`\ninstead of assuming inline workflow bash is being linted locally.\n\n### Version bumps\n\nVersion metadata is managed with `bumpver` from `pyproject.toml`. The checked-in\npackage version stays in plain PEP 440 form such as `0.2.0`, while the release\ntag shape remains `v0.2.0` to match the existing publish workflow trigger.\n\nFor PR-branch-safe review, dry-run a patch bump without touching git state:\n\n```bash\nbumpver update --patch --dry --no-fetch --no-commit --no-tag-commit --no-push\n```\n\nFor an actual release-prep branch, update the checked-in version contract but\nstill leave commit, tag, and push under explicit maintainer control:\n\n```bash\nbumpver update --patch --no-commit --no-tag-commit --no-push\n```\n\n### Full local validation\n\nThe repo's CI-equivalent local gate is broader than `pytest` alone. For a\nthorough local pass, run:\n\n```bash\npython -m pip check\npre-commit run --all-files\npython -m pytest --cov=paper_chaser_mcp --cov-report=term-missing --cov-fail-under=87\npython -m mypy --config-file pyproject.toml\npython -m ruff check .\npython -m bandit -c pyproject.toml -r paper_chaser_mcp\npython -m build\npython -m pip_audit . --progress-spinner off\n```\n\nIf you prefer to invoke the heavier hook-managed checks through pre-commit,\n`pre-commit run --hook-stage manual --all-files` runs the manual-stage\n`pip check`, coverage, build, and `pip-audit` hooks defined in\n`.pre-commit-config.yaml`.\n\nWhen you touch Azure IaC, deployment docs, the Dockerfile, the APIM policy, or\nthe Azure deployment workflow, also run:\n\n```bash\npython scripts/validate_psrule_azure.py\npython scripts/validate_deployment.py --skip-docker\n```\n\nFor parity with the `Deploy Azure` workflow's full deployment validation path,\nrun:\n\n```bash\npython scripts/validate_deployment.py --require-az --require-docker --image-tag paper-chaser-mcp:ci-validate\n```\n\n### GitHub Agentic Workflow smoke test\n\nThe repository includes an agentic regression workflow at\n`.github/workflows/test-paper-chaser.md` (source) and\n`.github/workflows/test-paper-chaser.lock.yml` (compiled lock file). It runs\nthe agent against the local MCP server inside GitHub Actions, exercises the\nprimary golden paths, evaluates agent UX quality, and can file actionable\nissues for follow-on work.\n\nAfter editing the Markdown workflow, recompile and validate:\n\n```bash\ngh aw compile test-paper-chaser --dir .github/workflows\npre-commit run --all-files\n```\n\nCommit both the `.md` source and `.lock.yml` output together, then run\n`Test Paper Chaser MCP` from the GitHub Actions UI.\n\n**Workflow inputs:** `mode` (`smoke`, `comprehensive`, or `feature_probe`),\n`tool_profile` (`guided` by default, `expert` when you intentionally want\nraw/provider-specific coverage), and an optional `focus_prompt`. Select them\nvia `workflow_dispatch` inputs.\n\n**Required secrets:** `COPILOT_GITHUB_TOKEN` is required.\n`GH_AW_MODEL_AGENT_COPILOT` (Actions variable, optional) controls the agent\nmodel. `CORE_API_KEY` and `SEMANTIC_SCHOLAR_API_KEY` are optional.\n\nThe repository also includes `.github/workflows/agentic-assign.yml`, which\nautomatically assigns GitHub Copilot to issues labeled `agentic` and\n`needs-copilot` (unless also labeled `needs-human`, `blocked`, or `no-agent`).\nThe `Validate` workflow recompiles `test-paper-chaser.md` on CI and fails if\nthe lock file is stale, so pull requests cannot silently drift out of sync.\nThe workflow is \"deployed\" when GitHub Actions sees the committed `.lock.yml`\non the branch where it should run.\n\nSee [SECURITY.md](SECURITY.md) for the public-repo security posture and the\nrecommended private reporting path for vulnerabilities.\n\nFor maintainer orientation after the module split, start with `docs/agent-handoff.md`. The public MCP surface stays in `paper_chaser_mcp/server.py`, while implementation lives in `paper_chaser_mcp/dispatch.py`, `paper_chaser_mcp/search.py`, `paper_chaser_mcp/tools.py`, `paper_chaser_mcp/runtime.py`, `paper_chaser_mcp/models/`, and provider subpackages under `paper_chaser_mcp/clients/`.\n\n## Guides\n\n- [GitHub Copilot Instructions](.github/copilot-instructions.md) - repo-specific guidance for GitHub Copilot and the GitHub cloud coding agent, including workflow defaults and durable planning expectations.\n- [Agent Handoff](docs/agent-handoff.md) - current repo status, validation commands, and next recommended work for follow-on agents.\n- [LLM Selection Guide](docs/llm-selection-guide.md) - planner versus synthesis responsibilities, current smart-layer model defaults, the eval-bootstrap funnel around `generate_eval_topics.py` and `run_eval_autopilot.py`, and criteria for choosing LLMs in this repo.\n- [LLM Evaluation Program Plan](docs/llm-evaluation-program-plan.md) - role-based evaluation strategy, dataset-generation plan, evaluator stack, and phased rollout for rigorous LLM performance measurement in this repo.\n- [LLM Evaluation Dataset Schema](docs/llm-evaluation-dataset-schema.md) - JSONL schema, field rules, governance conventions, and storage layout for role-based evaluation seed sets and future benchmark expansion.\n- [LLM Evaluation Platform Strategy](docs/llm-evaluation-platform-strategy.md) - how to combine repo-local evals with Azure AI Foundry, Hugging Face, and live-trace active-learning loops without losing portability.\n- [LLM Evaluation Trace Promotion](docs/llm-evaluation-trace-promotion.md) - workflow and helper format for promoting reviewed live traces into durable evaluation rows.\n\nOptional live eval-candidate capture can be enabled with `PAPER_CHASER_ENABLE_EVAL_TRACE_CAPTURE=true` and `PAPER_CHASER_EVAL_TRACE_PATH=...`, then converted into a review queue with `scripts/build_eval_review_queue.py` before promotion.\n\nPortable exports for downstream evaluation and training systems are available via `scripts/export_eval_assets.py`, including Foundry-friendly eval JSONL, Hugging Face dataset JSONL, and chat-style training JSONL from review-approved traces.\n\nService-specific publish helpers are available via `scripts/upload_foundry_eval_dataset.py` and `scripts/upload_hf_eval_assets.py` for pushing reviewed exports into a Foundry project dataset, a Hugging Face dataset repo, or a Hugging Face bucket.\n\nExpert batch curation runs can now emit `batch-summary.json` and `batch-ledger.csv` alongside the raw report, captured events, and review queue so offline drift and throughput checks do not depend on replaying the full JSONL artifacts.\n\nFor repo-local eval bootstrap, the current top-level workflow is:\n\n- `scripts/generate_eval_topics.py` for planner-led topic generation, taxonomy assignment, ranking, pruning, balancing, and scenario emission\n- `scripts/run_eval_autopilot.py` for profile-driven generation, immutable run bundles, holdout checks, and guarded workflow handoff\n- `scripts/run_eval_workflow.py` for expert batch capture, review or promotion, dataset splitting, and live provider-matrix evaluation\n\nThe checked-in autopilot sample profiles now include balanced-science defaults plus narrow-run profiles such as `single-seed-exploratory-review`, `single-seed-exploratory-safe`, and `single-seed-diagnostic-force`. Those narrow-run profiles can enable single-seed diversification so one-seed runs ask the planner for additional review, regulatory, and methods-oriented variants instead of depending only on looser workflow thresholds.\n\nSee `docs/llm-evaluation-integrations.md` for the current Foundry and Hugging Face integration posture, including when `hf-mount` is a good fit for a shared capture sink.\n- [Release And Publishing Plan](docs/release-publishing-plan.md) - the current release playbook for GHCR, GitHub Release assets, manual MCP Registry publication, and dormant PyPI.\n- [Guided Reset Migration Note](docs/guided-reset-migration-note.md) - breaking default-surface change, guided-vs-expert split, and client migration checklist.\n- [Paper Chaser Golden Paths](docs/golden-paths.md) - primary personas, workflow defaults, success signals, and future workflow-oriented follow-up work.\n- [Azure Deployment](docs/azure-deployment.md) - deployment modes, required secrets and variables, and validation paths for the private Azure rollout.\n- [Azure Architecture](docs/azure-architecture.md) - trust boundaries, runtime topology, and credential separation for the Azure scaffold.\n- [Azure Security Model](docs/azure-security-model.md) - credential classes, Key Vault usage, and backend-auth separation in the Azure rollout.\n- [Provider Upgrade Program](docs/provider-upgrade-program.md) - provider roles, latency profiles, diagnostics, benchmark corpus, and acceptance gates for the reliability-first provider upgrade.\n- [OpenRouter Provider Guide](docs/openrouter-api-guide.md) - implementation-focused guidance for adding and operating OpenRouter as a chat-only smart-layer provider, including the current Trinity bring-up plan.\n- [ScholarAPI Integration Guide](docs/scholarapi-api-guide.md) - planning guide for adding ScholarAPI as an explicit discovery, monitoring, full-text, and PDF provider without weakening the current graph-oriented provider contracts.\n- [OpenAlex API Guide](docs/openalex-api-guide.md) - implementation-focused guidance for the repo's explicit OpenAlex MCP surface, including authentication, credit-based limits, paging, `/works` semantics, and normalization caveats.\n- [Semantic Scholar API Guide](docs/semantic-scholar-api-guide.md) - practical guidance for respectful and effective Semantic Scholar API usage with async rate limiting, retries, and `.env`-based local development.\n- [SerpApi Google Scholar Guide](docs/serpapi-google-scholar-api-guide.md) - deep research notes on SerpApi capabilities, tradeoffs, and cost/compliance considerations; the repo ships the explicit cited-by, versions, author, account, and citation-format flows documented there.\n- [FastMCP Migration Plan](docs/fastmcp-migration-plan.md) - historical architecture rationale for the FastMCP migration and compatibility surface.\n\n## License\n\nMIT\n\n## Links\n\n### Protocol and runtime\n\n- [Model Context Protocol](https://modelcontextprotocol.io/)\n- [FastMCP](https://gofastmcp.com/)\n- [SerpApi pricing](https://serpapi.com/pricing)\n\n### Scholarly providers\n\n- [Semantic Scholar API](https://api.semanticscholar.org/api-docs)\n- [arXiv API User's Manual](https://info.arxiv.org/help/api/user-manual.html)\n- [CORE API v3 Documentation](https://api.core.ac.uk/docs/v3)\n- [OpenAlex API docs](https://docs.openalex.org/)\n- [ScholarAPI docs](https://scholarapi.net/docs/api)\n- [SerpApi Google Scholar API](https://serpapi.com/google-scholar-api)\n- [Crossref REST API](https://www.crossref.org/documentation/retrieve-metadata/rest-api/)\n- [Unpaywall API](https://unpaywall.org/products/api)\n\n### Regulatory and species sources\n\n- [ECOS](https://ecos.fws.gov/)\n- [FederalRegister.gov API](https://www.federalregister.gov/developers/documentation/api/v1)\n- [GovInfo API](https://api.govinfo.gov/docs/)\n",
  "bytes": 57304,
  "sha": "6100c58b62d5d716bf2e2181acde1f64a0445f88fb13050ea7ad80f245e6c044",
  "repo_slug": "joshuasundance-swca/paper-chaser-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_joshuasundance_swca_paper_chas_3117e897/readme"
}