> ## Documentation Index
> Fetch the complete documentation index at: https://docs.consensus.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Build internal research tools

> How enterprise R&D teams, biotechs, and AI startups connect Consensus paper search to internal assistants, monitoring agents, literature tables, and scientific agents.

Most organizations don't want another research app. They want the literature available *inside* what they already use — the company's ChatGPT or Claude workspace, an in-house model, a Slack bot, a spreadsheet, or the agent they ship to customers. Consensus is the retrieval layer underneath: one search call over 220+ million papers, with filters, pagination, and full-text excerpts.

This guide covers the five things enterprise teams build most, how each maps to the API, and what to get right.

| Build                                                                        | Surface                   | Key parameters                               | Worked example                                                           |
| ---------------------------------------------------------------------------- | ------------------------- | -------------------------------------------- | ------------------------------------------------------------------------ |
| [Internal AI assistant](#connect-paper-search-to-your-internal-ai-assistant) | MCP, or the API as a tool | `query` plus a few filters                   | [Add an evidence layer](/use-cases/add-an-evidence-layer)                |
| [Field-monitoring agent](#keep-on-top-of-a-field)                            | API, scheduled            | `domain`, `year_min`, `month_min`            | [Track new papers on a schedule](/use-cases/scheduled-research-pipeline) |
| [Exhaustive paper list](#pull-an-exhaustive-list-of-papers)                  | API                       | `page`, `page_size`, `publisher_name`        | [PRISMA-ready corpus](/use-cases/prisma-corpus)                          |
| [Literature table](#build-literature-tables-that-fill-themselves)            | API, on demand or synced  | `study_types`, `include_full_text_chunks`    | [Drug target dossier](/use-cases/target-evidence-tiers)                  |
| [Scientific agent](#give-your-scientific-agent-paper-search)                 | MCP or API                | parallel queries, `include_full_text_chunks` | [Parallel search angles](/use-cases/parallel-search-angles)              |

## Connect paper search to your internal AI assistant

This is usually the first thing a team ships, because it takes an afternoon. People already ask the company assistant research questions. Right now it answers from memory; with Consensus attached, it answers from papers and links to them.

**If your company uses ChatGPT or Claude**, add the Consensus connector with the server URL `https://mcp.consensus.app/mcp`. Each employee signs in with their own Consensus account, so their own plan and limits apply. See [Connect MCP](/consensus-mcp) for client-by-client steps.

**If you run your own model or agent framework**, register `GET /v1/search` as a tool. Keep the schema small: a model chooses filters better from five well-described options than from twenty.

```python theme={null}
import os, requests

SEARCH_TOOL = {
    "name": "search_papers",
    "description": (
        "Search 220M+ peer-reviewed research papers. Use for any question whose answer "
        "should rest on published evidence. Returns papers with title, authors, journal, "
        "year, citation count, DOI, and URL. Cite only papers this tool returned."
    ),
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {"type": "string", "description": "A natural-language research question or topic."},
            "year_min": {"type": "integer", "description": "Exclude papers published before this year."},
            "study_types": {"type": "array", "items": {"type": "string"},
                            "description": "Restrict by design, e.g. rct, meta-analysis, systematic review."},
            "human": {"type": "boolean", "description": "Only include human studies."},
            "sjr_max": {"type": "integer", "description": "Worst journal quartile to include. 1 keeps top-quartile journals only."},
        },
        "required": ["query"],
    },
}

FIELDS = ("title", "authors", "journal_name", "publish_year", "citation_count", "doi", "url", "takeaway")

def search_papers(**args):
    resp = requests.get(
        "https://api.consensus.app/v1/search",
        headers={"x-api-key": os.environ["CONSENSUS_API_KEY"]},
        params=args,
        timeout=30,
    )
    resp.raise_for_status()
    # Trim each result so twenty papers fit comfortably in the model's context.
    return [{k: p.get(k) for k in FIELDS} for p in resp.json()["results"]]
```

**What to get right**

* **Tell the model when to use it and how to cite.** Put "cite only papers returned by `search_papers`, with their URL" in the system prompt, and make "the literature does not answer this" an acceptable answer.
* **Return `doi` and `url` on every result** so each claim in the answer can link to its source.
* **Pick the auth model deliberately.** MCP spreads load across each person's account. A shared API key concentrates every employee's searches on one rate limit — one search per second outside Enterprise.

## Keep on top of a field

The request we hear most from corporate research and scouting teams: *tell me what came out this week that matters to me.* A typical example is a team tracking computer vision and robotics that wants an agent per team member, each surfacing new papers on that person's topics and following which authors and labs are publishing where.

<Steps>
  <Step title="Give each person or team a watchlist">
    A watchlist is a handful of queries plus the filters that scope them. Use `domain` to hard-filter by field (`cs`, `eng`, `bio`, `med`, and so on).
  </Step>

  <Step title="Window every run to the last one">
    Set `year_min` and `month_min` to the date of the last successful run, so each run only retrieves what is new.
  </Step>

  <Step title="Diff on DOI and send a digest">
    Store every DOI you have already sent. Each digest is the set difference, ranked by relevance to the watchlist — new papers have no citations yet, so `citation_count` is a poor signal here.
  </Step>

  <Step title="Track authors and institutions over time">
    Every result carries `authors` and `institutions`. Count them across runs to see who is publishing on your topics, where, and when an affiliation changes.
  </Step>
</Steps>

```python theme={null}
import os, time, requests
from collections import Counter

API = "https://api.consensus.app/v1/search"
HEADERS = {"x-api-key": os.environ["CONSENSUS_API_KEY"]}

WATCHLISTS = {
    "alice": [
        {"query": "vision-language-action models for robot manipulation", "domain": "cs,eng"},
        {"query": "sim-to-real transfer for legged locomotion", "domain": "cs,eng"},
    ],
    "bob": [
        {"query": "event cameras for autonomous driving perception", "domain": "cs"},
    ],
}

def digest(person, since, seen_dois):
    fresh = []
    for watch in WATCHLISTS[person]:
        params = {**watch, "year_min": since.year, "month_min": since.month, "page_size": 100}
        resp = requests.get(API, headers=HEADERS, params=params, timeout=30)
        resp.raise_for_status()
        for paper in resp.json()["results"]:
            doi = paper.get("doi")
            if doi and doi not in seen_dois:
                seen_dois.add(doi)
                fresh.append(paper)
        time.sleep(1)                     # one search per second outside Enterprise
    return fresh

fresh = digest("alice", since=last_run, seen_dois=load_seen("alice"))
top_authors = Counter(a for p in fresh for a in p.get("authors") or [])
top_labs = Counter(i for p in fresh for i in p.get("institutions") or [])
```

**What to get right**

* **Keep preprints in for early signal.** Preprints are included unless you set `exclude_preprints=true`, and each result's `is_preprint` flag lets you label them in the digest.
* **`journal_name` boosts, it does not filter.** It surfaces a journal higher but still returns others. To watch specific venues, pass `journal_name` and keep only matching results client-side, or use `publisher_name`, which is a hard filter.
* **Log the empty runs.** A digest with nothing in it is a record worth keeping: it tells "no new papers" apart from "the job broke three weeks ago."

For the scheduled version at scale, see [Track new papers across many topics on a schedule](/use-cases/scheduled-research-pipeline) and [Monitor new research about a drug, device, or brand](/use-cases/brand-and-device-monitoring).

## Pull an exhaustive list of papers

Landscape reviews, due diligence, and building an internal corpus all start with the same request: *give me every paper on this.* One search returns the most relevant page; an exhaustive list means paginating to the end, scoping with hard filters, and covering the topic with more than one phrasing.

```python theme={null}
def sweep(query, **filters):
    page, out = 0, []
    while page <= 49:                              # page is 0-indexed; 49 is the ceiling
        resp = requests.get(API, headers=HEADERS, timeout=30, params={
            "query": query, "page": page,
            "page_size": 1000,                     # clamped to your plan's maximum
            **filters,
        })
        resp.raise_for_status()
        body = resp.json()
        out.extend(body["results"])
        if body["is_end"] or body.get("next_page") is None:
            break
        page = body["next_page"]
        time.sleep(1)
    return out

# Everything in one journal since 2020: boost with journal_name, then filter exactly.
papers = sweep("perovskite solar cell stability", journal_name="Nature Energy", year_min=2020)
in_journal = [p for p in papers if p.get("journal_name") == "Nature Energy"]
```

**What to get right**

* **Scope with hard filters first:** `domain`, `year_min`/`year_max`, `publisher_name`, `country`, `study_types`. They shrink the set before you page through it.
* **Fan out phrasings for recall.** Results are ranked by relevance to one query, so a single phrasing misses papers that use different terminology. Run several phrasings, then deduplicate on `doi`.
* **Check the `page_size` echoed back.** A request above your plan's ceiling is clamped rather than rejected: 300 on Pro and Teams, 750 on Deep, 1,000+ on Enterprise.

The full method, including deduplication and flow counts, is in [Build a PRISMA-ready search corpus](/use-cases/prisma-corpus) and [best practices](/use-cases/best-practices#exhaustive-sweep).

## Build literature tables that fill themselves

Drug discovery and R\&D teams often want a table rather than a chat. Rows are entities — targets, compounds, materials, indications. Columns are the literature questions you ask of every one of them. Each cell is one filtered search, an optional pass over full-text excerpts, and a short cited summary. The table fills in when someone adds a row, or refreshes on a schedule.

```python theme={null}
ROWS = ["PCSK9", "ANGPTL3", "LPA"]

COLUMNS = {
    "human_genetics": dict(
        template="{row} loss-of-function variants cardiovascular outcomes Mendelian randomization",
        human=True,
    ),
    "clinical": dict(
        template="{row} inhibitor randomized controlled trial outcomes",
        study_types=["rct", "meta-analysis"],
    ),
    "safety": dict(
        template="{row} inhibition adverse events safety",
        human=True,
    ),
}

def fill_cell(row, column):
    spec = dict(COLUMNS[column])
    query = spec.pop("template").format(row=row)
    resp = requests.get(API, headers=HEADERS, timeout=30, params={
        "query": query, "include_full_text_chunks": True, **spec,
    })
    resp.raise_for_status()
    papers = resp.json()["results"]
    # Your LLM call: summarize from each paper's full_text_chunks, cite by DOI.
    return summarize_with_citations(row, column, papers)
```

**What to get right**

* **One template per column, not a hand-written query per cell.** Templates are auditable, and when you change one you know exactly which cells to refresh.
* **Keep the papers behind every cell.** Store the DOIs alongside the summary so a reader can click through from any cell to its evidence.
* **Use full-text excerpts for anything quantitative.** `full_text_chunks` (all paid plans) lets a cell carry an effect size or a measured value instead of a paraphrase of the abstract.
* **Refresh incrementally.** On each sync, window with `year_min` and `month_min`, and re-summarize only the cells whose paper set changed.
* **Budget searches before you add rows.** Rows × columns is the number of searches per refresh: 300 targets × 5 columns is 1,500 searches, or about 25 minutes at one per second.

Worked examples: [Build a drug target validation dossier](/use-cases/target-evidence-tiers), [Screen thousands of target-disease pairs](/use-cases/high-throughput-screening), and [Extract numbers from full-text papers](/use-cases/extract-values-from-full-text).

## Give your scientific agent paper search

Biotech and AI startups building scientific agents use Consensus as the agent's literature tool. The agent decides what to search, Consensus returns ranked papers and excerpts, and the agent reasons over them.

<CardGroup cols={2}>
  <Card title="Phylo — REST API, high throughput" img="https://mintcdn.com/consensus-f7e6ffce/bWN8de6MrQCsczek/images/case-studies/phylo.jpg?fit=max&auto=format&n=bWN8de6MrQCsczek&q=85&s=3f96519c11cabad3400d7222e1e7eee3" href="https://consensus.app/home/community-voices/phylo/" width="1200" height="675" data-path="images/case-studies/phylo.jpg">
    Phylo's agents turn each biology question into several parallel search angles, merge the evidence, and distill it into one answer. One team screens about 20,000 targets across hundreds of diseases.
  </Card>

  <Card title="Owkin — MCP, shipped in days" img="https://mintcdn.com/consensus-f7e6ffce/bWN8de6MrQCsczek/images/case-studies/owkin.jpg?fit=max&auto=format&n=bWN8de6MrQCsczek&q=85&s=547fa69e26e6e388143acf59b7ff79cb" href="https://consensus.app/home/community-voices/owkin/" width="1200" height="675" data-path="images/case-studies/owkin.jpg">
    Owkin exposed Consensus to K Pro's orchestrator the same way it exposes its other tools, replacing a curated PubMed-abstract corpus with full-text search.
  </Card>
</CardGroup>

> "It's very robust, with almost zero errors. It gives you genuinely useful results, and it embeds into a high-throughput agentic workflow easily."
>
> — **Kexin Huang**, Co-founder & CEO, Phylo

**Choosing a surface:** use **MCP** if your agent already consumes tools over MCP — it is a tool registration, not a new service. Use the **REST API** when you need pagination, batch workloads, or one shared quota across all your users.

**What to get right**

* **Search several angles per question.** One search per user question is the most common cause of thin answers. Decompose into mechanism, population, outcome, and the contradicting view, and pace the searches to your rate limit.
* **Reason over excerpts, not just abstracts.** `include_full_text_chunks=true` gives the generation step the results paragraphs.
* **Enforce grounding at generation time.** Drop any sentence that has no `doi` or `url` behind it.
* **Benchmark before you switch providers.** Curate queries with known-relevant papers and measure what each provider surfaces — Phylo ranked Consensus first on its own benchmark.

Worked examples: [Add a citable evidence layer to an agent](/use-cases/add-an-evidence-layer), [Answer one question with many parallel searches](/use-cases/parallel-search-angles), [Swap a hand-maintained paper corpus](/use-cases/swap-a-paper-corpus), and [Benchmark literature providers](/use-cases/benchmark-retrieval).

## Before you roll it out

<AccordionGroup>
  <Accordion title="Rate limits" icon="gauge">
    One search per second on every plan except Enterprise, where limits are custom. Pace fan-outs and scheduled jobs, honour `retry-after` on a 429, and add jitter. See [rate limits and result caps](/use-cases/best-practices#rate-limits-and-result-caps).
  </Accordion>

  <Accordion title="Result caps and full text" icon="layers">
    `page_size` caps at 300 on Pro and Teams, 750 on Deep, and 1,000+ on Enterprise. Query-relevant full-text excerpts (`include_full_text_chunks`) are available on all paid plans.
  </Accordion>

  <Accordion title="Per-user or shared auth" icon="key">
    MCP authenticates each person with OAuth, so their own plan applies. The API uses one `x-api-key` for the whole integration — simpler to operate, but every user shares its limits.
  </Accordion>

  <Accordion title="Caching and audit" icon="clipboard-list">
    Cache on the full parameter set with a short TTL so new papers still land. Log every query, its filters, and the DOIs returned — it makes answers auditable and debugging far faster.
  </Accordion>
</AccordionGroup>

<Tip>
  Building something your whole organization will use? An Enterprise trial gives you the higher limits and larger result pages to build without hitting ceilings. [Talk to us](https://consensus.app/home/api).
</Tip>

## Related

<CardGroup cols={2}>
  <Card title="Build custom research systems" icon="graduation-cap" href="/use-cases/research-systems">
    The academic counterpart: literature reviews, writing, and reports.
  </Card>

  <Card title="Best practices" icon="shapes" href="/use-cases/best-practices">
    Fan-out, the filter ladder, exhaustive sweeps, and grounding rules.
  </Card>

  <Card title="Search endpoint reference" icon="sliders-horizontal" href="/api-reference/query-for-relevant-papers">
    Every filter and response field, with an interactive playground.
  </Card>

  <Card title="Use case library" icon="layout-grid" href="/use-cases/gallery">
    30 worked examples you can filter by persona.
  </Card>
</CardGroup>
