Skip to main content
Glama
index.ts13.2 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; import { createErrorResponse, formatDrugSearchResults, formatDrugDetails, formatHealthIndicators, formatPubMedArticles, formatGoogleScholarArticles, formatMedicalDatabasesSearch, formatMedicalJournalsSearch, formatArticleDetails, formatRxNormDrugs, formatClinicalGuidelines, formatBrightFuturesGuidelines, formatAAPPolicyStatements, formatPediatricJournals, formatChildHealthIndicators, formatPediatricDrugs, formatAAPGuidelines, logSafetyWarnings, searchDrugsCached, getDrugByNDCCached, getHealthIndicatorsCached, searchPubMedArticlesCached, getPubMedArticleByPMIDCached, searchRxNormDrugsCached, searchGoogleScholarCached, searchClinicalGuidelinesCached, searchMedicalDatabasesCached, searchMedicalJournalsCached, searchBrightFuturesGuidelinesCached, searchAAPPolicyStatementsCached, searchPediatricJournalsCached, getChildHealthIndicatorsCached, searchPediatricDrugsCached, searchAAPGuidelinesCached, } from "./utils.js"; import { cacheManager } from "./cache/manager.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; const server = new McpServer({ name: "medical-mcp", version: "1.0.0", capabilities: { resources: {}, tools: {}, }, }); logSafetyWarnings(); // MCP Tools server.tool( "search-drugs", "Search for drug information using FDA database", { query: z .string() .describe("Drug name to search for (brand name or generic name)"), limit: z .number() .int() .min(1) .max(50) .optional() .default(10) .describe("Number of results to return (max 50)"), }, async ({ query, limit }) => { try { const result = await searchDrugsCached(query, limit); return formatDrugSearchResults(result.data, query, result.metadata); } catch (error: any) { return createErrorResponse("searching drugs", error); } }, ); server.tool( "get-drug-details", "Get detailed information about a specific drug by NDC (National Drug Code)", { ndc: z.string().describe("National Drug Code (NDC) of the drug"), }, async ({ ndc }) => { try { const result = await getDrugByNDCCached(ndc); return formatDrugDetails(result.data, ndc, result.metadata); } catch (error: any) { return createErrorResponse("fetching drug details", error); } }, ); server.tool( "get-health-statistics", "Get health statistics and indicators from WHO Global Health Observatory", { indicator: z .string() .describe( "Health indicator to search for (e.g., 'Life expectancy', 'Mortality rate')", ), country: z .string() .optional() .describe("Country code (e.g., 'USA', 'GBR') - optional"), limit: z .number() .int() .min(1) .max(20) .optional() .default(10) .describe("Number of results to return (max 20)"), }, async ({ indicator, country, limit }) => { try { const result = await getHealthIndicatorsCached(indicator, country, limit); return formatHealthIndicators( result.data, indicator, country, limit, result.metadata, ); } catch (error: any) { return createErrorResponse("fetching health statistics", error); } }, ); server.tool( "search-medical-literature", "Search for medical research articles in PubMed", { query: z.string().describe("Medical topic or condition to search for"), max_results: z .number() .int() .min(1) .max(20) .optional() .default(10) .describe("Maximum number of articles to return (max 20)"), }, async ({ query, max_results }) => { try { const result = await searchPubMedArticlesCached(query, max_results); return formatPubMedArticles(result.data, query, result.metadata); } catch (error: any) { return createErrorResponse("searching medical literature", error); } }, ); server.tool( "get-article-details", "Get detailed information about a specific medical article by PMID", { pmid: z.string().describe("PubMed ID (PMID) of the article"), }, async ({ pmid }) => { try { const result = await getPubMedArticleByPMIDCached(pmid); return formatArticleDetails(result.data, pmid, result.metadata); } catch (error: any) { return createErrorResponse("fetching article details", error); } }, ); server.tool( "search-drug-nomenclature", "Search for drug information using RxNorm (standardized drug nomenclature)", { query: z.string().describe("Drug name to search for in RxNorm database"), }, async ({ query }) => { try { const result = await searchRxNormDrugsCached(query); return formatRxNormDrugs(result.data, query, result.metadata); } catch (error: any) { return createErrorResponse("searching RxNorm", error); } }, ); server.tool( "search-google-scholar", "Search for academic research articles using Google Scholar", { query: z .string() .describe("Academic topic or research query to search for"), }, async ({ query }) => { try { const result = await searchGoogleScholarCached(query); return formatGoogleScholarArticles(result.data, query, result.metadata); } catch (error: any) { return createErrorResponse("searching Google Scholar", error); } }, ); server.tool( "search-clinical-guidelines", "Search for clinical guidelines and practice recommendations from medical organizations", { query: z .string() .describe("Medical condition or topic to search for guidelines"), organization: z .string() .optional() .describe( "Specific medical organization to filter by (e.g., 'American Heart Association', 'WHO')", ), }, async ({ query, organization }) => { try { const result = await searchClinicalGuidelinesCached(query, organization); return formatClinicalGuidelines( result.data, query, organization, result.metadata, ); } catch (error: any) { return createErrorResponse("searching clinical guidelines", error); } }, ); // Enhanced Medical Database Search Tool server.tool( "search-medical-databases", "Search across multiple medical databases (PubMed, Google Scholar, Cochrane, ClinicalTrials.gov) for comprehensive results", { query: z .string() .describe( "Medical topic or condition to search for across multiple databases", ), }, async ({ query }) => { try { const result = await searchMedicalDatabasesCached(query); return formatMedicalDatabasesSearch(result.data, query, result.metadata); } catch (error: any) { return createErrorResponse("searching medical databases", error); } }, ); // Enhanced Medical Journal Search Tool server.tool( "search-medical-journals", "Search specific medical journals (NEJM, JAMA, Lancet, BMJ, Nature Medicine) for high-quality research", { query: z .string() .describe( "Medical topic or condition to search for in top medical journals", ), }, async ({ query }) => { try { const result = await searchMedicalJournalsCached(query); return formatMedicalJournalsSearch(result.data, query, result.metadata); } catch (error: any) { return createErrorResponse("searching medical journals", error); } }, ); // Cache Statistics Tool server.tool( "get-cache-stats", "Get cache statistics including hit rate, total entries, and memory usage", {}, async () => { try { const stats = cacheManager.getStats(); const statsText = `**Cache Statistics**\n\n` + `Total Entries: ${stats.totalEntries}\n` + `Cache Hits: ${stats.hits}\n` + `Cache Misses: ${stats.misses}\n` + `Hit Rate: ${stats.hitRate}%\n` + `Miss Rate: ${stats.missRate}%\n` + `Memory Usage (estimate): ${(stats.memoryUsageEstimate / 1024 / 1024).toFixed(2)} MB\n` + `${stats.oldestEntry ? `Oldest Entry: ${stats.oldestEntry.toISOString()}\n` : ""}` + `${stats.newestEntry ? `Newest Entry: ${stats.newestEntry.toISOString()}\n` : ""}`; return { content: [ { type: "text" as const, text: statsText, }, ], }; } catch (error: any) { return createErrorResponse("fetching cache statistics", error); } }, ); // Pediatric Source Tools server.tool( "search-pediatric-guidelines", "Search for pediatric guidelines from AAP (Bright Futures and Policy Statements)", { query: z .string() .describe( "Medical condition or topic to search for pediatric guidelines", ), source: z .enum(["bright-futures", "aap-policy", "all"]) .optional() .default("all") .describe( "Source to search: 'bright-futures' for preventive care guidelines, 'aap-policy' for policy statements, or 'all' for both", ), }, async ({ query, source }) => { try { if (source === "bright-futures") { const result = await searchBrightFuturesGuidelinesCached(query); return formatBrightFuturesGuidelines( result.data, query, result.metadata, ); } else if (source === "aap-policy") { const result = await searchAAPPolicyStatementsCached(query); return formatAAPPolicyStatements(result.data, query, result.metadata); } else { const result = await searchAAPGuidelinesCached(query); return formatAAPGuidelines(result.data, query, result.metadata); } } catch (error: any) { return createErrorResponse("searching pediatric guidelines", error); } }, ); server.tool( "search-pediatric-literature", "Search for research articles in major pediatric journals (Pediatrics, JAMA Pediatrics, etc.)", { query: z .string() .describe( "Medical topic or condition to search for in pediatric journals", ), max_results: z .number() .int() .min(1) .max(20) .optional() .default(10) .describe("Maximum number of articles to return (max 20)"), }, async ({ query, max_results }) => { try { const result = await searchPediatricJournalsCached(query, max_results); return formatPediatricJournals(result.data, query, result.metadata); } catch (error: any) { return createErrorResponse("searching pediatric literature", error); } }, ); server.tool( "get-child-health-statistics", "Get pediatric health statistics and indicators from WHO Global Health Observatory", { indicator: z .string() .describe( "Health indicator to search for (e.g., 'Child mortality', 'Infant mortality', 'Immunization')", ), country: z .string() .optional() .describe("Country code (e.g., 'USA', 'GBR') - optional"), limit: z .number() .int() .min(1) .max(20) .optional() .default(10) .describe("Number of results to return (max 20)"), }, async ({ indicator, country, limit }) => { try { const result = await getChildHealthIndicatorsCached( indicator, country, limit, ); return formatChildHealthIndicators( result.data, indicator, country, result.metadata, ); } catch (error: any) { return createErrorResponse("fetching child health statistics", error); } }, ); server.tool( "search-pediatric-drugs", "Search for drugs with pediatric labeling and dosing information from FDA database", { query: z .string() .describe("Drug name to search for (brand name or generic name)"), limit: z .number() .int() .min(1) .max(50) .optional() .default(10) .describe("Number of results to return (max 50)"), }, async ({ query, limit }) => { try { const result = await searchPediatricDrugsCached(query, limit); return formatPediatricDrugs(result.data, query, result.metadata); } catch (error: any) { return createErrorResponse("searching pediatric drugs", error); } }, ); server.tool( "search-aap-guidelines", "Comprehensive search for AAP guidelines combining Bright Futures and Policy Statements", { query: z .string() .describe("Medical condition or topic to search for AAP guidelines"), }, async ({ query }) => { try { const result = await searchAAPGuidelinesCached(query); return formatAAPGuidelines(result.data, query, result.metadata); } catch (error: any) { return createErrorResponse("searching AAP guidelines", error); } }, ); async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.log("✅ Medical MCP Server running on stdio"); } main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/JamesANZ/medical-mcp'

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