eutils-mcp-server
Provides read-only access to PubMed (and other NCBI Entrez databases) through the E-utilities, letting a model search biomedical literature, translate queries, retrieve UIDs, fetch abstracts and full records, follow links between Entrez databases, and use the History server for batched retrieval.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@eutils-mcp-serverfind papers about CRISPR delivery in 2024 and show me the abstracts"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
eutils-mcp-server
中文 · English
MCP server exposing the nine NCBI Entrez E-utilities as eleven read-only tools.
It gives a language model the E-utilities directly, so it can search biomedical
literature, fetch sequences, and follow links between Entrez databases without a browser
and without scraping. The repository folder is named E-utilities after the API it
wraps. The package, the server name, and the GitHub repository are all
eutils-mcp-server.
Use it when you want an answer, not a dataset. A question such as "find papers about CRISPR delivery in 2024 and show me the abstracts" is the intended shape. Do not use it for bulk download: NCBI asks that bulk data mining use the local PubMed copy instead, and this server obeys NCBI's rate limit, so a large job takes days. Do not use it to change anything, because it is read-only and NCBI exposes no write path through these utilities.
Table of Contents
Related MCP server: PubMed MCP Server
Background
The Entrez Programming Utilities are a set of nine server-side programs at the National Center for Biotechnology Information. They share one URL syntax and cover 38 databases, including PubMed, PMC, Protein, Nucleotide, Gene, SNP, Structure, and Taxonomy. NCBI documents them in the E-utilities manual.
That interface is stable but awkward for a model to drive directly. Every request needs the same credentials, the same encoding, and the same knowledge of which endpoints accept which output formats. Batch retrieval needs the History server, which carries state across calls. NCBI blocks an IP that exceeds its rate limit.
This server puts those details in code. One client builds every URL, paces every request, follows redirects within an allowlist, caps response size, and redacts the API key. Each tool then maps one operation to one E-utilities call and returns a result the model can read.
Two upstream facts shaped the design. EGQuery is unreachable from the public internet, and the ESummary JSON limit is 500 records rather than the 10,000 the manual states. Both are recorded, with evidence, in docs/upstream-issues.md.
Install
git clone https://github.com/iwinoid/eutils-mcp-server.git
cd eutils-mcp-server
npm install
npm run buildDependencies
Node.js 22 or newer. The version is pinned in .nvmrc.
The server has three runtime dependencies: @modelcontextprotocol/server,
fast-xml-parser, and zod. The lockfile is committed. There is no installer script and
no native build step.
Usage
Register the server with your MCP host. Add this to the host configuration, for example
claude_desktop_config.json:
{
"mcpServers": {
"eutils": {
"command": "node",
"args": ["/absolute/path/to/E-utilities/dist/index.js"],
"env": {
"NCBI_API_KEY": "your-key",
"NCBI_EMAIL": "you@example.com",
"NCBI_TOOL": "eutils-mcp-server"
}
}
}
}To keep the key out of the host configuration, read it from .env instead:
{
"mcpServers": {
"eutils": {
"command": "node",
"args": [
"--env-file-if-exists=/absolute/path/to/E-utilities/.env",
"/absolute/path/to/E-utilities/dist/index.js"
]
}
}
}Then ask the model to search. You can also call a tool directly:
npm run call eutils_esearch '{"db":"pubmed","term":"CRISPR delivery AND 2024[pdat]","retmax":3}'The server answers with a count, a UID list, the translated query, and a History handle:
# ESearch: `CRISPR delivery AND 2024[pdat]`
Database **pubmed** matched **412** records. Showing 3 starting at 0.
## UIDs
40123456, 40123457, 40123458
## History handle
{"db":"pubmed","web_env":"MCID_6aa2...","query_key":"1"}The count changes as PubMed grows. Confirm that you see a count and three UIDs.
Configuration
Every variable is optional. NCBI asks automated clients to identify themselves, and an API key raises the rate limit.
Variable | Default | Purpose |
| unset | Raises the ceiling from 3 to 10 requests per second. Get one from the Settings page of your NCBI account. |
| unset | Contact address sent with every request. NCBI uses it to warn you before an IP block. |
|
| Name that identifies this software in the NCBI logs. |
Supply the values in the env block of your host configuration, or keep them in a .env
file at the project root and launch the server with --env-file-if-exists. npm start
and npm run dev pass that flag for you. When the file is absent, Node prints
not found. Continuing without it. and the launch continues, so a missing .env cannot
break startup. The path resolves against the working directory. Give an absolute path when
your host launches the server from elsewhere.
.gitignore excludes .env. It does not exclude a host configuration file. Check that
file before you commit it.
Set NCBI_EMAIL and NCBI_TOOL, then register both with NCBI by mail to
eutilities@ncbi.nlm.nih.gov. A request that carries the values without prior
registration does not satisfy the NCBI usage policy.
Subscribe to the Entrez Utilities announcement list at the same address. It is the only NCBI channel that reports known bugs. The NCBI Insights blog reports planned changes only, and the release notes inside the E-utilities manual stop at 2015.
Rate limits
NCBI blocks an IP that exceeds its limit. All requests, including internal batches, pass through one token bucket.
3 requests per second without an API key
10 requests per second with one
NCBI asks that large jobs run at a weekend. On a weekday, run them between 21:00 and 05:00 US Eastern time.
Limits
Entrez only. The server reads what Entrez indexes. Data that lives outside Entrez is not reachable.
retmaxceilings.eutils_esearchaccepts up to 10,000.eutils_esummaryandeutils_efetchaccept up to 500 per call. A larger UID list is split into batches of 500, and the response reportsbatches.PubMed and PMC caps. ESearch reaches only the first 10,000 records of a PubMed or PMC result set. Add date filters to segment a larger set.
Truncation. The server cuts a response over 25,000 characters. The message says how to page or narrow the query.
Response ceiling. The client abandons a response body over 5 MB.
stdio only. No HTTP transport. To add one, bind
127.0.0.1and validate theOriginandHostheaders.EGQuery coverage. EGQuery itself is unreachable, so
eutils_egquerycovers 12 databases instead of 38. See below.
Known upstream issue: EGQuery
NCBI's egquery.fcgi answers with an HTTP 301 to
ext-http-eutils.linkerd.ncbi.nlm.nih.gov. That host is not published in public DNS.
Two independent DNSSEC-validating resolvers, Cloudflare and Google, both return NXDOMAIN
for the name. A control query for eutils.ncbi.nlm.nih.gov resolves normally.
Every parameter combination tried redirects: GET and POST, with and without retmode,
retmax, tool, email, a browser User-Agent, and HTTP/1.0.
An API key does not help. With a valid key, esearch returns 200 while egquery still
returns 301 in the same session. A syntactically invalid key makes egquery return
400 API key invalid instead. That result shows NCBI validates the key before it routes
the request, so the redirect is not a credentials or rate-limit decision.
Run npm run doctor to reproduce the finding on your own network. The full evidence
chain, and the other upstream defects found while building this server, are in
docs/upstream-issues.md.
eutils_egquery tries the real EGQuery first. Only a network failure starts the fallback,
and then the server counts matches with ESearch over 12 commonly used databases. The
result carries degraded: true, a reason, and a note. Read that marker as "this covers a
subset, not all 38 databases". A validation error never starts the fallback, so a bad
query cannot cost 12 extra requests.
The fallback is lazy. If NCBI repairs the endpoint, the real EGQuery returns and no code changes.
Security
The server is read-only and holds no listener. It never writes to disk. There is no port for an attacker to connect to: the only network traffic is outbound HTTPS from the server to NCBI.
Threat | Control |
Prompt injection carried by record text | The server fences NCBI record text between |
Parameter injection | The server validates |
API key leakage | The server masks |
SSRF | The base URL is a constant, not an environment setting. The client follows redirects manually, at most three hops, and every hop must end with |
Resource exhaustion | A token bucket, per-endpoint |
Malicious XML | Entity processing is off. The client strips DOCTYPE declarations and caps the body size before parsing. |
Supply chain | Three runtime dependencies. The lockfile is committed. |
Report a vulnerability through the issue tracker.
API
Eleven tools. Every tool accepts response_format of "markdown" or "json", and
defaults to markdown. Every tool reports readOnlyHint: true and
destructiveHint: false, and declares an outputSchema that its own result satisfies.
Tool | Purpose |
| List databases, or describe one database: searchable fields, links, record count |
| Search a database. Returns UIDs and a History handle |
| Upload a UID list to the NCBI History server |
| Compact summaries for a UID set: title, authors, journal, date |
| Full records: PubMed abstracts, FASTA sequences, other formats |
| Follow links between databases, for example pubmed to pmc, or gene to protein |
| Count matches across many databases at once |
| Spelling suggestion for a query |
| Resolve formatted citations to PMIDs |
| Search and download in one call |
| Follow links and download the target records in one call |
Each tool takes one of the nine E-utilities as its subject. The tool name carries the
E-utilities name after the eutils_ prefix, so eutils_esearch calls esearch.fcgi.
Parameter names follow the API, so the manual applies directly.
Working with large result sets
The server keeps no state. The History handle travels as an ordinary value, so you pass it back unchanged.
eutils_esearch(db="pubmed", term="...", retmax=0, usehistory=true)
-> { total: 16896, history: { db, web_env, query_key } }
eutils_efetch(history={...}, retstart=0, retmax=500)
eutils_efetch(history={...}, retstart=500, retmax=500)Run the inspector to read the full input and output schema of every tool:
npm run build
npx @modelcontextprotocol/inspector node dist/index.jsMaintainers
Contributing
Ask questions in the issue tracker. Pull requests are accepted.
Read CONTRIBUTING.md before you open one. It states the development commands, the requirements a pull request must meet, and how to read the coverage number.
This project follows the Contributor Covenant, version 2.1.
License
MIT © iwinoid
NCBI supplies the data. If you redistribute this software or its output, NCBI's Disclaimer and Copyright notice must be evident to users. PubMed abstracts can be protected by copyright. Redistribution beyond fair use needs the permission of the copyright holder.
Available Tools
11 toolseutils_ecitmatchBatch Citation to PMID LookupARead-onlyIdempotent
Resolve formatted citation strings to PubMed IDs.
Use this when you have a reference list but no PMIDs. It is far more reliable than free-text searching for a specific article.
Args:
citations (string[]): each string formatted as journal_title|year|volume|first_page|author_name|your_key| A trailing pipe is optional and is added for you.
response_format ('markdown' | 'json'): output format. Default 'markdown'.
Returns: { submitted, matched, records: [{ input, journal, year, volume, first_page, author, key, pmid, matched }] }
Examples:
Use when: "find the PMID for Mann BJ, Proc Natl Acad Sci USA 1991;88:3248" -> citations=["proc natl acad sci u s a|1991|88|3248|mann bj|Art1|"]
Use when: converting a bibliography into PMIDs before fetching abstracts
Don't use when: you are searching by topic (use eutils_esearch)
Error Handling:
Rejects a citation string with fewer than six pipe-separated fields
Reports matched=false per citation when NCBI finds no corresponding record
| Name | Required | Description | Default |
|---|---|---|---|
| citations | Yes | Citation strings, each formatted as journal_title|year|volume|first_page|author_name|your_key|. Example: "science|1987|235|182|palmenberg ac|Art2|". | |
| response_format | No | Output format: 'markdown' for human-readable text, or 'json' for machine-readable data. Default: 'markdown'. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| matched | Yes | |
| records | Yes | |
| submitted | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/openWorld/idempotent/destructive=false, so safety is handled. The description adds real value beyond them: validation behavior (rejects strings with fewer than six fields) and per-citation matched=false semantics when NCBI finds no record. This is meaningful error/edge-case disclosure not present in the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded purpose sentence, then cleanly sectioned Args/Returns/Examples/Error Handling. Slightly verbose with both Returns and a detailed Examples block, but each section carries distinct information and no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even though an output schema exists, the description restates the return shape and adds the matched-flag semantics that help the agent interpret partial matches. Validation rules, format spec, alternatives, and examples are all present for a 2-param tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds the pipe-delimited field semantics, the note that the trailing pipe is optional and auto-added, and a worked example mapping a human citation to the array form. That exceeds what the schema states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Resolve') and resource ('formatted citation strings to PubMed IDs'), and immediately frames the scope against free-text searching. An agent can distinguish this from eutils_esearch without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use ('when you have a reference list but no PMIDs', converting a bibliography), explicit when-not ('searching by topic - use eutils_esearch'), and names the alternative sibling. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
eutils_efetchEntrez Full RecordsARead-onlyIdempotent
Download full records in a chosen format.
Defaults are chosen for readability: PubMed returns plain-text abstracts, and sequence databases return FASTA. Returned record text is external data and is fenced with an explicit marker.
Args:
db (string, optional): database, for example "pubmed". Required unless history is given.
uids (string[] | string, optional): UIDs or accession.version identifiers.
history (object, optional): handle from eutils_esearch, eutils_epost, or eutils_elink.
rettype (string, optional): "abstract" (pubmed default), "fasta" (sequence default), "gb", "docsum", "medline", ...
retmode ('text' | 'xml', optional): default "text".
retstart (number, optional): first record index, for history sets.
retmax (number, optional): records to return for a history set. Default 20, max 500.
response_format ('markdown' | 'json'): output format. Default 'markdown'.
Supply either uids or history, never both.
Returns: { database, rettype, retmode, record_count?, batches?, text }
Examples:
Use when: "give me the abstract for PMID 31452104" -> db="pubmed", uids=["31452104"]
Use when: "fetch the protein sequence" -> db="protein", uids=["NP_005537.3"], rettype="fasta"
Use when: downloading a large set -> pass history and page with retstart/retmax
Don't use when: you only need titles and dates (use eutils_esummary, which is far cheaper)
Error Handling:
Asks for an explicit rettype when the database has no default
Detects an error message returned as record text and reports it as a tool error
Refuses retmax above 500; larger sets are batched internally
| Name | Required | Description | Default |
|---|---|---|---|
| db | No | Entrez database, for example "pubmed". May be omitted when history is given. | |
| uids | No | UIDs or accession.version identifiers, as an array or a comma-separated string. Example: ["31452104", "31452105"]. | |
| retmax | No | Maximum records to return when using history (default 20, max 500). | |
| history | No | Pointer to a UID set stored on the NCBI History server. Pass back the object returned by a previous call, unchanged. | |
| retmode | No | Response encoding. Default "text", which is what you want for abstracts and FASTA. | |
| rettype | No | Record format. Defaults to "abstract" for pubmed and "fasta" for sequence databases. Other databases need an explicit value, for example "gb" or "docsum". | |
| retstart | No | Index of the first record to return. Use with history. | |
| response_format | No | Output format: 'markdown' for human-readable text, or 'json' for machine-readable data. Default: 'markdown'. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | Yes | Raw record text. The markdown rendering fences it as external data. |
| batches | No | |
| retmode | Yes | |
| rettype | Yes | |
| database | Yes | |
| record_count | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, open-world), and the description adds genuinely new behavior: DB-specific defaults, external-data fencing, retmax>500 refusal with internal batching, error-text detection, and explicit rettype prompting. This goes well beyond the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded purpose followed by cleanly labeled Args/Returns/Examples/Error Handling sections. The Args block partially duplicates schema descriptions, but for an 8-parameter tool with several behaviors the length is justified, not padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema exists and annotations carry the safety profile, the description still supplies everything an agent needs: format defaults, source selection rules, paging limits, and error behavior. No material gap remains for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 100% schema coverage the baseline is 3, but the description adds meaning the schema lacks: the mutual-exclusivity rule ('supply either uids or history, never both'), per-database rettype default semantics, and the purpose of retstart/retmax as history-only paging controls.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Download full records') and immediately clarifies the format behavior. It differentiates itself from siblings, notably by naming eutils_esummary as the cheaper tool for titles/dates, so an agent can distinguish it within the E-utilities family without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when' examples (abstract fetch, sequence fetch, large-set download) plus a 'Don't use when' exclusion routing to eutils_esummary. It also states the history-vs-uids selection rule and the paging strategy with retstart/retmax.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
eutils_egqueryGlobal Entrez QueryARead-onlyIdempotent
Search every Entrez database at once and report how many records each one matches.
Use this to find which database holds data for a topic before committing to a search. It returns counts only, never records.
Args:
term (string): Entrez text query, for example "CRISPR base editing".
response_format ('markdown' | 'json'): output format. Default 'markdown'.
Returns: { term, databases_searched, databases_with_hits, hits: [{ db, menu, count, status }] (sorted by count, descending), empty_databases: string[] }
Examples:
Use when: "which database has information about BRCA1 variants?" -> term="BRCA1 variants"
Don't use when: you already know the database (use eutils_esearch instead)
Error Handling:
Returns "The search term was empty" when term is blank
NCBI EGQuery redirects to an internal host that is not published in public DNS, for every client including ones with a valid API key. When the real EGQuery is unreachable this tool falls back to per-database ESearch counts over 12 commonly used databases, and says so in a "degraded" field. Counts are then a subset, not all 38.
The fallback triggers only on a network failure, never on a validation error.
| Name | Required | Description | Default |
|---|---|---|---|
| term | Yes | Entrez text query to run against every database at once. | |
| response_format | No | Output format: 'markdown' for human-readable text, or 'json' for machine-readable data. Default: 'markdown'. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| hits | Yes | |
| term | Yes | |
| degraded | No | True when the fallback produced this result. |
| degraded_reason | No | |
| empty_databases | Yes | |
| databases_searched | Yes | |
| databases_with_hits | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish read-only, idempotent, open-world safety, and the description adds materially more: counts-only output, a degraded-mode fallback limited to 12 of 38 databases, the DNS/redirect cause, the exact fallback trigger condition (network failure, never validation error), and the blank-term error string. This is unusually rich disclosure for a read tool with full annotation coverage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the one-line purpose, then cleanly sectioned into Args, Returns, Examples, and Error Handling. Despite its length, every section carries non-redundant operational information, particularly the degraded-mode caveat.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even though an output schema exists, the description spells out the full return shape including the degraded field, sorting order, and empty_databases, plus failure modes. Nothing an agent needs to interpret a result or handle a fallback is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 documented, and the description largely restates them. The example query 'CRISPR base editing' adds a small amount of concreteness about term format, but no syntax, limits, or field-qualifier guidance beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Search every Entrez database at once') plus the exact output contract ('report how many records each one matches'). The 'Don't use when' line explicitly separates it from eutils_esearch, so an agent can route without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides both a positive trigger ('find which database holds data for a topic before committing to a search') and an explicit exclusion with the named alternative ('you already know the database (use eutils_esearch instead)'). The worked example ('which database has information about BRCA1 variants?') makes the intent unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
eutils_einfoEntrez Database InfoARead-onlyIdempotent
List Entrez databases, or describe one database's searchable fields and links.
Call with no arguments to list all Entrez databases. Call with db to get that database's record count, last update time, searchable field names, and the links available to other databases.
Args:
db (string, optional): database to describe, for example "pubmed". Omit to list all.
response_format ('markdown' | 'json'): output format. Default 'markdown'.
Returns: Without db: { count, databases: string[] } With db: { database, menu_name, description, record_count, last_update, build, field_count, fields: [{ name, fullname, description, termcount? }], link_count, links: [{ name, dbto, menu }] }
Examples:
Use when: "what fields can I search in PubMed?" -> db="pubmed"
Use when: "which Entrez databases exist?" -> no arguments
Use when: "what databases link from a gene record?" -> db="gene"
Don't use when: you want record counts for a query (use eutils_egquery instead)
Error Handling:
Rejects a database name that is not one of the known Entrez databases, and lists samples
Returns a parse error if NCBI changes the response shape
| Name | Required | Description | Default |
|---|---|---|---|
| db | No | Entrez database to describe, for example "pubmed" or "protein". Omit to list all databases. | |
| response_format | No | Output format: 'markdown' for human-readable text, or 'json' for machine-readable data. Default: 'markdown'. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | Number of Entrez databases, when no db was given. |
| links | No | |
| fields | No | |
| database | No | Database name, when db was given. |
| databases | No | Database names, when no db was given. |
| link_count | No | |
| field_count | No | |
| record_count | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so safety is covered. The description goes further by disclosing error behavior (unknown db names are rejected with samples; parse errors if NCBI changes the response shape) and by enumerating exactly what data each mode returns, including last_update and record_count.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core behavior is front-loaded in the first paragraph, followed by clearly labeled Args, Returns, Examples, and Error Handling sections. The Returns block partly duplicates the output schema, but the Examples and Error Handling sections earn their space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter, zero-required tool with a full output schema and rich annotations, the description covers both modes, the argument semantics, worked examples, sibling routing, and failure modes. An agent has everything needed to select and invoke it correctly; return-value detail is a bonus given the output schema exists.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 meaning beyond the schema by explaining the consequence of each choice: omitting db yields the full list, supplying db yields record count, last update, searchable fields, and outbound links. The response_format enum is already fully documented in the schema and is merely restated.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb (List / describe) applied to a precise resource (Entrez databases and their searchable fields and links). It cleanly separates the two operating modes (no args = list, db = describe), which lets an agent pick the right call 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives concrete when-to-use examples mapped to inputs ("what fields can I search in PubMed?" -> db="pubmed") and an explicit don't-use case that names the alternative sibling (eutils_egquery) for record counts on a query. The choice between this tool and its closest sibling is fully resolved.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
eutils_elinkEntrez Cross-Database LinksARead-only
Find records linked to a set of UIDs, either in another database or within the same one.
This is how you move between databases: gene to protein, pubmed to pmc, nucleotide to snp, and so on. With cmd="neighbor_history" the linked set is stored on the NCBI History server and returned as a handle you can feed straight into eutils_efetch.
Args:
dbfrom (string): source database, for example "pubmed".
db (string, optional): target database, for example "pmc". Omit for same-database links.
uids (string[] | string, optional): source UIDs.
history (object, optional): handle whose db matches dbfrom.
cmd (string, optional): "neighbor" (default), "neighbor_score", "neighbor_history", "acheck", "ncheck", "lcheck", "llinks", "prlinks".
linkname (string, optional): a specific link, for example "pubmed_pmc". Use eutils_einfo to list them.
response_format ('markdown' | 'json'): output format. Default 'markdown'.
Supply either uids or history, never both.
Returns: { dbfrom, dbto?, command, groups_found, total_linked, groups: [{ dbto, linkname, count, ids[], query_key? }], histories? }
Examples:
Use when: "which PMC articles correspond to these PMIDs?" -> dbfrom="pubmed", db="pmc"
Use when: "find proteins for these gene IDs" -> dbfrom="gene", db="protein"
Use when: chaining a download -> cmd="neighbor_history", then pass histories to eutils_efetch
Don't use when: you want records, not UID lists (use eutils_link_then_fetch)
Error Handling:
Rejects a history whose db does not match dbfrom
Returns an empty result with a hint to list valid link names via eutils_einfo
| Name | Required | Description | Default |
|---|---|---|---|
| db | No | Target database to find links in, for example "pmc". Omit to find related records in the same database. | |
| cmd | No | Link command. "neighbor" returns linked UIDs immediately (default). "neighbor_history" stores them on the History server and returns a handle. | |
| uids | No | UIDs or accession.version identifiers, as an array or a comma-separated string. Example: ["31452104", "31452105"]. | |
| dbfrom | Yes | Source database holding the input UIDs, for example "pubmed". | |
| history | No | Pointer to a UID set stored on the NCBI History server. Pass back the object returned by a previous call, unchanged. | |
| linkname | No | Specific link to follow, for example "pubmed_pmc". Call eutils_einfo to list valid link names. | |
| response_format | No | Output format: 'markdown' for human-readable text, or 'json' for machine-readable data. Default: 'markdown'. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| dbto | No | |
| dbfrom | Yes | |
| groups | Yes | |
| command | Yes | |
| histories | No | Present when cmd is neighbor_history. |
| groups_found | Yes | |
| total_linked | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/openWorld/non-idempotent/non-destructive, so the description's added value is the History-server persistence semantics of cmd="neighbor_history" (a real side effect explaining the non-idempotent hint), the uids-vs-history mutual exclusion rule, and error-handling behavior (rejecting a mismatched history db, empty-result hint). It stops short of covering operational concerns like rate limits or expired-history handling, but the additions are substantive rather than restated annotation content.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded: purpose first, then the database-bridging framing, then a structured Args/Returns/Examples/Error Handling layout. It is slightly long because the Args section and Returns block duplicate the input and output schemas, but every non-duplicated sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter tool with nested objects and cross-database semantics, the definition covers selection, chaining, constraints, and failure modes; the returns description is redundant given an output schema exists but does no harm. An agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is already 100%, so the Args section largely restates the schema. However, it adds meaning the schema does not encode: "Supply either uids or history, never both" and the note that history.db must match dbfrom, plus the shorthand that omit-db means same-database links.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (find records linked to a set of UIDs) and immediately scopes it as cross-database navigation with concrete examples (gene to protein, pubmed to pmc). It explicitly differentiates itself from siblings by naming eutils_link_then_fetch as the alternative when records are wanted rather than UID lists.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Contains an explicit "Use when" list with three concrete scenarios and a "Don't use when" clause that routes to eutils_link_then_fetch. It also names eutils_einfo for discovering link names and describes the chaining path into eutils_efetch.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
eutils_epostUpload UIDs to Entrez HistoryARead-only
Upload a list of UIDs to the NCBI History server and get a reusable handle.
Use this when you already have UIDs from somewhere other than an ESearch, or when you want to combine several sets. Many thousands of UIDs fit in one call.
Args:
db (string): database the UIDs belong to, for example "gene".
uids (string[] | string): UIDs or accessions, as an array or comma-separated string.
response_format ('markdown' | 'json'): output format. Default 'markdown'.
Returns: { database, uploaded, history: { db, web_env, query_key } }
Examples:
Use when: "fetch these five gene IDs" -> db="gene", uids=["7173","22018","54314"]
Use when: combining UID lists from two sources before one download
Don't use when: you are about to search; ESearch with usehistory already posts its own results
Error Handling:
Rejects UIDs containing URL metacharacters
Reports an upstream error if NCBI returns no History handle
| Name | Required | Description | Default |
|---|---|---|---|
| db | Yes | Entrez database the UIDs belong to, for example "pubmed". | |
| uids | Yes | UIDs or accessions to upload, as an array or a comma-separated string. | |
| response_format | No | Output format: 'markdown' for human-readable text, or 'json' for machine-readable data. Default: 'markdown'. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| history | Yes | |
| database | Yes | |
| uploaded | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint/destructiveHint/idempotentHint), it discloses capacity (many thousands of UIDs per call), the validation rule (UIDs with URL metacharacters are rejected), and failure mode (upstream error if NCBI returns no History handle). This explains why idempotentHint is false: each call yields a fresh handle.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well structured and front-loaded: purpose first, then Args/Returns/Examples/Error Handling. The Args section largely restates the schema descriptions, which is mild redundancy, but no sentence is wasted elsewhere.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter tool with an output schema and full annotation coverage, the description supplies everything an agent needs: purpose, routing advice, parameter shapes, return shape, and error behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds worked examples with real values (db="gene", uids=["7173","22018","54314"]) and restates the array-or-comma-separated flexibility of uids, which helps an agent choose a form quickly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource+outcome: upload UIDs to the NCBI History server and receive a reusable handle. It distinguishes itself from the search-oriented siblings by explaining that this is the entry point when UIDs come from somewhere other than ESearch.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names when to use it (UIDs from another source, combining sets), when not to use it (you are about to search; ESearch with usehistory already posts its own results), and gives concrete examples. The alternative is named and the selecting condition is stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
eutils_esearchEntrez Text SearchARead-only
Search an Entrez database and return matching UIDs.
This is the entry point for a retrieval pipeline. It returns UIDs, never records. By default it also stores the result set on the NCBI History server and returns a history handle, so later calls can page through the whole set without re-searching.
Entrez field tags go in square brackets: gene[tiab], 2008[pdat], mouse[orgn]. Boolean operators AND, OR, NOT must be uppercase.
Args:
db (string): database to search, for example "pubmed".
term (string): Entrez query, for example "breast cancer AND 2008[pdat]".
retmax (number, optional): UIDs to return, 0-10000. Default 20. Use 0 for count only.
retstart (number, optional): index of the first UID. Default 0.
sort (string, optional): "pub_date", "relevance", "first_author", ...
datetype ('pdat' | 'edat' | 'mdat', optional): date field for mindate/maxdate.
mindate, maxdate (string, optional): YYYY, YYYY/MM, or YYYY/MM/DD.
usehistory (boolean, optional): return a History handle. Default true.
response_format ('markdown' | 'json'): output format. Default 'markdown'.
Returns: { database, term, total, count, offset, has_more, next_offset, uids: string[], query_translation, term_translations: [{ from, to }], history? }
Examples:
Use when: "find papers about CRISPR in Nature" -> db="pubmed", term="CRISPR AND nature[journal]"
Use when: "how many records mention this gene?" -> retmax=0
Don't use when: you already have UIDs (use eutils_esummary or eutils_efetch)
Don't use when: you don't know which database (use eutils_egquery first)
Error Handling:
Rejects retmax above 10000 with advice to use the History server
Rejects an unknown database and lists valid ones
Returns an empty result with spelling advice rather than an error
| Name | Required | Description | Default |
|---|---|---|---|
| db | Yes | Entrez database to search, for example "pubmed" or "protein". | |
| sort | No | Sort order, for example "pub_date", "relevance", or "first_author". Valid values vary by database. | |
| term | Yes | Entrez query. Field tags go in square brackets, for example "breast cancer AND 2008[pdat]" or "mouse[orgn]". | |
| retmax | No | Maximum UIDs to return (default 20). Use 0 to fetch only the count. | |
| maxdate | No | End date, as YYYY, YYYY/MM, or YYYY/MM/DD. Requires datetype. | |
| mindate | No | Start date, as YYYY, YYYY/MM, or YYYY/MM/DD. Requires datetype. | |
| datetype | No | Which date field mindate/maxdate apply to: pdat (publication), edat (Entrez), mdat (modification). | |
| retstart | No | Index of the first UID to return. Use for paging. | |
| usehistory | No | Store the result set on the NCBI History server and return a history handle (default true). Set false to skip it. | |
| response_format | No | Output format: 'markdown' for human-readable text, or 'json' for machine-readable data. Default: 'markdown'. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| term | Yes | |
| uids | Yes | |
| count | Yes | Records returned on this page. |
| total | Yes | Records matching the whole query, not just this page. |
| offset | Yes | |
| history | No | Present when usehistory is true. |
| database | Yes | |
| has_more | Yes | |
| next_offset | No | |
| query_translation | Yes | How Entrez rewrote the query. |
| term_translations | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/openWorld/idempotent annotations, the description discloses a real server-side side effect: the result set is stored on the NCBI History server and a handle returned. It also documents failure modes (retmax>10000 rejection with advice, unknown-database rejection listing valid ones, empty results returned with spelling advice rather than as errors), which an agent cannot infer from annotations alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and scoping in the first paragraph, then Args/Returns/Examples/Error Handling sections that are easy to scan. It is somewhat long and the Args block restates fields already 100% covered by the schema, so it loses a point for redundancy rather than for verbosity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter, open-world search tool with an output schema, the description covers the return shape, the history-handle mechanism, syntax rules, and error behavior. Nothing an agent needs to call it correctly is missing, and the output schema carries the response detail.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so a 3 is the floor. The description adds value the schema does not: the uppercase-only rule for AND/OR/NOT and the YYYY / YYYY/MM / YYYY/MM/DD date formats, plus a consolidated default listing. Much of the Args block duplicates the schema, which caps it below 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Search an Entrez database and return matching UIDs") and immediately frames it as "the entry point for a retrieval pipeline" that "returns UIDs, never records." The Don't-use-when clauses name eutils_esummary, eutils_efetch, and eutils_egquery, so an agent can distinguish it from siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when/when-not routing with concrete conditionals: don't use it when you already have UIDs (use esummary/efetch), and don't use it when the database is unknown (use egquery first). The Examples block reinforces this with realistic query-to-parameter mappings, including the count-only pattern via retmax=0.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
eutils_espellSpelling SuggestionARead-onlyIdempotent
Get NCBI's spelling suggestion for a query in one database.
Args:
db (string): database to check against, for example "pubmed".
term (string): query to check, for example "breast cancr".
response_format ('markdown' | 'json'): output format. Default 'markdown'.
Returns: { database, query, corrected_query, changed }
Examples:
Use when: a search returned no results and you suspect a typo
Use when: "did you mean" for a query -> term="diabetis"
Don't use when: the query is a structured field search; ESpell works on plain terms
Error Handling:
Reports changed=false when NCBI has no correction, rather than an error
| Name | Required | Description | Default |
|---|---|---|---|
| db | Yes | Entrez database to check the spelling against, for example "pubmed". | |
| term | Yes | Query whose spelling should be checked, for example "breast cancr". | |
| response_format | No | Output format: 'markdown' for human-readable text, or 'json' for machine-readable data. Default: 'markdown'. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| query | Yes | |
| changed | Yes | |
| database | Yes | |
| corrected_query | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and destructiveHint=false, so safety is covered. The description adds genuinely useful context beyond that: the error-handling note that changed=false is reported rather than an error when NCBI has no correction. It stops short of describing rate limits or response latency, but the error semantics are a real value-add.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded with purpose first, then structured Args/Returns/Examples/Error Handling sections. Every section earns its place except the Args block, which duplicates the schema verbatim, making it slightly longer than necessary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Although an output schema exists (so return explanation is optional), the description still documents the return shape and even covers the no-correction edge case. For a 3-parameter, fully-annotated tool, an agent has everything needed to select and invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the Args section largely restates what the schema already documents for db, term, and response_format. The only marginal addition is the illustrative example term 'breast cancr', which does not deepen syntactic understanding. Baseline 3 applies when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Get NCBI's spelling suggestion for a query in one database.' An agent can immediately distinguish this diagnostic spelling tool from search/fetch siblings like eutils_esearch or eutils_efetch.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' bullets (no-results search, 'did you mean' scenario) and a 'Don't use when' exclusion for structured field searches. The alternative condition is stated precisely, so nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
eutils_esummaryEntrez Document SummariesARead-onlyIdempotent
Fetch compact summaries (DocSums) for a set of UIDs.
Use this to screen records by title, authors, journal, and date before paying the cost of downloading full records.
Args:
db (string, optional): database, for example "pubmed". Required unless history is given.
uids (string[] | string, optional): UIDs or accessions.
history (object, optional): handle from eutils_esearch, eutils_epost, or eutils_elink.
retstart (number, optional): first record index, for history sets. Default 0.
retmax (number, optional): records to return for a history set. Default 20, max 500.
response_format ('markdown' | 'json'): output format. Default 'markdown'.
Supply either uids or history, never both.
Returns: { database, total, count, offset, has_more, next_offset?, batches?, records: [{ uid, title, authors[], journal, source, pubdate, volume, issue, pages, doi?, pmcid?, pubtype[], lang[] }] }
Non-PubMed databases return whichever scalar fields the DocSum carries.
Examples:
Use when: "show me the titles of these PMIDs" -> db="pubmed", uids=["31452104"]
Use when: screening a large result set -> pass history from eutils_esearch
Don't use when: you need the full abstract or sequence (use eutils_efetch)
Error Handling:
Refuses more than 500 UIDs per call and batches larger lists internally
Refuses to combine uids and history in one call
Rejects retmax above 500 rather than silently truncating
| Name | Required | Description | Default |
|---|---|---|---|
| db | No | Entrez database, for example "pubmed". May be omitted when history is given. | |
| uids | No | UIDs or accession.version identifiers, as an array or a comma-separated string. Example: ["31452104", "31452105"]. | |
| retmax | No | Maximum summaries to return when using history (default 20, max 500). | |
| history | No | Pointer to a UID set stored on the NCBI History server. Pass back the object returned by a previous call, unchanged. | |
| retstart | No | Index of the first summary to return. Use with history. | |
| response_format | No | Output format: 'markdown' for human-readable text, or 'json' for machine-readable data. Default: 'markdown'. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | |
| total | Yes | |
| offset | Yes | |
| batches | No | Present when the UID list needed more than one request. |
| records | Yes | |
| database | Yes | |
| has_more | Yes | |
| next_offset | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive, open-world behavior, so the safety profile is covered. The description adds genuinely useful disclosure beyond that: internal batching above 500 UIDs, refusal to combine uids and history, and rejection of retmax >500 rather than silent truncation. It loses a point for paying output-format detail that the output schema already supplies.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded one-line purpose, then cleanly labelled Args/Returns/Examples/Error Handling sections that are easy to scan. The Returns block restates what the output schema already provides and the Args list largely mirrors the schema, so a small amount of redundancy keeps it just short of a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only summarizer with a full output schema and rich annotations, everything an agent needs is present: the either/or parameter rule, defaults, caps, batching behavior, and failure modes. Nothing about correct invocation is left to inference.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 goes further by stating the cross-parameter constraint ("Supply either uids or history, never both") and the retmax default/max in prose form. That inter-parameter rule is the kind of semantics a schema rarely makes explicit.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Fetch compact summaries (DocSums) for a set of UIDs") and immediately scopes it against the heavier alternative: "Don't use when: you need the full abstract or sequence (use eutils_efetch)". An agent can distinguish this from eutils_efetch and eutils_esearch without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit "Use when" scenarios (screening titles by PMID, screening a large result set via history) and a "Don't use when" routing to eutils_efetch. It also names the sibling tools that produce the history handle, closing the loop on the prescreen-then-fetch workflow.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
eutils_link_then_fetchLink and Fetch Across DatabasesARead-onlyIdempotent
Follow links from one database to another and download the target records in one call.
Typical uses: gene IDs to protein sequences, PMIDs to PMC full text, nucleotide records to SNPs. Give it either a query or a UID list in the source database, and it returns records from the target database.
Args:
dbfrom (string): source database, for example "gene".
db (string): target database to download from, for example "protein".
term (string, optional): query in dbfrom. Pass exactly one of term or uids.
uids (string[] | string, optional): source UIDs in dbfrom.
linkname (string, optional): specific link to follow.
retmax (number, optional): target records to download. Default 20, max 500.
rettype (string, optional): record format for the target database.
response_format ('markdown' | 'json'): output format. Default 'markdown'.
Returns: { dbfrom, dbto, source_total, retrieved, rettype, source_history, history, text }
Examples:
Use when: "get the protein sequences for these gene IDs" -> dbfrom="gene", db="protein", uids=[...]
Use when: "find PMC full text for papers about X" -> dbfrom="pubmed", db="pmc", term="..."
Don't use when: you only need the linked UIDs (use eutils_elink, which is cheaper)
Error Handling:
Rejects passing both term and uids, or neither
Returns an empty result with a hint to list link names when no links exist
Refuses retmax above 500
| Name | Required | Description | Default |
|---|---|---|---|
| db | Yes | Target database to download from, for example "protein". | |
| term | No | Query in dbfrom. Use instead of uids to select the source records. | |
| uids | No | Source UIDs in dbfrom. Use instead of term. | |
| dbfrom | Yes | Source database, for example "gene". | |
| retmax | No | Records to download from the target database (default 20, max 500). | |
| rettype | No | Record format for the target database. | |
| linkname | No | Specific link to follow. Use eutils_einfo to list valid names. | |
| response_format | No | Output format: 'markdown' for human-readable text, or 'json' for machine-readable data. Default: 'markdown'. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| dbto | Yes | |
| text | Yes | |
| dbfrom | Yes | |
| history | No | |
| rettype | No | |
| retrieved | No | |
| source_total | Yes | |
| source_history | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint, so the safety profile is covered. The description adds real behavioral detail beyond that: mutual exclusivity of term/uids, retmax capped at 500 with default 20, and graceful empty-result hinting when no links exist. This is richer than typical but stops short of describing pagination or auth needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is well front-loaded (purpose, then uses, args, returns, examples, errors) and every section is scannable. The Args block largely restates the 100%-covered schema, which is mild redundancy, but the examples and error-handling sections earn their space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter cross-database tool, the description covers selection of source/target, the term-vs-uids rule, format control, and failure modes, and an output schema exists so return values need not be re-explained. Nothing material is missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description nevertheless adds meaning the schema does not encode, notably the 'Pass exactly one of term or uids' constraint and the retmax default/ceiling framing, which helps an agent construct a valid call rather than just read field docs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific compound action (follow links across databases and download target records in one call) and gives concrete examples (gene IDs to protein sequences, PMIDs to PMC full text). It is clearly distinguishable from eutils_elink and eutils_search_then_fetch because the 'link then fetch' scope is stated explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides explicit 'Use when' examples and a 'Don't use when: you only need the linked UIDs (use eutils_elink, which is cheaper)' exclusion naming the alternative tool. The agent can route between this tool and eutils_elink without inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
eutils_search_then_fetchSearch and FetchARead-onlyIdempotent
Search a database and download the matching records in one call.
This is the shortcut for the common "find me the papers about X" request. It runs ESearch with a History handle, then EFetch, saving a round trip. Use the individual tools when you want to screen titles before downloading.
Args:
db (string): database to search, for example "pubmed".
term (string): Entrez query.
retmax (number, optional): records to download. Default 20, max 500.
rettype (string, optional): "abstract" (pubmed default), "fasta" (sequence default), ...
retmode ('text' | 'xml', optional): default "text".
response_format ('markdown' | 'json'): output format. Default 'markdown'.
Returns: { database, term, total, retrieved, rettype, retmode, history, text }
Examples:
Use when: "summarize recent papers on CRISPR delivery" -> db="pubmed", term="CRISPR delivery AND 2024[pdat]"
Use when: "get the sequences for these gene records" -> db="nuccore", term="..."
Don't use when: you want to inspect titles first (use eutils_esearch then eutils_esummary)
Don't use when: the result set is huge; search with retmax=0 first to see the count
Error Handling:
Returns a friendly empty result, with spelling advice, when nothing matches
Refuses retmax above 500
Reports the ESearch count so you can judge whether to page
| Name | Required | Description | Default |
|---|---|---|---|
| db | Yes | Entrez database to search, for example "pubmed". | |
| term | Yes | Entrez query, for example "CRISPR AND 2024[pdat]". | |
| retmax | No | Records to download (default 20, max 500). | |
| retmode | No | Response encoding. Default "text". | |
| rettype | No | Record format. Defaults to "abstract" for pubmed, "fasta" for sequences. | |
| response_format | No | Output format: 'markdown' for human-readable text, or 'json' for machine-readable data. Default: 'markdown'. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| term | Yes | |
| text | Yes | |
| total | Yes | |
| history | Yes | |
| retmode | No | |
| rettype | No | |
| database | Yes | |
| retrieved | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, and non-destructive, so the safety profile is covered. The description adds value beyond that: it explains the ESearch History handle mechanism, the round-trip saving, the retmax>500 refusal, and the friendly-empty-result behavior with spelling advice.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the one-line purpose, then organizes Args, Returns, Examples, and Error Handling. Despite covering a lot, every section earns its place with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a compound search+fetch tool, the description covers purpose, alternatives, parameters, return shape, examples, and error handling. With an output schema also present, nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description goes slightly beyond by noting db-specific rettype defaults ('abstract' for pubmed, 'fasta' for sequences) and restating the retmax cap, adding useful semantics not fully captured by the schema's brief descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific compound verb+resource: 'Search a database and download the matching records in one call.' It explicitly frames itself as the shortcut vs the individual tools, so an agent can distinguish it from eutils_esearch and eutils_efetch without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when' and 'Don't use when' examples naming the alternative tools (eutils_esearch then eutils_esummary), plus guidance to search with retmax=0 when the result set is huge. This is textbook when/when-not/alternatives coverage.
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.
11 tool updates
v0.1.0- First observed
eutils_ecitmatch - First observed
eutils_efetch - First observed
eutils_egquery - First observed
eutils_einfo - First observed
eutils_elink - First observed
eutils_epost - First observed
eutils_esearch - First observed
eutils_espell - First observed
eutils_esummary - First observed
eutils_link_then_fetch - First observed
eutils_search_then_fetch
TDQS
Scored across 11 tools
Each tool maps to a distinct E-utilities operation (search, fetch, summary, link, post, spell, cite-match, database listing, cross-db counts), and descriptions include explicit 'Don't use when' cross-references. The two composite tools (search_then_fetch, link_then_fetch) could overlap with manual chains, but the descriptions clearly state when to prefer each, e.g. use esummary first to screen titles.
All tools share the eutils_ prefix and mostly follow the NCBI API names (esearch, efetch, elink), giving a predictable pattern. The two convenience tools use snake_case (search_then_fetch, link_then_fetch), which is readable but a slight deviation from the concatenated style.
11 tools is well-scoped, essentially covering the standard NCBI E-utilities suite plus two pragmatic shortcuts. Each tool earns its place with no redundant entries.
The surface covers the full E-utilities lifecycle: discovery (einfo, egquery), searching (esearch), history management (epost), retrieval (esummary, efetch), linking (elink), and utilities (espell, ecitmatch), plus end-to-end combos. No obvious dead ends for the domain.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Search biomedical literature, get article details, find related articles, and explore MeSH terms
Search biomedical papers, inspect publication records, and traverse citation or semantic graphs.
NCBI E-utilities — federated Entrez search/fetch (PubMed/Gene/Nucleotide/…)
PubMed MCP — wraps the NCBI E-utilities API (biomedical literature, free, no auth)
Related MCP Servers
- FlicenseNot gradedqualityNot gradedmaintenanceProvides access to NCBI's scientific databases including E-utilities, PubChem, and PMC APIs for biomedical literature search, molecular data retrieval, and research through natural language queries.3-
- FlicenseNot gradedqualityCmaintenanceEnables searching PubMed's biomedical literature database and retrieving article metadata, abstracts, and full content through the E-utilities API. Supports advanced queries, batch operations, and multiple output formats with automatic rate limiting.1-
- FlicenseNot gradedqualityDmaintenanceProvides access to NCBI's E-utilities, PubChem, and PMC APIs for searching and retrieving biomedical literature, chemical, and genomic data.-
- AlicenseNot gradedqualityCmaintenanceEnables searching and retrieving biomedical literature from PubMed via the NCBI E-utilities API.141MIT