Skip to main content
Glama
rdwj

NIH RePORTER MCP Server

by rdwj

NIH RePORTER MCP Server

An MCP server that wraps the NIH RePORTER API v2, enabling AI agents to search and analyze NIH-funded research projects and their linked publications. No API key required.

Tools

Tool

Description

nih_search_projects

Search for NIH research projects by text, PI, organization, funding, and more

nih_get_project

Get full details for a specific project by application ID or project number

nih_find_publications

Find PubMed publications linked to NIH grants

nih_search_projects

Search the NIH RePORTER database for federally funded research projects. Multiple criteria are combined with AND logic; within list parameters, values use OR logic.

Parameters:

  • text (string, optional): Free-text search across titles, abstracts, and terms

  • text_operator ("and" | "or", default "and"): How multi-word queries are combined

  • text_fields ("all" | "title" | "abstract" | "terms", default "all"): Which fields to search

  • pi_name (string, optional): PI name, e.g. "Smith, John" or "Smith"

  • organization (string, optional): Organization name (partial match)

  • activity_codes (list of string, optional): e.g. ["R01", "R21"]

  • agencies (list of string, optional): NIH IC abbreviations, e.g. ["NCI", "NIMH"]

  • fiscal_years (list of int, optional): e.g. [2024, 2025]

  • funding_mechanism (list of string, optional): e.g. ["RP", "SB"]

  • spending_categories (list of int, optional): RCDC category IDs

  • states (list of string, optional): US state abbreviations

  • award_amount_min / award_amount_max (int, optional): Dollar range

  • project_start_after / project_start_before (string, optional): YYYY-MM-DD

  • exclude_subprojects (bool, default true): Exclude subprojects

  • include_active_only (bool, default false): Only active projects

  • detail_level ("summary" | "full", default "summary"): Summary returns key fields; full includes abstracts

  • sort_by ("relevance" | "date" | "amount", default "relevance"): Sort order

  • limit (int, default 10, max 50): Results per page

  • offset (int, default 0): Pagination offset

  • search_id (string, optional): Reuse a prior search for pagination

Example:

{
  "text": "machine learning",
  "agencies": ["NIGMS"],
  "activity_codes": ["R01"],
  "fiscal_years": [2025],
  "limit": 5
}

nih_get_project

Get full details for a specific NIH-funded project. Use after finding a project of interest via nih_search_projects.

Parameters:

  • appl_id (int, optional): Application ID, e.g. 10878415

  • project_num (string, optional): Full project number, e.g. "5R01CA123456-03"

One of appl_id or project_num is required.

Example:

{"appl_id": 10878415}

nih_find_publications

Find PubMed publications linked to NIH-funded projects. Returns PMIDs that can be used with PubMed APIs for full citation details.

Parameters:

  • core_project_nums (list of string, optional): e.g. ["R01CA123456"]. Supports wildcard *.

  • appl_ids (list of int, optional): Application IDs

  • pmids (list of int, optional): PubMed IDs (reverse lookup: which grants funded this paper?)

  • limit (int, default 50, max 500): Results per page

  • offset (int, default 0): Pagination offset

At least one of the search parameters is required.

Example:

{"core_project_nums": ["R01CA123456"]}

Related MCP server: NIH Reporter MCP Server

Quick Start

Local Development

make install
make run-local

# Test with cmcp (in another terminal)
cmcp ".venv/bin/python -m src.main" tools/list

Deploy to OpenShift

make deploy PROJECT=my-project

Client Configuration

STDIO (local):

{
  "mcpServers": {
    "nih-reporter": {
      "command": ".venv/bin/python",
      "args": ["-m", "src.main"]
    }
  }
}

HTTP (remote):

{
  "mcpServers": {
    "nih-reporter": {
      "url": "https://<route>/mcp/"
    }
  }
}

Development

Running Tests

make test

# Or directly
.venv/bin/pytest tests/ -v

# Single test file
.venv/bin/pytest tests/tools/test_nih_search_projects.py -v

Adding Tools

Create a Python file in src/tools/ using the @mcp.tool decorator:

from typing import Annotated
from pydantic import Field
from fastmcp import Context
from fastmcp.exceptions import ToolError
from src.core.app import mcp

@mcp.tool(
    annotations={"readOnlyHint": True, "openWorldHint": True},
    timeout=30.0,
)
async def my_tool(
    param: Annotated[str, Field(description="Parameter description")],
    ctx: Context = None,
) -> dict:
    """Tool description for the LLM."""
    return {"result": param}

Generate scaffolds with:

fips-agents generate tool my_tool --description "Tool description" --async --with-context

Project Structure

src/
├── core/
│   ├── app.py          # Shared FastMCP instance
│   ├── server.py       # Server bootstrap (load + run)
│   ├── loaders.py      # Dynamic component discovery
│   ├── auth.py         # Optional JWT authentication
│   └── logging.py      # Logging configuration
├── tools/
│   ├── nih_client.py          # Shared HTTP client with rate limiting
│   ├── nih_search_projects.py # Project search tool
│   ├── nih_get_project.py     # Project detail tool
│   └── nih_find_publications.py # Publication search tool
├── resources/          # (none currently)
├── prompts/            # (none currently)
└── middleware/         # (none currently)
tests/
└── tools/
    ├── test_nih_search_projects.py  # 55 tests
    ├── test_nih_get_project.py      # 8 tests
    └── test_nih_find_publications.py # 9 tests

Dependencies

  • fastmcp >= 2.11.3 -- MCP server framework

  • httpx >= 0.28.0 -- Async HTTP client for NIH API calls

Environment Variables

Variable

Default

Purpose

MCP_TRANSPORT

stdio

Transport: stdio or http

MCP_HTTP_HOST

127.0.0.1

HTTP bind address

MCP_HTTP_PORT

8000

HTTP port

MCP_HTTP_PATH

/mcp/

HTTP endpoint path

MCP_LOG_LEVEL

INFO

Logging level

MCP_HOT_RELOAD

0

Enable hot-reload for development

MCP_SERVER_NAME

fastmcp-unified

Server name in MCP responses

NIH API Notes

  • No authentication required. The API is publicly accessible.

  • Rate limit: 1 request per second (enforced by the shared client).

  • Result limit: The API can return at most 15,000 records per search. The tool warns when this limit is hit.

  • Documentation: api.reporter.nih.gov

License

This project is licensed under the MIT License.

Available Tools

3 tools
nih_find_publicationsNih Find PublicationsA
Read-only

Find publications linked to NIH-funded projects.

Returns PubMed IDs (PMIDs) associated with grants. Search by core project number (e.g. 'R01CA123456', supports wildcard *), application ID, or PubMed ID. Use PMIDs with PubMed APIs for full citation details. Note: publication linkage may lag behind award dates.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum results to return.
pmidsNoPubMed IDs — find which NIH grants funded a known publication.
offsetNoStarting position for pagination.
appl_idsNoApplication IDs to search for linked publications.
core_project_numsNoCore project numbers to search. Example: ['R01CA123456']. Supports wildcard * for partial matching.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and openWorldHint, so the safety profile is covered. The description adds genuinely useful domain behavior beyond the annotations: results are PMIDs only, and 'publication linkage may lag behind award dates' — a real caveat an agent should know before interpreting sparse results.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight paragraphs, front-loaded with purpose, then return value and search keys, then the caveat. Every sentence carries information and nothing is padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter, all-optional search tool with a full output schema and read-only annotations, the description says everything needed: what it returns, the three search dimensions, the downstream handoff to PubMed, and the data-lag caveat. Return-value and pagination details are appropriately delegated to the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3, but the description adds framing the schema lacks: the reverse-lookup purpose of pmids ('find which grants funded a known publication') and the worked example/wildcard note for core_project_nums. It enriches meaning rather than just restating fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Find publications linked to NIH-funded projects') and pins down the output (PubMed IDs/PMIDs). It is clearly distinguishable from the sibling tools nih_search_projects and nih_get_project, which operate on projects rather than publications.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the accepted search keys (core project number, application ID, or PubMed ID) and tells the agent to pass PMIDs on to PubMed APIs for citation details. It gives clear context for use but does not explicitly state when to prefer this tool over the sibling project tools or note exclusion conditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

nih_get_projectNih Get ProjectA
Read-only

Get full details for a specific NIH-funded project.

Use this after finding a project of interest via nih_search_projects. Accepts either an application ID (numeric, e.g. 10878415) or a full project number (e.g. '5R01CA123456-03'). Returns the complete record including abstract, all PIs, funding breakdown, and study section.

ParametersJSON Schema
NameRequiredDescriptionDefault
appl_idNoApplication ID — unique numeric identifier for an NIH grant application. Example: 10878415
project_numNoFull NIH project number. Example: '5R01CA123456-03'. Format: type + activity + IC + serial + year.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds useful behavioral context — it accepts either an appl_id or a project_num, and it enumerates the returned content (abstract, all PIs, funding breakdown, study section). It doesn't mention auth, rate limits, or error behavior, keeping it short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the core purpose and then the routing guidance. No filler; every sentence carries a distinct fact.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values needn't be re-explained, yet the description still summarizes the payload. With annotations covering safety and 100% schema coverage, nothing an agent needs to invoke this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are already fully documented in the schema with the same example values the description repeats. The description's 'accepts either' phrasing adds mild value by implying the two identifiers are alternatives, but otherwise the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Get full details') and resource ('a specific NIH-funded project'), and clearly demarcates itself from the sibling search tool. An agent can tell it apart from nih_search_projects without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states the workflow condition: 'Use this after finding a project of interest via nih_search_projects,' naming the alternative and when to reach for it. This is exactly the retrieval-after-search routing guidance an agent needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

nih_search_projectsNih Search ProjectsA
Read-only

Search the NIH RePORTER database for federally funded research projects.

NIH RePORTER (Research Portfolio Online Reporting Tools) provides access to data on all research projects funded by the National Institutes of Health. This includes grants, contracts, and intramural projects across all 27 NIH institutes and centers.

Text search supports multi-word queries. With text_operator="and" (default), all words must appear in the searched fields. With "or", any word matching is sufficient. Wrap phrases in quotes for exact phrase matching within the text parameter.

Multiple criteria are combined with AND logic (e.g., text + agency narrows results to projects matching both). Within list parameters like agencies or activity_codes, values use OR logic.

Common activity codes: R01 - Research Project Grant (most common) R21 - Exploratory/Developmental Research R03 - Small Research Grant P01 - Program Project Grant U01 - Research Project Cooperative Agreement K01 - Mentored Research Scientist Career Development K08 - Mentored Clinical Scientist Career Development K23 - Mentored Patient-Oriented Research Career Development T32 - Institutional Training Grant F31 - Predoctoral Fellowship F32 - Postdoctoral Fellowship

Common agency abbreviations: NCI (Cancer), NIMH (Mental Health), NIGMS (General Medical Sciences), NIAID (Allergy/Infectious Diseases), NHLBI (Heart/Lung/Blood), NIA (Aging), NINDS (Neurological Disorders), NIDA (Drug Abuse), NICHD (Child Health), NIDDK (Diabetes/Digestive/Kidney)

