Skip to main content
Glama

search_publications

Find publications associated with NIH-funded projects by entering PubMed IDs or core project numbers. Retrieve up to 50 results per query for efficient research tracking.

Instructions

Search for publications linked to NIH projects Args: pmids: Comma-separated list of PubMed IDs core_project_nums: Comma-separated list of NIH core project numbers limit: Maximum number of results to return (default: 10, max: 50)

Input Schema

NameRequiredDescriptionDefault
core_project_numsNo
limitNo
pmidsNo

Input Schema (JSON Schema)

{ "properties": { "core_project_nums": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Core Project Nums" }, "limit": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": 10, "title": "Limit" }, "pmids": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Pmids" } }, "title": "search_publicationsArguments", "type": "object" }

Implementation Reference

  • The main handler function for the search_publications tool, registered via @mcp.tool(). It processes input parameters (pmids, core_project_nums, limit), constructs search criteria, calls the helper get_publications method, and formats results using format_publication_results.
    @mcp.tool() async def search_publications( pmids: Optional[str] = None, core_project_nums: Optional[str] = None, limit: Optional[int] = 10 ) -> str: """ Search for publications linked to NIH projects Args: pmids: Comma-separated list of PubMed IDs core_project_nums: Comma-separated list of NIH core project numbers limit: Maximum number of results to return (default: 10, max: 50) """ try: logger.info(f"Publication search request received with parameters: {locals()}") criteria = {} # Handle PMIDs if pmids: pmid_list = [pmid.strip() for pmid in pmids.split(",")] criteria["pmids"] = pmid_list # Handle core project numbers if core_project_nums: logger.info(f"Processing core_project_nums input: {core_project_nums}") # Clean the input string of any quotes clean_input = core_project_nums.strip().strip('"').strip("'") logger.info(f"Cleaned input: {clean_input}") proj_list = [num.strip() for num in clean_input.split(",")] logger.info(f"Created project list: {proj_list}") criteria["core_project_nums"] = proj_list # Ensure limit is within bounds criteria["limit"] = min(max(1, limit), 50) logger.info(f"Constructed publication search criteria: {json.dumps(criteria, indent=2)}") results = await api_client.get_publications({"criteria": criteria}) return api_client.format_publication_results(results) except Exception as e: logger.error(f"Publication search failed: {str(e)}", exc_info=True) return f"Publication search failed: {str(e)}\nPlease check the logs for more details."
  • Supporting utility in NIHReporterClient class that handles the HTTP POST to NIH RePORTER /publications/search endpoint, enriches results with PubMed E-summary data for titles, authors, etc.
    async def get_publications(self, criteria: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: """Get publications from NIH RePORTER API""" logger.info(f"Fetching publications from NIH RePORTER with criteria: {criteria}") async with httpx.AsyncClient() as client: # Construct the payload according to API specification payload = { "criteria": criteria.get("criteria", {}), "limit": criteria.get("limit", 50), "offset": criteria.get("offset", 0), "sort_field": criteria.get("sort_field", "core_project_nums"), "sort_order": criteria.get("sort_order", "desc") } # Add publication years if specified if "publication_years" in criteria.get("criteria", {}): payload["criteria"]["publication_years"] = criteria["criteria"]["publication_years"] logger.debug(f"Sending payload to NIH Publications API: {json.dumps(payload, indent=2)}") try: response = await client.post( f"{API_BASE}/publications/search", headers=self.headers, json=payload ) response.raise_for_status() response_data = response.json() # If we got PMIDs, fetch the full publication details from PubMed if response_data.get("results"): pmids = [str(result.get("pmid")) for result in response_data["results"] if result.get("pmid")] if pmids: async with httpx.AsyncClient() as pubmed_client: # Use E-utilities to get full publication details pubmed_url = f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id={','.join(pmids)}&retmode=json" pubmed_response = await pubmed_client.get(pubmed_url) pubmed_data = pubmed_response.json() # Update our results with PubMed data for result in response_data["results"]: if result.get("pmid"): pmid = str(result["pmid"]) if pmid in pubmed_data.get("result", {}): pub_details = pubmed_data["result"][pmid] result.update({ "title": pub_details.get("title", ""), "authors": [author.get("name", "") for author in pub_details.get("authors", [])], "journal_title": pub_details.get("fulljournalname", ""), "publication_year": pub_details.get("pubdate", "").split()[0] if pub_details.get("pubdate") else None }) logger.debug(f"Received response: {json.dumps(response_data, indent=2)}") return response_data except httpx.HTTPStatusError as e: logger.error(f"HTTP error occurred: {e.response.status_code} - {e.response.text}") raise except json.JSONDecodeError as e: logger.error(f"Failed to parse API response: {e}") logger.error(f"Raw response: {response.text}") raise except Exception as e: logger.error(f"Unexpected error during API call: {str(e)}") raise
  • Supporting utility that converts raw publication API results into formatted Markdown output with details like title, authors, PMID, links to PubMed/DOI, and related projects.
    def format_publication_results(self, results: Dict[str, Any], include_projects: bool = False) -> str: """Format publication results into markdown string with optional project links""" logger.debug(f"Formatting publication results: {json.dumps(results, indent=2)}") if not results.get("results"): logger.info("No publications found in API response") return "No publications found." try: formatted_results = [] for pub in results["results"]: # Format authors safely authors = pub.get('authors', []) author_str = ", ".join(authors) if authors else "N/A" pub_info = [ f"### {pub.get('title', 'Untitled Publication')}", "", f"**Authors:** {author_str}", f"**PMID:** `{pub.get('pmid', 'N/A')}`", f"**Core Project Number:** `{pub.get('core_project_num', 'N/A')}`" ] # Add publication year if available if pub.get('publication_year'): pub_info.append(f"**Publication Year:** {pub['publication_year']}") # Add journal info if available if pub.get('journal_title'): pub_info.append(f"**Journal:** {pub['journal_title']}") # Add DOI if available if pub.get('doi'): pub_info.append(f"**DOI:** [{pub['doi']}](https://doi.org/{pub['doi']})") # Add project links if available if pub.get('core_project_num'): pub_info.extend([ "", "#### Related NIH Projects", f"- Core Project: `{pub['core_project_num']}`" ]) pub_info.extend(["", "---", ""]) formatted_results.append("\n".join(filter(None, pub_info))) total = f"# NIH RePORTER Publication Results\n\n**Total matching publications:** {results.get('meta', {}).get('total', 0)}" return f"{total}\n\n" + "\n".join(formatted_results) except Exception as e: logger.error(f"Error formatting publication results: {str(e)}") logger.error(f"Results that caused error: {json.dumps(results, indent=2)}") raise
  • The @mcp.tool() decorator registers the search_publications function as an MCP tool.
    @mcp.tool()

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jbdamask/mcp-nih-reporter'

If you have feedback or need assistance with the MCP directory API, please join our Discord server