Skip to main content
Glama

PubMed MCP Server

by ncukondo
index.ts7.26 kB
#!/usr/bin/env node import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; import { createSearchHandler } from './handlers/search.js'; import { createFetchSummaryHandler } from './handlers/fetch-summary.js'; import { createGetFullTextHandler } from './handlers/get-fulltext.js'; import pkg from '../package.json' with { type: 'json' }; const { name: serverName, version: serverVersion } = pkg; const server = new McpServer( { name: serverName, version: serverVersion, }, { capabilities: { tools: {}, resources: {}, }, } ); // Parse command line arguments function parseArgs() { const args = process.argv.slice(2); const parsed: Record<string, string> = {}; for (let i = 0; i < args.length; i++) { const arg = args[i]; if (arg.startsWith('--')) { const key = arg.slice(2); const value = args[i + 1]; if (value && !value.startsWith('--')) { parsed[key] = value; i++; // Skip the value in the next iteration } } } return parsed; } const cmdArgs = parseArgs(); // Read configuration from environment variables and command line arguments const email = cmdArgs.email || process.env.PUBMED_EMAIL; const apiKey = cmdArgs['api-key'] || process.env.PUBMED_API_KEY; const cacheDir = cmdArgs['cache-dir'] || process.env.PUBMED_CACHE_DIR; const cacheTTL = cmdArgs['cache-ttl'] || process.env.PUBMED_CACHE_TTL; if (!email) { console.error(`ERROR: PUBMED_EMAIL environment variable or --email argument is required Configuration options: Environment variables: PUBMED_EMAIL (required): Your email address for PubMed API requests PUBMED_API_KEY (optional): Your PubMed API key for higher rate limits PUBMED_CACHE_DIR (optional): Directory path for caching API responses PUBMED_CACHE_TTL (optional): Cache TTL in seconds (default: 86400) Command line arguments: --email <email>: Your email address for PubMed API requests --api-key <key>: Your PubMed API key for higher rate limits --cache-dir <path>: Directory path for caching API responses --cache-ttl <seconds>: Cache TTL in seconds (default: 86400)`); process.exit(1); } const pubmedOptions = { email, ...(apiKey && { apiKey }), ...(cacheDir && { cacheDir }), ...(cacheTTL && { cacheTTL: parseInt(cacheTTL) }) }; const searchHandler = createSearchHandler(pubmedOptions); const fetchSummaryHandler = createFetchSummaryHandler(pubmedOptions); const getFullTextHandler = createGetFullTextHandler(pubmedOptions); // Register resources server.registerResource( "article", new ResourceTemplate("articles://pmid/{pmid}", { list: undefined }), { title: "PubMed Article", description: "Detailed information about a specific PubMed article" }, async (uri, { pmid }) => { try { const articles = await fetchSummaryHandler.fetchSummary([pmid as string]); if (articles.length === 0) { throw new Error(`Article with PMID ${pmid} not found`); } const article = articles[0]; return { contents: [{ uri: uri.href, text: JSON.stringify(article, null, 2), mimeType: "application/json" }] }; } catch (error) { return { contents: [{ uri: uri.href, text: `Error fetching article ${pmid}: ${error instanceof Error ? error.message : 'Unknown error'}`, mimeType: "text/plain" }] }; } } ); // Register tools server.registerTool( 'search_pubmed', { title: 'PubMed Search', description: 'Search PubMed for scientific articles.', inputSchema: { query: z.string().describe('Search query for PubMed'), searchOptions: z.object({ retMax: z.number().optional().describe('Maximum number of results to return'), retStart: z.number().optional().describe('Starting index for results'), sort: z.enum(['relevance', 'pub_date', 'author', 'journal']).optional().describe('Sort order for results'), dateFrom: z.string().optional().describe('Start date filter (YYYY/MM/DD format)'), dateTo: z.string().optional().describe('End date filter (YYYY/MM/DD format)'), }).optional().describe('Optional search parameters') } }, async ({ query, searchOptions }) => { try { const results = await searchHandler.search(query, searchOptions); return { content: [ { type: 'text', text: JSON.stringify(results, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error searching PubMed: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], }; } } ); server.registerTool( 'fetch_summary', { title: 'PubMed Article Summary', description: 'Fetch detailed article information from PubMed using PMIDs.', inputSchema: { pmids: z.array(z.string()).describe('Array of PubMed IDs (PMIDs) to fetch') } }, async ({ pmids }) => { try { const results = await fetchSummaryHandler.fetchSummary(pmids); return { content: [ { type: 'text', text: JSON.stringify(results, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error fetching article summaries: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], }; } } ); server.registerTool( 'get_fulltext', { title: 'PubMed Full Text', description: 'Get full text content of PubMed articles using PMIDs.', inputSchema: { pmids: z.array(z.string()).describe('Array of PubMed IDs (PMIDs) to get full text for') } }, async ({ pmids }) => { try { const results = await getFullTextHandler.getFullText(pmids); return { content: [ { type: 'text', text: JSON.stringify(results, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error fetching full text: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], }; } } ); async function main() { const configMessage = ` MCP PubMed Server Configuration: Email: ${email} API Key: ${apiKey ? 'Configured' : 'Not configured (using default rate limits)'} Cache Directory: ${cacheDir || 'Not configured (caching disabled)'} Cache TTL: ${cacheTTL ? `${cacheTTL} seconds` : '86400 seconds (default)'} `; console.log(configMessage); const transport = new StdioServerTransport(); await server.connect(transport); console.log('MCP PubMed server running on stdio'); } if (import.meta.url === `file://${process.argv[1]}`) { main().catch((error) => { console.error('Server error:', error); process.exit(1); }); } await main();

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/ncukondo/pubmed-mcp'

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