MedBridge

MedBridge

An MCP server that gives LLMs live access to clinical trials, FDA drug recalls, adverse-event reports, drug labels, and drug-name normalization via six validated tools.

Category
Visit Server

README

MedBridge

An MCP server that gives an LLM live access to clinical trials, FDA drug recalls, adverse-event reports, drug labels, and drug-name normalization.

MCP (Model Context Protocol) is an open protocol that lets an AI application discover and call external tools over a standard interface. A client — Claude Desktop, an MCP-compatible IDE, or a custom agent — connects to a server, asks what tools it offers, and invokes them with typed arguments; MedBridge is one such server, wrapping three public healthcare APIs behind six validated tools.

Demo: asking Claude Desktop about recruiting diabetes trials near Dallas and metformin recalls, tools firing live

Claude Desktop answering from live data: search_trials returns recruiting Dallas trials by NCT number, then search_drug_recalls pulls FDA enforcement records for metformin.

This is informational public data only. Nothing MedBridge returns is medical advice, and it is not a clinical decision tool.

Tools

Tool Purpose Key parameters
search_trials Find clinical trials for a condition condition, status, location, max_results
get_trial Full record for one trial, including eligibility criteria nct_id
search_drug_recalls FDA recall/enforcement reports for a drug drug_name, max_results
get_adverse_events Most frequently reported side effects for a drug drug_name, top_n
get_drug_label FDA-approved label: indications, warnings, dosage forms drug_name
normalize_drug_name Resolve a (possibly misspelled) drug name to its RxNorm concept name

Every response carries source and retrieved_at. Long text fields are truncated at stated limits with a <field>_truncated: true flag when cut. Failures come back as a structured {error: true, error_type, message} rather than a stack trace or a silently empty result — see Design decisions.

Install

Requires Python 3.11+.

git clone <this-repository-url> medbridge-mcp
cd medbridge-mcp
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

OPENFDA_API_KEY is optional — it raises openFDA's rate limit but every tool works without it. To set it:

cp .env.example .env
# then edit .env and set OPENFDA_API_KEY=your-key-here

Confirm the install:

pytest -q

Connect to Claude Desktop

Claude Desktop launches MCP servers as a local subprocess, configured in its claude_desktop_config.json:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Add a medbridge entry pointing at the venv's Python interpreter, running the server as a module. examples/claude_desktop_config.json has the template:

{
  "mcpServers": {
    "medbridge": {
      "command": "/ABSOLUTE/PATH/TO/medbridge-mcp/.venv/bin/python",
      "args": ["-m", "medbridge.server"]
    }
  }
}

Replace the path with the absolute path to your clone's .venv/bin/python, then restart Claude Desktop fully.

Running under WSL: Claude Desktop only ships for macOS and Windows, so on WSL the Windows-side Desktop app has to reach into the Linux filesystem to launch the server. Point command at wsl.exe instead and pass the real command as arguments — see examples/claude_desktop_config.wsl.json:

{
  "mcpServers": {
    "medbridge": {
      "command": "wsl.exe",
      "args": ["-d", "Ubuntu-24.04", "--", "/ABSOLUTE/PATH/TO/medbridge-mcp/.venv/bin/python", "-m", "medbridge.server"]
    }
  }
}

Replace Ubuntu-24.04 with your distro name from wsl.exe -l -v if it differs.

Once connected, Claude Desktop lists the six tools under its tools/search indicator and prompts for approval on first use of each.

Any MCP client

Nothing here is Claude-specific beyond the config file format. Any client that speaks the MCP stdio transport — an MCP-compatible IDE, a custom agent script, another chat client — can launch the same command (/path/to/.venv/bin/python -m medbridge.server) and connect. The server has no knowledge of which client is on the other end.

For interactive debugging outside any client, the official inspector works too (requires Node):

npx @modelcontextprotocol/inspector /ABSOLUTE/PATH/TO/medbridge-mcp/.venv/bin/python -m medbridge.server

Design decisions