ParametersJSON Schema
NameRequiredDescriptionDefault
textNoFree-text search across project titles, abstracts, and terms. Supports multi-word queries; word matching is controlled by text_operator.
limitNoMaximum number of results to return (1-50).
offsetNoStarting index for pagination. Use with search_id to page through results.
statesNoUS state abbreviations for organization location. Example: ["CA", "MA", "NY"].
pi_nameNoPrincipal Investigator name. Use "Last, First" for exact matching or a single name for broad matching. Partial names are supported (implicitly wildcarded).
sort_byNoSort order for results. 'relevance' ranks by text match quality (best with text searches), 'date' by project start date descending, 'amount' by award amount descending.relevance
agenciesNoNIH institute/center abbreviations. Examples: NCI, NIMH, NIGMS, NIAID, NHLBI, NIA, NINDS, NIDA, NICHD, NIDDK, NEI, NIBIB, NIEHS, NHGRI, NCATS, FIC, NLM, NCCIH.
search_idNoReuse a previous search_id to page through an existing result set without re-specifying criteria. Returned in every search response.
text_fieldsNoWhich text fields to search. 'all' searches titles, abstracts, and terms. 'title', 'abstract', or 'terms' restricts to that single field.all
detail_levelNo'summary' returns key fields (title, PI, org, amount, dates). 'full' returns all available fields including abstracts.summary
fiscal_yearsNoFiscal years to include. NIH fiscal year runs Oct 1 - Sep 30. Example: [2024, 2025].
organizationNoResearch organization name (implicitly wildcarded). Example: "Johns" matches "Johns Hopkins University".
text_operatorNoHow multi-word text queries are combined. "and" requires all words to appear (default), "or" matches any word.and
activity_codesNoNIH activity codes to filter by. Common codes: R01 (Research Project), R21 (Exploratory), R03 (Small Grant), P01 (Program Project), U01 (Cooperative Agreement), K01/K08/K23 (Career Development), T32 (Training Grant), F31/F32 (Fellowship).
award_amount_maxNoMaximum award amount in dollars.
award_amount_minNoMinimum award amount in dollars.
funding_mechanismNoFunding mechanism codes: RP (Research Projects), SB (SBIR/STTR), RC (Research Centers), OR (Other Research), TR (Training Individual), TI (Training Institutional), CO (Construction).
exclude_subprojectsNoExclude subprojects from results. Usually True to avoid duplicate counting of large program projects.
include_active_onlyNoWhen True, only return currently active projects.
project_start_afterNoFilter to projects starting on or after this date. Format: YYYY-MM-DD.
spending_categoriesNoRCDC spending category IDs (OR logic). Common IDs: 132 (Cancer), 140 (Cardiovascular), 224 (Diabetes), 284 (HIV/AIDS), 338 (Infectious Diseases), 443 (Mental Health), 525 (Neurosciences), 4372 (Machine Learning/AI), 4531 (Data Science).
project_start_beforeNoFilter to projects starting on or before this date. Format: YYYY-MM-DD.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=true and openWorldHint=true, so the safety profile is already covered. The description adds useful behavioral context: AND/OR combination logic, exact phrase quoting, and that search_id enables paging without re-specifying criteria. It does not mention rate limits, result caps, or anything beyond the schema. With annotations carrying the safety burden, this is adequate but not rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The opening is front-loaded and clear, but the large inline reference lists for activity codes and agencies are bulky and partially duplicate the schema descriptions (which already list common codes). It is informative but not tightly structured; the code lists could be seen as padding since the schema already covers many of them.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 22-parameter read-only search tool with an output schema present, the description covers query semantics, value conventions, and paging via search_id. It is largely complete; the main gap is the absence of guidance on choosing between this tool and its siblings, but return values are covered by the output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds genuine value beyond the schema by supplying the common activity code and agency abbreviation reference tables, which help the agent construct valid values for those parameters. That elevates it above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states a specific verb and resource: search the NIH RePORTER database for federally funded research projects. It provides rich scope detail (grants, contracts, intramural, 27 institutes). It does not, however, differentiate itself from the sibling nih_get_project or explain how it relates to it, so it falls short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains query semantics (AND across criteria, OR within lists, text_operator behavior) which implicitly guides usage, but it never states when to use this search tool versus nih_get_project or nih_find_publications. No explicit when/when-not guidance or named alternatives are given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.4.0
    • First observednih_find_publications
    • First observednih_get_project
    • First observednih_search_projects

TDQS

A4.2/5.0

Scored across 3 tools

Disambiguation5/5

The three tools have clearly distinct purposes: searching for projects, retrieving full project details, and finding linked publications. Each tool's description clarifies its specific role, leaving no ambiguity for an agent to choose the appropriate tool.

Naming Consistency5/5

All tool names follow a consistent snake_case convention with a common 'nih_' prefix and verb_noun structure: nih_search_projects, nih_get_project, nih_find_publications. This pattern is predictable and easy to parse.

Tool Count5/5

With only 3 tools, the set is minimal but well-scoped for the core read-only operations of the NIH RePORTER database. Each tool serves a distinct essential function without overlap or redundancy.

Completeness4/5

The tools cover the primary read operations: search, detail retrieval, and publication linkage. However, there is no support for listing related entities (e.g., all projects by a PI or organization) or exporting results, which could be useful but are not critical for the stated purpose.

Maintenance

ActivityInactive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Enables AI assistants to search and retrieve biomedical research articles from PubMed's database of over 35 million citations, including metadata, abstracts, MeSH terms, and full-text PDFs when available.
    1
    1
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides programmatic access to the NIH Reporter API for searching and retrieving detailed information on NIH-funded research projects, grants, and investigators. It enables AI assistants to query project abstracts, funding amounts, and organization details through natural language.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to search and retrieve EU research outputs including publications, datasets, software, and funded projects from OpenAIRE.
    3 npm
    MIT