Skip to main content
Glama

get_full_text

Retrieve open-access full text articles from PubMed Central using PubMed IDs. Returns complete article content when available or provides alternative access information.

Instructions

Retrieve the full text of an article from PubMed Central (PMC) if available.

Only open-access articles archived in PMC have a full text. Subscription-only articles will return a link to PubMed instead.

Args: pmid: The PubMed ID of the article.

Returns: The full text (title, abstract, and body sections) when the article is open-access in PMC, or a helpful message with links otherwise.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pmidYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • main.py:444-539 (handler)
    The `get_full_text` function is decorated with `@mcp.tool()` and implements the logic to fetch full-text content from PubMed Central (PMC) based on a provided PubMed ID (PMID). It first retrieves the PMC ID from the PubMed record and then fetches the full text from PMC if it's available.
    @mcp.tool()
    async def get_full_text(pmid: str) -> str:
        """Retrieve the full text of an article from PubMed Central (PMC) if available.
    
        Only open-access articles archived in PMC have a full text.
        Subscription-only articles will return a link to PubMed instead.
    
        Args:
            pmid: The PubMed ID of the article.
    
        Returns:
            The full text (title, abstract, and body sections) when the article
            is open-access in PMC, or a helpful message with links otherwise.
        """
        pmid = pmid.strip()
        if not pmid.isdigit():
            return _err(f"Invalid PMID: {pmid!r}. A PMID must be a numeric string.")
    
        try:
            # 1) Retrieve the PubMed record to find the PMC ID
            fetch_resp = await _get(
                "efetch.fcgi",
                {"db": "pubmed", "id": pmid, "retmode": "xml", "rettype": "abstract"},
            )
            root = _require_xml(fetch_resp, f"efetch PMID {pmid}")
            article_xml = root.find(".//PubmedArticle")
    
            if article_xml is None:
                return _err(f"No article found for PMID {pmid}.")
    
            pmc_id: Optional[str] = None
            for id_el in article_xml.findall(".//ArticleId"):
                if id_el.get("IdType") == "pmc" and id_el.text:
                    pmc_id = id_el.text.strip()
                    break
    
            if not pmc_id:
                title_el = article_xml.find(".//ArticleTitle")
                title = "".join(title_el.itertext()).strip() if title_el is not None else ""
                msg = [f"Full text not available in PubMed Central for PMID {pmid}."]
                if title:
                    msg.append(f"Title: {title}")
                msg.append(
                    "The article may be subscription-only or not yet indexed in PMC.\n"
                    f"PubMed page: https://pubmed.ncbi.nlm.nih.gov/{pmid}/"
                )
                return "\n".join(msg)
    
            # 2) Fetch full-text XML from PMC
            numeric_id = pmc_id.replace("PMC", "")
            pmc_resp = await _get(
                "efetch.fcgi",
                {"db": "pmc", "id": numeric_id, "retmode": "xml", "rettype": "full"},
            )
    
            try:
                pmc_root = ET.fromstring(pmc_resp.text)
            except ET.ParseError as exc:
                return (
                    f"Full text is available in PMC but could not be parsed.\n"
                    f"Reason: {exc}\n"
                    f"PMC URL: https://www.ncbi.nlm.nih.gov/pmc/articles/{pmc_id}/"
                )
    
            sections: list[str] = []
    
            title_el = pmc_root.find(".//article-title")
            if title_el is not None:
                sections.append(f"TITLE\n{''.join(title_el.itertext()).strip()}\n")
    
            abstract_el = pmc_root.find(".//abstract")
            if abstract_el is not None:
                sections.append("ABSTRACT\n" + "".join(abstract_el.itertext()).strip() + "\n")
    
            body = pmc_root.find(".//body")
            if body is not None:
                for sec in body.findall(".//sec"):
                    title_el = sec.find("title")
                    if title_el is not None:
                        sections.append(f"\n{''.join(title_el.itertext()).upper()}")
                    for p in sec.findall("p"):
                        para = "".join(p.itertext()).strip()
                        if para:
                            sections.append(para)
    
            if not sections:
                return (
                    f"Full text is available in PMC but the content could not be extracted.\n"
                    f"PMC URL: https://www.ncbi.nlm.nih.gov/pmc/articles/{pmc_id}/"
                )
    
            header = f"=== Full Text — PMID {pmid} | {pmc_id} ===\n"
            return header + "\n".join(sections)
    
        except PubMedError as exc:
            return _err(str(exc))
Behavior4/5

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

With no annotations provided, the description carries full burden and successfully discloses dual-output behavior (full text with structure 'title, abstract, and body sections' vs 'helpful message with links'), and the PMC open-access constraint. Lacks mention of rate limits, caching, or authentication requirements.

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?

Uses standard docstring format (Args/Returns) that is appropriate for the documentation burden. Every sentence serves a distinct purpose: capability statement, constraint warning, fallback behavior, parameter definition, and return value specification. No redundancy.

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 single-parameter tool with conditional output logic, the description is comprehensive. It explains the parameter (since schema fails to), documents both success and failure response patterns, and clarifies content scope (PMC open-access only) without needing to duplicate the output schema structure.

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?

Compensates effectively for 0% schema description coverage by defining the 'pmid' parameter as 'The PubMed ID of the article,' providing essential semantic mapping. Would benefit from format hints (e.g., numeric string) or validation constraints to achieve a 5.

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?

The description opens with a specific verb ('Retrieve') and resource ('full text of an article from PubMed Central'), clearly distinguishing it from siblings like 'get_article' (likely metadata) and 'search_pubmed' (discovery). The 'if available' qualifier immediately signals the conditional nature of this operation.

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?

Explicitly defines scope limitations ('Only open-access articles archived in PMC') and failure mode behavior ('Subscription-only articles will return a link'), guiding users on when the tool will and won't return full text. Lacks explicit cross-reference to sibling tools (e.g., 'use get_article for metadata-only retrieval').

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

Install Server

Other 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/benoitleq/mcp-pubmed'

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