Outputs are shaped, not proxied. Raw upstream JSON is deeply nested and full of fields no one asking a question needs — a tool response for LLM consumption is an interface design problem, not a pass-through. get_adverse_events, for instance, returns ranked reaction counts instead of raw case records, and long free-text fields are cut to stated limits with a truncation flag so the model reading the output knows it's seeing a summary rather than the whole field.

Errors are structured and honest. Every failure maps to exactly one of four types — not_found, upstream_unavailable, rate_limited, invalid_input — carried in a small dict a model can act on, instead of a stack trace. Zero legitimate matches is a success carrying an empty list and a note; only an actual failure sets error: true. That distinction is what lets a tool answer "no recalls found" correctly instead of a model guessing from a bare empty list whether the search worked.

Every response carries provenance: source (which upstream API answered) and retrieved_at (when). Public health data changes; a model — and the person reading its answer — should know how fresh it is and where it came from.

Caching is a single-process, in-memory TTL dict keyed on URL and sorted query parameters, not an external cache. The server is one process speaking stdio to one client at a time, so there's no second process to share cache state with, and no concurrent writer to guard against — an external cache would be deployment theater at this scale. It exists because public APIs are shared infrastructure and the same question tends to come up more than once in a conversation; repeated identical requests inside the TTL window are served from memory rather than hitting the network again. Retries on 429 and 5xx use exponential backoff for the same reason: a demo that hammers a public API on transient errors fails unpredictably and disrespects rate limits.

normalize_drug_name's candidates carry a match_source field (spelling_suggestion or approximate_term) beyond the minimal {name, rxcui, score} shape. This came from testing RxNorm's approximateTerm endpoint directly: for a misspelling like "metfromin" it ranks lexically similar but wrong concepts (e.g. "merbromin") above the intended drug and never surfaces it in a usable number of results. spellingsuggestions does return "metformin" for that input. Both endpoints answer genuinely different questions — one corrects a typo, the other finds lexically similar concepts — so both are consulted and merged, and each candidate names which one produced it.

Testing

pytest -q

60 tests, entirely offline — every upstream call is intercepted with respx against real response payloads captured live from all three APIs and trimmed to the fields the code actually reads (tests/fixtures/). Coverage spans the HTTP layer (success paths, openFDA's 404-means-empty convention, retry-then-succeed on 5xx, exhausted retries on 429 mapping to rate_limited, timeout mapping to upstream_unavailable), the pure shaping functions (exact output shapes, truncation flags, adverse-event aggregation), input validation (malformed identifiers, out-of-range counts, blank strings), and tool-level contracts (every success path carries source and retrieved_at; every failure path returns a structured error instead of raising).

Data sources and their terms

Source Base URL Notes
ClinicalTrials.gov clinicaltrials.gov/api/v2 U.S. government public data; no key required. See terms and conditions.
openFDA api.fda.gov No key required; optional key raises the rate limit. openFDA explicitly disclaims the data as not for real-time clinical or production decision-making without independent verification — see openFDA terms.
RxNorm (NLM RxNav) rxnav.nlm.nih.gov/REST No key required for API access. RxNorm draws on source vocabularies that fall under the UMLS Metathesaurus; broader use beyond simple normalization lookups may require a free UMLS Metathesaurus License.

Limitations and future work

  • No drug-drug interaction tool. NLM's interaction API was retired; interaction data would need a different, licensed source, so this scope was cut rather than faked with a weaker substitute.
  • No pagination. Search tools return up to max_results (max 25) in one call; there's no cursor or next-page token for walking a full result set.
  • stdio transport only. No HTTP/SSE server mode, so MedBridge currently only runs as a locally spawned subprocess, not as a remote service multiple clients could share.
  • Tool layer, not yet an agent. MedBridge exposes these six tools to any MCP client today; wiring the same server into an autonomous agent loop that chains calls (search a trial, then check the drug's recalls, then normalize a name it wasn't sure about) is the natural next step.

License

MIT — see LICENSE.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured