FAERS MCP Server
Click on "Deploy 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., "@FAERS MCP ServerRun a full signal workup for semaglutide and pancreatitis"
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.
FAERS MCP Server
Wraps the OpenFDA Drug Adverse Event API (https://api.fda.gov/drug/event.json) as an MCP
server with 15 pharmacovigilance tools: case search, disproportionality (ROR/PRR), empirical
Bayes signal scores (MGPS/EBGM), bulk screening, and confounder-adjusted versions of all of
them.
See docs/PLAN.md for the assessment behind the design, including the verified openFDA behaviours the server depends on.
Layout
faers/
server.py tool definitions and the faers-mcp entry point
client.py shared openFDA client: Basic-auth key, retry, ceilings
query.py Lucene construction, escaping, the case-sensitivity rules
projection.py compact case cards, per-record suspect verification
stats.py ROR / PRR / chi-square, Mantel-Haenszel, Breslow-Day
screen.py bulk signal screen with the cached global marginal table
ebgm.py DuMouchel gamma-Poisson shrinker (MGPS) against scipy
background.py the drug x event background table the prior is fitted on
strata.py sex / age / year stratifiers and their resolution
fields.py field catalogue served by faers_describe_fields
errors.py structured {code, reason, recovery} failures
tests/ offline tests on recorded fixtures, plus live openFDA contract tests
docs/PLAN.md assessment, verified findings, design decisionsRelated MCP server: @cyanheads/openfda-mcp-server
Installation
pip install -e . # from a clone
pip install -e ".[test]" # with the test dependenciesOr directly from the repository, with no clone or virtualenv:
uvx --from git+https://github.com/drvvek/faers_mcp faers-mcp --versionThe mcp dependency is pinned to <2: mcp 2.x renamed FastMCP to MCPServer, and an
unpinned >=1.0 resolves to 2.x on a fresh install.
API key
Without a key: 1,000 requests/day and a count limit ceiling of 999.
With a key: 120,000 requests/day and limit up to 1,000.
Free key at https://open.fda.gov/apis/authentication/
The key is read from OPENFDA_API_KEY and sent as an HTTP Basic auth header, never in the
query string, so it stays out of URLs, proxy logs and crash traces. The key belongs in the client config or the environment, never in the repository;
.gitignore excludes .env.
Running
faers-mcp # stdio - what Claude Desktop / Cursor spawn
faers-mcp --transport http --port 8010 # Streamable HTTP on 127.0.0.1:8010/mcp
python -m faers # same as faers-mcpFAERS_MCP_TRANSPORT, FAERS_MCP_HOST and FAERS_MCP_PORT set the defaults. Binding
HTTP to anything other than loopback prints a warning: the transport has no authentication.
Interface
Arguments are flat. Every tool takes
drug_name,events, ... at the top level of the arguments object; nothing is wrapped in aparamskey. Enumerated arguments (role_basis,stratify_by,mode,sort_by,category) are declared as enums in the schema, anddate_from/date_tocarry a^\d{8}$pattern, so invalid values are rejected before any API call.Results are structured. Tools return objects; the server publishes an
outputSchemaand sends the result asstructuredContentwith a JSON text fallback.Failures are errors. A failed call is an MCP error result (
isError: true) whose text is a{code, reason, recovery}object. It is never a success payload withok: false.Progress.
faers_signal_screen,faers_ebgmandfaers_warm_cachereport progress to clients that support it.
Timeouts
The first faers_ebgm call for a FAERS release builds a background table: 3 + 100 API calls
and a prior fit, about 100 s in total, which exceeds many MCP clients' per-call timeout.
Call faers_warm_cache first — it does that work on a turn that expects it and reports
whether each cache was already warm — after which faers_ebgm takes a few seconds. Year
stratification adds ~47 calls on its first use, likewise cached.
Prompt
faers_signal_workup(drug_name, event=None) returns a fixed sequence of tool calls for a
defensible work-up — counts, screen, crude and stratified ROR/PRR, EBGM with year
stratification, trend, suspect-verified cases — ending with the disclaimer. Clients that
support MCP prompts can offer it directly.
Deployment options
The choice between them comes down to whether each user spends their own openFDA quota or all users share one key.
1. Git URL + uvx (per-user install)
Each user adds the following to their Claude Desktop config (claude_desktop_config.json)
or Cursor MCP settings, with their own API key:
{
"mcpServers": {
"faers": {
"command": "uvx",
"args": ["--from", "git+https://github.com/drvvek/faers_mcp", "faers-mcp"],
"env": { "OPENFDA_API_KEY": "<key>" }
}
}
}There is nothing to clone and no virtualenv to manage; updates are picked up on the next
launch. A private repository works the same way provided the user's machine already has
GitHub credentials (gh auth, a credential manager, or an SSH key) — uvx does not
prompt. Caches build per machine under ~/.faers_mcp_cache.
2. PyPI
python -m build && twine upload dist/*The config then reduces to "command": "uvx", "args": ["faers-mcp"].
3. Shared HTTP endpoint
A single process serves the tools over Streamable HTTP, and every client points at its URL:
OPENFDA_API_KEY=... faers-mcp --transport http --host 10.0.0.5 --port 8010{ "mcpServers": { "faers": { "url": "http://10.0.0.5:8010/mcp" } } }No per-user install, and the expensive caches — the EBGM background table, fitted priors, stratified marginals — are built once and shared. The trade-offs: all users draw on one key's 120,000/day quota, the endpoint has no authentication of its own, and it is a single point of failure. It should be bound to a private interface or placed behind an authenticating proxy, and never exposed to the public internet.
per-user quota | install effort | shared caches | auth | |
git + uvx | yes | none | no | n/a |
PyPI | yes | none | no | n/a |
shared HTTP | no — one key | none | yes | none built in |
Local install
{
"mcpServers": {
"faers": {
"command": "faers-mcp",
"env": { "OPENFDA_API_KEY": "<key>" }
}
}
}Tools
Tool | Description |
| Case reports as compact triage cards ( |
| Total / serious / fatal counts |
| 2x2 table, ROR, PRR, chi-square, named criteria; optional Mantel-Haenszel adjustment |
| Aggregate by any FAERS field (GROUP BY equivalent) |
| Top MedDRA PTs for a drug |
| Full ICSR by Safety Report ID |
| Sex, age (coded group and onset-age bands, each with coverage), reporter, country |
| Reaction outcomes + seriousness criteria |
| Yearly reporting trend |
| Substances co-reported with an index drug |
| Bulk ROR/PRR screen: a drug against all its events, or vice versa |
| Empirical Bayes signal scores (EBGM, EB05/EB95) via MGPS; optional stratification |
| Arbitrary Lucene query passthrough, validated |
| Catalogue of searchable field paths, stratifiers and their traps |
| Build the EBGM background and fit the prior ahead of time; report cache state |
Date windows and filters
Every query-shaped tool accepts date_from / date_to (YYYYMMDD, both or neither) and a
raw_filter Lucene clause. On faers_disproportionality and faers_signal_screen these
are applied to all four marginals including the grand total N, so the table stays
internally consistent — which is what makes raw_filter="patient.patientsex:2" a genuine
restricted analysis rather than a broken one.
Bulk screening
faers_signal_screen computes ROR, PRR and chi-square for every event reported with a
drug (or every drug reported with an event). The database-wide marginals come from a
single cached count call rather than one call per term:
screening 200 events, cold cache 13 API calls, 13.3 s
same, warm cache, another drug 10 API calls, 3.9 s
one-call-per-term equivalent ~202 calls, ~60 s floorThe cache is keyed on openFDA's own meta.last_updated, so a FAERS refresh invalidates it.
Set FAERS_CACHE_DIR to relocate it; it defaults to ~/.faers_mcp_cache.
Stratification
Crude ROR/PRR/EBGM compare a drug against the whole database, so anything predicting both
exposure and reporting confounds them. Pass stratify_by to adjust:
stratifier | strata | field | coverage |
| male, female |
| 87.9% |
| 0-17, 18-64, 65+ |
| 55.3% |
| calendar year, measured from the data |
| ~100% |
| age band x sex | both | lower |
patientagegroup is not used for age: it is populated on only 18.4% of reports. Age
bands are derived from patientonsetage instead.
faers_disproportionality pools stratum-specific tables by Mantel-Haenszel (Robins-
Breslow-Greenland variance for ROR, Greenland-Robins for PRR) and reports crude and
adjusted side by side with a Breslow-Day homogeneity test:
ATORVASTATIN x RHABDOMYOLYSIS, by age coverage 55.3%
crude ROR 6.273 adjusted ROR 4.888 (-22.1%, material)
Breslow-Day p = 0.0 -> heterogeneous
0-17 a=11 ROR 16.95
18-64 a=963 ROR 5.58
65+ a=1538 ROR 4.51Statins are prescribed predominantly to older patients, who also report more rhabdomyolysis; adjustment removes that confounding. A small Breslow-Day p indicates that the stratum-specific estimates differ, in which case the per-stratum rows are more informative than the pooled value.
Cost is four calls per outer band, because openFDA can count on the stratifying field and the bins are formed locally. Reports missing the field cannot enter any stratum, so every stratified result states its coverage.
faers_ebgm accepts all four. Stratification enters MGPS only through the expected count —
E = sum_k (n_drug,k * n_event,k) / n_k — and the prior is refitted on those expectations.
Year strata are not knowable in advance, so they are measured from the data and the
negligible tail is pruned: FAERS spans 38 calendar years, but 1986–2003 hold 385 reports
between them (0.002%) while costing two calls each to stratify. max_strata (default 30)
caps the number of strata; a narrower date_from/date_to window reduces it.
Year is the only stratifier with full coverage (receivedate is present on every report).
On empagliflozin it produces the largest correction:
event | obs | EBGM crude | EBGM by sex | EBGM by year |
FOURNIER^S GANGRENE | 1,102 | 140.0 | 124.3 | 87.0 |
DIABETIC KETOACIDOSIS | 3,902 | 50.7 | 52.9 | 52.6 |
URINARY TRACT INFECTION | 2,024 | 3.70 | 4.36 | 3.76 |
NAUSEA | 3,595 | 1.42 | 1.66 | 1.55 |
Empagliflozin was approved in 2014 and Fournier's gangrene reporting spiked after FDA's 2018 safety communication, so both are concentrated in the same recent years. Adjusting for report year removes that stimulated-reporting effect and drops EBGM by 38%.
EBGM / MGPS
faers_ebgm fits DuMouchel's Gamma-Poisson Shrinker and reports EBGM with an EB05/EB95
credibility interval. EB05 is the conventional screening statistic; EB05 > 2 is the usual
threshold.
Shrinkage is what distinguishes EBGM from ROR and PRR, which treat two cases against an expectation of 0.02 as a strong signal; EBGM discounts a ratio in proportion to how little evidence supports it. Teplizumab (29 reports in total) illustrates the difference:
event | n | expected | RRR | ROR lo95 | EBGM | EB05 |
HEPATIC CYTOLYSIS | 2 | 0.017 | 118.3 | 30.2 | 11.0 | 1.5 |
BLOOD POTASSIUM INCREASED | 2 | 0.022 | 89.1 | 22.7 | 10.1 | 1.5 |
DEEP VEIN THROMBOSIS | 2 | 0.090 | 22.1 | 5.6 | 5.0 | 1.1 |
An ROR lower confidence bound of 30 on two cases is a false alarm; the EB05 of 1.5 sits below the screening threshold. On a heavily-reported drug the two agree closely — for empagliflozin's top 200 events (all n >= 201) EBGM retains 98-100% of the raw ratio and the rankings match.
The prior is fitted across a drug x event background table, not the single pair, so the
first call for a FAERS release builds and caches it (3 + background_drugs calls; ~100 s
for the default 100 drugs / 74,000 cells). Later calls take about 6.
Caveats, repeated in every payload: expected counts use any-role marginals, the prior
comes from a truncated background, and the likelihood is zero-truncated because openFDA
reports only co-occurring pairs. Unstratified by default — pass stratify_by for sex, age
or report year. These values will not reproduce FDA's published EBGMs.
Reading the output
Role basis. openFDA cannot scope a count to one drug's role within a report: the
clause drugcharacterization:1 filters the report, not the matched drug. Counts are
therefore any-role (suspect, concomitant or interacting), and are labelled as such in
role_basis_note.
faers_search_cases accepts role_basis="suspect_verified", which checks each returned
record individually — the one place the distinction is computable.
Screening criteria. There is no single "signal detected" verdict. criteria_met
reports each convention separately:
Criterion | Rule |
| ROR lower 95% CI > 1 and a >= 3 |
| PRR >= 2 and chi-square >= 4 and a >= 3 |
Counts are not de-duplicated. They do not match FAERS Public Dashboard case counts. These are reporting-rate comparisons, not incidence, and cannot support causal inference. Every count payload carries this disclaimer.
Approximate terms. FAERS stores apostrophes as a caret (CROHN^S DISEASE), and
openFDA rejects that character in a search however it is escaped. Such terms fall back to a
tokenised phrase match, which is slightly over-inclusive (measured +0.08% to +1.36%). Rows
affected carry the flag approximate_marginal.
Response size. ICSRs average ~72 KB; ten raw records measured 724 KB. Case tools
return compact cards by default and declare what was dropped in fields_omitted.
Tests
python -m pytestCI runs the offline suite on Python 3.10–3.12 for every push and pull request. The live
contract suite runs on pushes only, never gates a PR, and needs OPENFDA_API_KEY as a
repository secret to stay under the keyless quota.
Offline tests run against recorded fixtures. Contract tests that hit the live API — they
pin undocumented openFDA behaviour such as .exact case sensitivity and the time key on
date histograms — are deselected by default:
python -m pytest -m liveExample queries
"What are the top adverse events for empagliflozin in FAERS?"
"Calculate ROR and PRR for metformin and lactic acidosis, adjusted for age"
"Give me a demographic profile of levetiracetam rhabdomyolysis cases"
"Show the yearly trend of pancreatitis reports with sitagliptin"
"Find atorvastatin myopathy cases where atorvastatin is the suspect drug"
"EBGM for empagliflozin's top events, stratified by report year"
Available Tools
15 toolsfaers_case_countsARead-onlyIdempotent
Total, serious and fatal case counts for a drug, optionally by event.
All counts are issued concurrently as a single round trip.
| Name | Required | Description | Default |
|---|---|---|---|
| events | No | MedDRA preferred terms, e.g. ['PANCREATITIS']. Case-insensitive. | |
| date_to | No | End of a receivedate window, YYYYMMDD. Must be paired with date_from. | |
| date_from | No | Start of a receivedate window, YYYYMMDD. Must be paired with date_to. | |
| drug_name | Yes | Active substance name, e.g. 'EMPAGLIFLOZIN'. | |
| raw_filter | No | Extra Lucene clause ANDed onto the preset query, e.g. 'patient.patientsex:2'. Applied to every marginal of a contingency table. See faers_describe_fields. | |
| role_basis | No | 'any' counts every report naming the drug in any role. 'suspect_verified' is only computable where records are in hand (faers_search_cases, faers_raw_search). | any |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, openWorld and non-destructive, so the safety profile is covered. The description adds one genuine behavioral fact beyond the structured data — that all counts are issued concurrently in a single round trip — but says nothing about latency/rate limits, result stability, or how the three count categories relate.
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?
Two short sentences, front-loaded with the core capability and a distinct secondary note about concurrency. No filler, no restatement of the tool name.
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?
With a fully described schema, an output schema, and safety annotations, the description covers what the tool returns well enough that return values need not be explained. The remaining gap is comparative context against the many overlapping counting/aggregation siblings, which an agent must resolve on its own.
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%, with every parameter (events, date_from/date_to pairing, drug_name, raw_filter, role_basis) documented in the schema itself, including the enum semantics. The description adds no parameter-level meaning, so the baseline 3 applies.
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 verb+resource ('case counts for a drug') and specifies the exact measures returned (total, serious, fatal) plus the optional event breakdown. It clearly separates this from a generic search or raw-list tool, but never names the close siblings (faers_count_by_field, faers_top_events, faers_outcome_breakdown) that an agent must choose between.
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?
Usage is only implied by the capability statement: use it when you want case counts for one drug, with or without an event breakdown. There is no explicit when-to-use/when-not-to-use guidance and no mention of the alternative counting tools in the sibling set, so routing 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.
faers_coreported_drugsARead-onlyIdempotent
Substances most often appearing on the same reports as an index drug.
Co-REPORTED at any role, not co-suspect: openFDA cannot restrict a count to substances carried as suspect, so the list is dominated by concomitant medication.
| Name | Required | Description | Default |
|---|---|---|---|
| top_n | No | Number of co-reported substances. | |
| events | No | MedDRA preferred terms, e.g. ['PANCREATITIS']. Case-insensitive. | |
| date_to | No | End of a receivedate window, YYYYMMDD. Must be paired with date_from. | |
| date_from | No | Start of a receivedate window, YYYYMMDD. Must be paired with date_to. | |
| drug_name | Yes | Active substance name, e.g. 'EMPAGLIFLOZIN'. | |
| raw_filter | No | Extra Lucene clause ANDed onto the preset query, e.g. 'patient.patientsex:2'. Applied to every marginal of a contingency table. See faers_describe_fields. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnlyHint, idempotentHint, destructiveHint=false), so the bar is lower. The description still adds substantial domain-level behavior: the count is taken at any role and cannot be restricted to suspect substances, producing a list skewed toward concomitant medication. This is real interpretive value not available 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?
Two short sentences, zero filler, and the most important caveat is front-loaded right after the core statement. Every clause 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?
An output schema exists, so return-value details are not the description's burden. For a six-parameter analytical tool, the description supplies exactly the missing piece an agent needs, the co-reported vs co-suspect distinction, and nothing extraneous.
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%, with every parameter (top_n, events, date_from/date_to, drug_name, raw_filter) documented in the schema including formats and pairing constraints. The description adds no parameter-level meaning beyond what the schema provides, so the baseline 3 applies.
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 (substances most often appearing on the same reports as an index drug) and immediately disambiguates the semantics with 'Co-REPORTED at any role, not co-suspect'. This distinguishes it from a naive suspect-based co-occurrence reading, which is the main confusion risk with siblings like faers_disproportionality.
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?
The description gives a clear condition and an implicit warning: the output 'is dominated by concomitant medication', so the agent knows the tool cannot answer suspect-only questions. It does not, however, name the alternative tool to use when suspect-restricted analysis is required, leaving that inference to the agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
faers_count_by_fieldBRead-onlyIdempotent
Aggregate FAERS reports for a drug by any field (SQL GROUP BY equivalent).
| Name | Required | Description | Default |
|---|---|---|---|
| top_n | No | Number of values to return. | |
| events | No | MedDRA preferred terms, e.g. ['PANCREATITIS']. Case-insensitive. | |
| date_to | No | End of a receivedate window, YYYYMMDD. Must be paired with date_from. | |
| date_from | No | Start of a receivedate window, YYYYMMDD. Must be paired with date_to. | |
| drug_name | Yes | Active substance name, e.g. 'EMPAGLIFLOZIN'. | |
| raw_filter | No | Extra Lucene clause ANDed onto the preset query, e.g. 'patient.patientsex:2'. Applied to every marginal of a contingency table. See faers_describe_fields. | |
| count_field | Yes | FAERS field to aggregate, e.g. 'patient.reaction.reactionmeddrapt.exact'. See faers_describe_fields for the catalogue. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and destructiveHint=false, covering the safety profile. The description adds the useful aggregation semantics via the SQL GROUP BY analogy, but says nothing about result limits or query behavior beyond what annotations and schema imply.
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?
One tightly written sentence that front-loads the action, resource, and scope. It contains no filler or redundant restatement.
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?
The output schema, rich annotations, and full schema coverage mean the description need not explain return values or parameter details. However, for a seven-parameter aggregation tool in a crowded sibling set, the description is thin on sibling differentiation and usage context.
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 all seven parameters are documented in the schema itself. The description adds only the generic 'by any field' concept, not parameter-specific syntax or constraints beyond what the schema already provides.
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: aggregate FAERS reports for a drug by any field, with a helpful SQL GROUP BY equivalent. It is clear but does not explicitly distinguish itself from specialized siblings such as faers_top_events or faers_outcome_breakdown.
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 no when-to-use guidance, prerequisites, or alternatives to sibling tools. The SQL GROUP BY analogy hints at generic aggregation, but the agent receives no routing advice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
faers_demographic_profileARead-onlyIdempotent
Sex, age, reporter qualification and country breakdown for a drug.
Age is reported two ways: the coded patientagegroup (populated on ~18% of reports) and bands derived from patientonsetage in years (~55%), the same bands the stratifiers use. Each carries its own coverage against the total.
| Name | Required | Description | Default |
|---|---|---|---|
| events | No | MedDRA preferred terms, e.g. ['PANCREATITIS']. Case-insensitive. | |
| date_to | No | End of a receivedate window, YYYYMMDD. Must be paired with date_from. | |
| date_from | No | Start of a receivedate window, YYYYMMDD. Must be paired with date_to. | |
| drug_name | Yes | Active substance name, e.g. 'EMPAGLIFLOZIN'. | |
| raw_filter | No | Extra Lucene clause ANDed onto the preset query, e.g. 'patient.patientsex:2'. Applied to every marginal of a contingency table. See faers_describe_fields. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnly, idempotent, openWorld, non-destructive), so the description earns credit for the data-quality disclosure: patientagegroup populated on ~18% of reports versus derived bands at ~55%, and that the raw_filter is ANDed onto every marginal of a contingency table. This is exactly the kind of behavior an agent cannot read off the schema.
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 returned dimensions, then a compact clarification of the two age representations. Two sentences, no filler; only mild density in the parenthetical coverage figures.
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?
With an output schema present, return values need not be explained, and the description supplies the caveats an analyst needs (coverage percentages, dual age encodings, filter interaction). Adequate for a read-only profiling tool, though it could note the interaction with the events/date parameters.
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 parameters are already documented and a baseline of 3 applies. The description adds that the derived bands are 'the same bands the stratifiers use,' which is a small semantic bonus but not new syntax or format detail.
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 resource and the exact dimensions returned: sex, age, reporter qualification, and country breakdown for a drug. It is clear what the tool produces, though it never names the sibling it is distinct from (e.g., faers_count_by_field or faers_outcome_breakdown), so an agent must infer the boundary.
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?
There is no statement of when to use this tool rather than the demographic-capable siblings, nor any prerequisites or exclusions. The age-methodology note is useful background but is not usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
faers_describe_fieldsARead-onlyIdempotent
Searchable FAERS field paths with coded values and traps, plus the available stratifiers.
Consult before writing a raw_filter or count_field rather than guessing a path.
| Name | Required | Description | Default |
|---|---|---|---|
| category | No | Narrow to one category. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint, idempotentHint, openWorldHint, and destructiveHint=false, so the safety profile is covered. The description adds that the catalogue includes 'traps' (worth flagging as non-obvious behavioral context). There's no output schema shown to the agent in the prompt despite has_output_schema=true, but the description doesn't need to explain return values further.
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?
Two short sentences, front-loaded with what the tool returns, followed by a concrete when-to-use instruction. 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 read-only lookup/catalogue tool with full schema coverage and an output schema, the description is sufficient: it tells the agent what it contains and when to call it instead of guessing field paths.
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% and the single optional 'category' param is documented with an enum and description. The description adds minimal parameter-specific semantics but the baseline for a well-covered single optional param is high.
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 resource (FAERS field paths) and what it returns (coded values, traps, stratifiers). Clearly distinguishable from siblings like faers_raw_search or faers_count_by_field, which are data-retrieval tools rather than a field catalogue.
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 instructs the agent to consult this before writing a raw_filter or count_field rather than guessing a path. This names the alternatives and the condition that selects this tool, which is exactly the routing guidance an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
faers_disproportionalityARead-onlyIdempotent
Build the 2x2 contingency table and compute ROR, PRR and chi-square.
Any date window or raw_filter is applied to all four marginals including the grand total N, so the table stays internally consistent. Screening criteria are reported individually by name rather than collapsed into a verdict.
| Name | Required | Description | Default |
|---|---|---|---|
| events | Yes | One or more MedDRA preferred terms. | |
| date_to | No | End of a receivedate window, YYYYMMDD. Must be paired with date_from. | |
| date_from | No | Start of a receivedate window, YYYYMMDD. Must be paired with date_to. | |
| drug_name | Yes | Active substance name, e.g. 'EMPAGLIFLOZIN'. | |
| raw_filter | No | Extra Lucene clause ANDed onto the preset query, e.g. 'patient.patientsex:2'. Applied to every marginal of a contingency table. See faers_describe_fields. | |
| role_basis | No | 'any' counts every report naming the drug in any role. 'suspect_verified' is only computable where records are in hand (faers_search_cases, faers_raw_search). | any |
| stratify_by | No | Adjust for a confounder by Mantel-Haenszel pooling. Reports crude and adjusted side by side with a Breslow-Day homogeneity test. Adds 4 calls per outer band. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
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 genuinely non-annotation behavior: date/raw_filter constraints propagate to all four marginals including the grand total N to preserve internal consistency, and screening criteria are reported individually rather than collapsed into a verdict. Return format details are left to the output schema.
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?
Two tight sentences, front-loaded with the tool's output and followed by a single clarifying paragraph on consistency and reporting semantics. Nothing is wasted or restated from structured fields.
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 analysis tool with an output schema, annotations, and 100% schema coverage, the description supplies the key behavioral context an agent needs (marginal consistency, per-criterion output). The main remaining gap is tool-selection guidance versus faers_ebgm and faers_signal_screen.
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 real meaning beyond the schema by explaining that date window and raw_filter are applied to every marginal including the grand total. That interaction semantics is not derivable from the parameter descriptions alone. It does not, however, elaborate on role_basis or stratify_by cost/behavior beyond 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 and computational artifact ('Build the 2x2 contingency table and compute ROR, PRR and chi-square'), which is concrete and distinct from count- or search-oriented siblings. It does not, however, differentiate itself from faers_ebgm, the other disproportionality estimator in the sibling set, so an agent gets no direct comparison cue.
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?
There is no explicit when-to-use or when-not guidance, and no alternative is named. The second paragraph describes mechanics (marginal consistency, per-criterion reporting) rather than selection criteria against faers_ebgm, faers_signal_screen, or faers_case_counts.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
faers_ebgmARead-onlyIdempotent
Empirical Bayes signal scores (EBGM with EB05/EB95) via the Gamma-Poisson Shrinker.
EBGM shrinks the observed-to-expected ratio toward 1 in proportion to how little evidence supports it. EB05 is the conventional screening statistic; EB05 > 2 is the usual threshold. The prior is fitted across a drug x event background table, so the FIRST call for a FAERS release builds and caches that table (~100 s, 3 + background_drugs calls). Call faers_warm_cache first, or raise the client timeout. Later calls take a few seconds.
| Name | Required | Description | Default |
|---|---|---|---|
| top_n | No | Events to score when `events` is omitted. | |
| events | No | Specific MedDRA PTs. Omit to score the drug's most-reported events. | |
| date_to | No | End of a receivedate window, YYYYMMDD. Must be paired with date_from. | |
| date_from | No | Start of a receivedate window, YYYYMMDD. Must be paired with date_to. | |
| drug_name | Yes | Active substance name, e.g. 'EMPAGLIFLOZIN'. | |
| min_cases | No | Minimum observed count for a row. | |
| raw_filter | No | Extra Lucene clause ANDed onto the preset query, e.g. 'patient.patientsex:2'. Applied to every marginal of a contingency table. See faers_describe_fields. | |
| stratify_by | No | Adjust expected counts for a confounder. Stratification enters MGPS only through E, so the prior is refitted. ~2 calls per stratum, cached. 'year' resolves its strata from the data and prunes negligible years. | |
| background_drugs | No | Substances in the background table the prior is fitted on. Building it costs 3 + this many calls, once per FAERS release, then it is cached. | |
| background_events | No | Terms in the background table. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent/openWorld annotations, the description discloses the expensive first-call cost (~100 s, 3 + background_drugs calls), the caching lifetime (once per FAERS release), and the timeout remedy. This is exactly the behavioral context an agent needs before invoking a tool that can block for minutes.
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?
Roughly five sentences, front-loaded with the method and the screening threshold, then the cost warning. Dense but every line carries information; the only flab is mild detail on the shrinker mechanics.
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?
With a rich 10-parameter schema, an output schema, and full annotation coverage, the description correctly focuses on the non-obvious parts: cost, caching, and stratification side effects. The remaining gap is the absence of sibling routing guidance for a tool in a cluster of signal-detection alternatives.
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 real semantics: stratification enters MGPS only through expected counts so the prior is refitted, ~2 calls per stratum, and 'year' resolves and prunes strata from the data. That meaning isn't recoverable from the schema descriptions alone.
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 statistic and method ('Empirical Bayes signal scores (EBGM with EB05/EB95) via the Gamma-Poisson Shrinker') and explains what EBGM does mechanically. An agent can tell this computes Bayesian disproportionality scores rather than raw counts, though it never explicitly distinguishes itself from faers_disproportionality or faers_signal_screen.
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 interpretive guidance ('EB05 is the conventional screening statistic; EB05 > 2 is the usual threshold') and an operational instruction to call faers_warm_cache first or raise the timeout. However, it never says when to prefer this tool over faers_disproportionality or faers_signal_screen, so sibling selection 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.
faers_get_reportARead-onlyIdempotent
Retrieve one complete ICSR by Safety Report ID.
The only tool that returns an unprojected record; a single ICSR averages ~72 KB.
| Name | Required | Description | Default |
|---|---|---|---|
| safetyreportid | Yes | FDA Safety Report ID. Usually a plain 8-digit number such as 10084081. A hyphenated form (1234567-1) is accepted and both forms are tried. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly, idempotent, non-destructive). The description adds genuinely useful cost/behavior context the annotations don't: the record is unprojected and averages ~72 KB, warning the agent about payload size. It doesn't mention pagination or error behavior for missing IDs, but the size disclosure is valuable.
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?
Two short sentences, front-loaded with the action and scope, then the differentiator and size warning. Zero waste.
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?
With an output schema present, the description needn't explain return values, and annotations cover safety. It supplies the key behavioral fact (unprojected, large) that structured fields don't. Only usage routing against siblings is thin.
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% and the parameter schema already documents the ID format, pattern, plain 8-digit form, and hyphenated fallback. The description adds nothing beyond 'by Safety Report ID'. Baseline 3 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?
States a specific verb+resource: retrieve one complete ICSR by Safety Report ID. The claim of being 'the only tool that returns an unprojected record' differentiates it from the many projection-oriented siblings, though it doesn't name a specific alternative.
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?
No explicit when-to-use guidance or named alternative. The 'only tool' claim implies it's for full-record retrieval vs siblings, but an agent gets no condition for choosing it over faers_search_cases or faers_raw_search.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
faers_outcome_breakdownBRead-onlyIdempotent
Reaction outcomes and seriousness criteria for a drug, in one concurrent round trip.
| Name | Required | Description | Default |
|---|---|---|---|
| events | No | MedDRA preferred terms, e.g. ['PANCREATITIS']. Case-insensitive. | |
| date_to | No | End of a receivedate window, YYYYMMDD. Must be paired with date_from. | |
| date_from | No | Start of a receivedate window, YYYYMMDD. Must be paired with date_to. | |
| drug_name | Yes | Active substance name, e.g. 'EMPAGLIFLOZIN'. | |
| raw_filter | No | Extra Lucene clause ANDed onto the preset query, e.g. 'patient.patientsex:2'. Applied to every marginal of a contingency table. See faers_describe_fields. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is fully covered elsewhere. The description's only added behavioral fact is the concurrent single-round-trip execution model, which is genuinely useful but thin; nothing is said about result limits, cardinality caps, or how marginals are returned.
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?
A single front-loaded sentence with no filler. Every clause carries information: the two output dimensions and the round-trip efficiency property.
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?
With an output schema present and 100% parameter documentation in the schema, the description need not explain return values or parameter formats. It is essentially complete for invocation purposes, though it could have used one clause to distinguish this breakdown tool from the other aggregation siblings.
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 every parameter (drug_name, events, date_from/date_to pairing, raw_filter) is already documented in the schema, including the Lucene clause syntax and the required pairing rule. The description adds no parameter meaning beyond that, which is the expected baseline 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 names a concrete subject (reaction outcomes and seriousness criteria for a drug), so an agent can tell it produces an outcome/seriousness aggregation. However, it gives no differentiation from aggregation siblings like faers_count_by_field, faers_top_events, or faers_demographic_profile, so an agent must guess which aggregation tool to pick.
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?
There is no explicit when-to-use or when-not-to-use guidance. The phrase 'in one concurrent round trip' hints that this tool is a more efficient alternative to issuing separate outcome and seriousness queries, but that is an efficiency hint, not a routing rule, and no alternative sibling is named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
faers_raw_searchARead-onlyIdempotent
Escape hatch: run an arbitrary Lucene query against the FAERS endpoint.
The query is checked for balanced quotes and parentheses and for the "+AND+" mistake before being sent; the same compact projection and ceilings apply.
| Name | Required | Description | Default |
|---|---|---|---|
| full | No | Return complete records rather than compact cards. | |
| skip | No | Pagination offset (openFDA ceiling 25000). | |
| sort | No | e.g. 'receivedate:desc'. | |
| count | No | Field to aggregate by. When set, results are {term, count} rows instead of records. | |
| limit | No | Records or count rows to return. | |
| search | Yes | Raw Lucene query, e.g. 'patient.patientsex:2 AND serious:1'. Join clauses with spaces (" AND ", " OR "), never "+AND+". | |
| drug_name | No | Optional substance to annotate on each returned card as suspect_verified (true when carried in a suspect role on that record). Annotates only; does not filter. Use faers_search_cases with role_basis='suspect_verified' to filter. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnlyHint, idempotentHint, destructiveHint=false), so the bar is lower, and the description still adds real behavior: pre-flight validation of balanced quotes/parentheses, detection of the '+AND+' mistake, and that the same compact projection and ceilings apply as elsewhere. The projection/ceiling reference is left vague, but the validation disclosure is genuine added value.
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?
Two sentences with no filler, and the identity of the tool ('escape hatch') is front-loaded. The trailing clause about projection and ceilings is slightly compressed to the point of ambiguity, which keeps it out of 5 territory.
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?
An output schema exists, so return values need not be described, and the description covers the non-obvious input-validation behavior. For a seven-parameter openWorld tool it is nearly complete; the omitted piece is explicit routing guidance against the many structured siblings.
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 schema already documents all seven parameters, including the annotate-only semantics of drug_name. The description adds no syntax or format detail beyond what the schema provides, so the baseline 3 applies.
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 (run) and resource (arbitrary Lucene query against the FAERS endpoint), and the 'escape hatch' framing immediately distinguishes it from the structured siblings like faers_search_cases. It stops short of naming which siblings it supersedes in which situation, but the core purpose is unambiguous.
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?
'Escape hatch' implies the usage condition — reach for this when the curated tools cannot express what you need — but the description never states that explicitly or names an alternative. The guidance is implied rather than stated; a reader must infer when this beats faers_search_cases.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
faers_search_casesARead-onlyIdempotent
Search FAERS for individual case safety reports (ICSRs).
Returns compact triage cards by default: report id, dates, seriousness flags, suspect drugs, reactions and outcomes. Pass full=true for complete records.
| Name | Required | Description | Default |
|---|---|---|---|
| full | No | Return complete ICSR records (~72 KB each) instead of compact cards. | |
| skip | No | Pagination offset (openFDA ceiling 25000). | |
| sort | No | openFDA sort, e.g. 'receivedate:desc'. | receivedate:desc |
| limit | No | Records per page. | |
| events | No | MedDRA preferred terms, e.g. ['PANCREATITIS']. Case-insensitive. | |
| date_to | No | End of a receivedate window, YYYYMMDD. Must be paired with date_from. | |
| date_from | No | Start of a receivedate window, YYYYMMDD. Must be paired with date_to. | |
| drug_name | Yes | Active substance name, e.g. 'EMPAGLIFLOZIN'. | |
| fatal_only | No | Restrict to fatal cases (seriousnessdeath=1). | |
| raw_filter | No | Extra Lucene clause ANDed onto the preset query, e.g. 'patient.patientsex:2'. Applied to every marginal of a contingency table. See faers_describe_fields. | |
| role_basis | No | 'suspect_verified' checks each returned record for the drug in a suspect role. | any |
| serious_only | No | Restrict to serious cases (serious=1). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish the safety profile (readOnly, idempotent, openWorld, non-destructive), and the description adds real value on top: the default return shape is a compact triage card enumerating report id, dates, seriousness flags, suspect drugs, reactions and outcomes, and full=true yields complete records. It doesn't mention the openFDA pagination ceiling (25000) or rate limits, but that is minor.
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?
Three tight sentences, front-loaded with the core action and then the return-mode distinction. The field list in sentence two is slightly over-enumerated given the output schema exists, but nothing is wasted.
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 12-parameter read-only search with 100% schema coverage and an output schema, the description supplies everything the agent needs: what it does, the default compact return, and how to opt into full records. No material gaps remain.
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 schema already documents all 12 parameters including 'full'. The description only amplifies 'full' versus the default card mode and adds nothing for skip/sort/limit/dates. Baseline 3 is appropriate when the schema carries the semantic load.
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 states a specific verb ('Search') and resource ('FAERS individual case safety reports (ICSRs)'), which is more precise than the sibling names alone. It does not explicitly name which sibling (e.g. faers_raw_search, faers_get_report) it contrasts with, so an agent still has to infer the boundary, keeping it out of 5 territory.
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 one internal usage rule ('Pass full=true for complete records') but no when-to-use/when-not guidance relative to the many siblings. The agent must infer whether this or faers_raw_search, faers_case_counts, or faers_get_report is the right entry point.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
faers_signal_screenARead-onlyIdempotent
Screen a drug against all its reported events, or an event against all its drugs.
ROR, PRR and chi-square for every term with named criteria. The database-wide marginals come from a single cached count call rather than one call per term, so a 200-term screen costs ~13 calls cold and ~10 warm. Any date window or raw_filter is applied to every marginal.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | Screen a drug against its events, or an event against its drugs. | drug |
| term | Yes | Active substance (mode='drug') or MedDRA PT (mode='event'). | |
| top_n | No | How many terms to screen. | |
| date_to | No | End of a receivedate window, YYYYMMDD. Must be paired with date_from. | |
| sort_by | No | Statistic to sort rows by. | ror_lower |
| return_n | No | How many rows to return. | |
| date_from | No | Start of a receivedate window, YYYYMMDD. Must be paired with date_to. | |
| min_cases | No | Minimum case count for a row to be reported. | |
| raw_filter | No | Extra Lucene clause ANDed onto the preset query, e.g. 'patient.patientsex:2'. Applied to every marginal of a contingency table. See faers_describe_fields. | |
| signals_only | No | Return only rows meeting the EMA ROR criterion. | |
| max_fallback_calls | No | Cap on per-term lookups for terms absent from the cached global marginal table. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld). The description adds genuinely useful behavior beyond that: the cached-marginal cost model (~13 calls cold, ~10 warm) and the rule that any date window or raw_filter propagates to every marginal of the contingency table. It stops short of rate-limit or failure behavior.
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?
Four sentences, front-loaded with the purpose, then statistics, then cost, then filter propagation. Efficient overall, though the call-count detail is more than strictly required for selection and slightly dilutes the otherwise tight structure.
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?
With an output schema present and 100% schema coverage, the description need not explain return values. It covers scope, statistics, cost, and filter propagation, leaving only explicit sibling routing as a gap for a tool with 15 siblings.
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 the schema by clarifying propagation semantics for date window and raw_filter ('applied to every marginal'), which the per-parameter schema text does not state, warranting a step above baseline.
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 states a specific verb (screen) and resource scope (a drug against all its events, or an event against all its drugs), and names the statistics produced (ROR, PRR, chi-square). The 'all its reported events/drugs' scope distinguishes it from the single-pair sibling faers_disproportionality, though it never names that sibling 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?
Usage is implied by the bulk scope and the cost discussion, but the description never states when to pick this over faers_disproportionality, faers_ebgm, or faers_top_events, nor any prerequisites or exclusions. The agent must infer the right context from scope alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
faers_time_trendARead-onlyIdempotent
Yearly reporting trend for a drug, aggregated from receivedate.
count=receivedate returns a complete date histogram irrespective of limit, so the yearly rollup is exact. Date buckets arrive keyed "time", not "term".
| Name | Required | Description | Default |
|---|---|---|---|
| events | No | MedDRA preferred terms, e.g. ['PANCREATITIS']. Case-insensitive. | |
| date_to | No | End of a receivedate window, YYYYMMDD. Must be paired with date_from. | |
| date_from | No | Start of a receivedate window, YYYYMMDD. Must be paired with date_to. | |
| drug_name | Yes | Active substance name, e.g. 'EMPAGLIFLOZIN'. | |
| raw_filter | No | Extra Lucene clause ANDed onto the preset query, e.g. 'patient.patientsex:2'. Applied to every marginal of a contingency table. See faers_describe_fields. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds genuinely new behavioral context: the aggregation is exact because the receivedate histogram ignores limit, and result buckets are keyed 'time' rather than 'term'. That is real added value 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?
Three short sentences with no filler, and the core purpose is front-loaded. The second and third sentences are implementation notes rather than padding, though the fragmentation and mid-sentence line break make it slightly less polished than it could be.
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?
An output schema exists, so return-value documentation is not required. The description still supplies the two things an agent would otherwise misread (exactness under limit, and the 'time' key), leaving little missing for a 5-parameter read-only aggregation 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 description coverage is 100%, so all five parameters (drug_name, events, date_from, date_to, raw_filter) are already documented in the schema, including the date pairing constraint and the Lucene example. The description adds no parameter-level detail beyond naming receivedate as the underlying date field, so the baseline 3 applies.
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 states a specific verb and resource: a yearly reporting trend for a drug, aggregated from receivedate. That is clear enough to distinguish it from case-lookup siblings like faers_search_cases or faers_get_report, though it never names a sibling explicitly (e.g. faers_count_by_field) to sharpen the boundary.
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?
Usage is implied by the framing (temporal trend analysis) but there is no explicit when-to-use guidance, no when-not-to-use, and no alternative tool named for the same job. The note that 'count=receivedate returns a complete date histogram irrespective of limit' hints at method rather than at when to prefer this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
faers_top_eventsARead-onlyIdempotent
Top MedDRA preferred terms reported with a drug.
Convenience form of faers_count_by_field with the reaction field preset.
| Name | Required | Description | Default |
|---|---|---|---|
| top_n | No | Number of PTs to return. | |
| date_to | No | End of a receivedate window, YYYYMMDD. Must be paired with date_from. | |
| date_from | No | Start of a receivedate window, YYYYMMDD. Must be paired with date_to. | |
| drug_name | Yes | Active substance name, e.g. 'EMPAGLIFLOZIN'. | |
| raw_filter | No | Extra Lucene clause ANDed onto the preset query, e.g. 'patient.patientsex:2'. Applied to every marginal of a contingency table. See faers_describe_fields. | |
| serious_only | No | Restrict to serious cases. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false and openWorldHint=true, so the safety/behavior profile is covered. The description adds the preset-field semantics but says nothing about sorting, ranking ties, result limits beyond top_n, or data-source caveats; with annotations carrying the load, a 3 is appropriate.
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?
Two short sentences, purpose first and the sibling relationship second, with zero filler. Everything 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?
An output schema exists, so return structure needn't be explained, and the schema documents all parameters. The description adequately covers purpose and how it relates to the parent tool, though it omits why one would choose the top-N preset over full field counts (e.g., default top_n=20 is not surfaced in prose).
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 all six parameters (top_n default/range, date window pairing, drug_name format, raw_filter Lucene syntax, serious_only) are already documented in the schema. The description adds no parameter detail beyond implying the reaction field; baseline 3 applies.
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 ('Top MedDRA preferred terms reported with a drug') and then explicitly positions itself as a preset convenience form of faers_count_by_field with the reaction field, which distinguishes it from that sibling 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?
By naming faers_count_by_field and stating the field is preset to reaction, it implicitly tells the agent when to reach for this tool (reaction counting) versus the general one (any field). It stops short of explicit when-not conditions or other alternatives, so it lands at 4 rather than 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
faers_warm_cacheARead-onlyIdempotent
Build the EBGM background table and fit the prior ahead of time.
The first faers_ebgm call for a FAERS release takes ~100 s and 100+ API calls, which exceeds many MCP client timeouts. Calling this tool first moves that cost to a turn that expects it; subsequent faers_ebgm calls take a few seconds. Reports whether each cache was already warm.
| Name | Required | Description | Default |
|---|---|---|---|
| date_to | No | End of a receivedate window, YYYYMMDD. Must be paired with date_from. | |
| date_from | No | Start of a receivedate window, YYYYMMDD. Must be paired with date_to. | |
| stratify_by | No | Also build the per-stratum marginals and fit the stratified prior. | |
| background_drugs | No | Substances in the background table the prior is fitted on. Building it costs 3 + this many calls, once per FAERS release, then it is cached. | |
| background_events | No | Terms in the background table. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses latency, API-call cost, timeout risk, and warm-cache reporting — none of which the annotations carry. The annotations cover safety (readOnly/idempotent/non-destructive), and the description adds the operational economics the agent needs to sequence calls, clarifying that the behavior is a benign cache build rather than a domain mutation.
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?
Four tight sentences, front-loaded with the action and immediately followed by the justification. No filler, and the cost/benefit framing is exactly what an agent needs before committing to a long call.
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?
An output schema exists, so return values need no explanation, and the description still notes it reports warm-cache state. With annotations covering safety and the schema covering all five parameters, nothing required to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so every parameter including the date-window pairing rule and the enum for stratify_by is already documented inline. The description only alludes to 'background table' and 'prior' without adding format or constraint detail beyond the schema, so the baseline 3 is correct.
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 concrete action on a named artifact: build the EBGM background table and fit the prior. It explicitly positions itself relative to faers_ebgm, so an agent can distinguish it from all 14 siblings without opening a 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?
Gives explicit when-to-use guidance (call this first, before faers_ebgm) and quantifies why (the first faers_ebgm call costs ~100 s and 100+ API calls and can exceed client timeouts). It also implies when not to bother, since it reports whether each cache was already warm.
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.
15 tool updates
v0.1.0- First observed
faers_case_counts - First observed
faers_coreported_drugs - First observed
faers_count_by_field - First observed
faers_demographic_profile - First observed
faers_describe_fields - First observed
faers_disproportionality - First observed
faers_ebgm - First observed
faers_get_report - First observed
faers_outcome_breakdown - First observed
faers_raw_search - First observed
faers_search_cases - First observed
faers_signal_screen - First observed
faers_time_trend - First observed
faers_top_events - First observed
faers_warm_cache
TDQS
Scored across 15 tools
Most tools have clearly distinct purposes, but there is notable overlap among counting/aggregation tools (faers_case_counts, faers_count_by_field, faers_top_events) and signal detection tools (faers_signal_screen vs faers_disproportionality). The detailed descriptions clarify scope (e.g., top_events is a convenience form, signal_screen screens all terms), so an agent can usually tell them apart, but a few could still be confused.
All tools use a consistent faers_ prefix and snake_case, which is predictable. However, the naming pattern is not strictly verb_noun throughout; it mixes verb phrases (search_cases, get_report) with noun phrases (case_counts, demographic_profile) and acronyms (ebgm). This is a minor deviation from the ideal verb_noun consistency.
15 tools is appropriate for a comprehensive FAERS analysis server, covering search, retrieval, aggregation, signal detection, and specialized metrics. Each tool appears to earn its place, with only minor redundancy (e.g., top_events as a convenience wrapper). The count is at the upper end of the ideal 3-15 range but well-scoped.
The tool set covers the full lifecycle of FAERS analysis: search (structured and raw), retrieval, counts, disproportionality, EBGM, demographics, outcomes, trends, and co-reported drugs. Field description and cache warming are also included. No obvious gaps for typical signal detection workflows.
Maintenance
Related MCP Connectors
OpenFDA MCP — wraps the openFDA API (free, no auth required)
Search FDA safety data: drug adverse events, recalls, and device events.
Query FDA data on drugs, food, devices, and recalls via openFDA. STDIO or Streamable HTTP.
FDA medical-device regulatory intelligence from keyless openFDA datasets.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI agents to query and analyze FDA adverse events, drug labels, medical device clearances, and other public health datasets through natural language commands.13-
- AlicenseNot gradedqualityAmaintenanceQuery FDA data on drugs, food, devices, and recalls via openFDA. Provides 12 tools for searching adverse events, drug labels, recalls, and more.135 npm4Apache 2.0
- FlicenseNot gradedqualityDmaintenanceEnables querying FDA drug approvals, device clearances (510(k)), recalls, and adverse events via the openFDA API, providing tools for clinical and pharmaceutical research.1-
- AlicenseAqualityDmaintenanceEnables LLMs to search FDA drug labels and adverse event data via the OpenFDA API, supporting natural language queries for drug safety information.2MIT