@cyanheads/pubmed-mcp-server
Version:
Search PubMed/Europe PMC, fetch articles and full text (PMC/EPMC/Unpaywall), citations, MeSH terms via MCP. STDIO or Streamable HTTP.
53 lines • 2.7 kB
TypeScript
/**
* @fileoverview Handles parsing of NCBI E-utility responses and NCBI-specific error extraction.
* Creates an NCBI-specific XMLParser instance with `isArray` callback support for handling
* NCBI's inconsistent XML structures where single-element lists are collapsed to scalars.
* @module src/services/ncbi/response-handler
*/
import type { NcbiRequestOptions } from './types.js';
/**
* Flattens inline mixed-content markup (`<sup>`, `<sub>`, `<inf>`, `<i>`,
* `<b>`, `<u>`, `<sc>`) inside PubMed/MEDLINE XML before fast-xml-parser
* runs. The non-ordered parser used for EFetch responses doesn't preserve
* mixed content — `1.73 m<sup>2</sup>` parses to `{ '#text': '1.73 m', sup:
* 2 }`, and `extractAbstractText` only reads `#text`, so the superscript
* digit is silently dropped from abstracts and titles.
*
* Numeric and operator characters map to Unicode (²/³/⁻²/₂…); anything else
* falls back to a `^X` / `_X` ASCII prefix so the content survives in a
* recognizable form. Italic / bold / underline / small-caps tags are
* stripped (content kept) since they don't carry meaning in our text
* rendering. Only invoked on the regular parser path; the PMC JATS path
* already preserves inline markup via `preserveOrder: true`.
*
* @internal exported for direct unit tests
*/
export declare function flattenInlineMarkup(xml: string): string;
/**
* Parses NCBI E-utility responses (XML, JSON, text) and checks for NCBI-specific
* error structures embedded in response bodies.
*/
export declare class NcbiResponseHandler {
private readonly xmlParser;
/**
* Parser configured for JATS mixed content (PMC full-text). `preserveOrder`
* keeps document order so inline markup in `<p>`, `<abstract>`, `<title>`
* doesn't collapse into reordered text. `trimValues: false` retains spacing
* between text nodes and adjacent inline children.
*/
private readonly orderedXmlParser;
constructor();
/**
* Extract a structured error from a parsed NCBI XML body and throw it as
* `notFound()` for permanent "no such record" responses or `serviceUnavailable()`
* for transient backend failures. Never returns.
*
* NCBI returns "cannot get document summary" / "Empty id list" for invalid
* UIDs — these are permanent (the record doesn't exist), so we surface them
* as NotFound so the retry loop short-circuits instead of hammering NCBI.
*/
private throwNcbiError;
extractNcbiErrorMessages(parsedXml: Record<string, unknown>): string[];
parseAndHandleResponse<T>(responseText: string, endpoint: string, options?: NcbiRequestOptions): T;
}
//# sourceMappingURL=response-handler.d.ts.map