Skip to main content
Glama

PubMed MCP Server

by ncukondo
pubmed-api.integration.test.ts7.85 kB
import { describe, it, expect, beforeAll } from 'vitest'; import { createPubMedAPI, type PubMedAPI } from '../pubmed-api.js'; describe('PubMed API Integration Tests', () => { let api: PubMedAPI; beforeAll(() => { // Use a test email for integration tests // In real usage, users should provide their own email api = createPubMedAPI({ email: 'integration-test@example.com' }); }); describe('Real API Integration', () => { it('should perform a real search with small result set', async () => { // Use a very specific query to limit results and avoid overloading the API const result = await api.search('PMC test[Title]', { retMax: 2 }); expect(result).toBeDefined(); expect(typeof result.count).toBe('number'); expect(Array.isArray(result.idList)).toBe(true); expect(result.retMax).toBe(2); expect(result.retStart).toBe(0); // Should have some results for this query expect(result.count).toBeGreaterThan(0); }, 10000); // 10 second timeout for API calls it('should fetch article details from real API', async () => { // Use a known PMID for testing const knownPMID = '34686906'; // A real article about COVID-19 const articles = await api.fetchArticles([knownPMID]); expect(articles).toBeDefined(); expect(Array.isArray(articles)).toBe(true); expect(articles.length).toBe(1); const article = articles[0]; expect(article.pmid).toBe(knownPMID); expect(typeof article.title).toBe('string'); expect(article.title.length).toBeGreaterThan(0); expect(Array.isArray(article.authors)).toBe(true); expect(typeof article.journal).toBe('string'); expect(typeof article.pubDate).toBe('string'); }, 10000); it('should perform searchAndFetch with real API', async () => { // Search for a very specific term to get predictable results const articles = await api.searchAndFetch('coronavirus disease 2019[Title]', { maxResults: 2 }); expect(articles).toBeDefined(); expect(Array.isArray(articles)).toBe(true); expect(articles.length).toBeGreaterThanOrEqual(1); expect(articles.length).toBeLessThanOrEqual(2); // Verify article structure articles.forEach(article => { expect(typeof article.pmid).toBe('string'); expect(article.pmid.length).toBeGreaterThan(0); expect(typeof article.title).toBe('string'); expect(article.title.length).toBeGreaterThan(0); expect(Array.isArray(article.authors)).toBe(true); expect(typeof article.journal).toBe('string'); expect(typeof article.pubDate).toBe('string'); }); }, 15000); it('should handle search with date filters', async () => { const result = await api.search('machine learning', { retMax: 3, dateFrom: '2023/01/01', dateTo: '2023/12/31' }); expect(result).toBeDefined(); expect(typeof result.count).toBe('number'); expect(Array.isArray(result.idList)).toBe(true); }, 10000); it('should handle empty search results gracefully', async () => { // Use a query that should return no results const result = await api.search('zyxwvutsrqponmlkjihgfedcba12345', { retMax: 5 }); expect(result).toBeDefined(); expect(result.count).toBe(0); expect(result.idList).toEqual([]); }, 10000); it('should respect rate limiting', async () => { const startTime = Date.now(); // Make multiple requests await api.search('test query 1', { retMax: 1 }); await api.search('test query 2', { retMax: 1 }); await api.search('test query 3', { retMax: 1 }); const endTime = Date.now(); const totalTime = endTime - startTime; // Should take at least 600ms for 3 requests (334ms delay between each) // without API key expect(totalTime).toBeGreaterThan(600); }, 15000); it('should check full text availability for a known PMC article', async () => { // Use a PMID that is known to have PMC full text const knownPMIDWithPMC = '34686906'; // This should have PMC full text const result = await api.checkFullTextAvailability(knownPMIDWithPMC); expect(result).toBeDefined(); expect(typeof result.hasFullText).toBe('boolean'); if (result.hasFullText) { expect(typeof result.pmcId).toBe('string'); expect(result.pmcId).toBeTruthy(); } }, 10000); it('should check full text availability for an article without PMC', async () => { // Use a PMID that likely doesn't have PMC full text const pmidWithoutPMC = '12345678'; // Random PMID that probably doesn't exist const result = await api.checkFullTextAvailability(pmidWithoutPMC); expect(result).toBeDefined(); expect(typeof result.hasFullText).toBe('boolean'); // For non-existent PMID, should return false expect(result.hasFullText).toBe(false); }, 10000); it('should attempt to get full text for a PMC article', async () => { // Use a PMID that should have PMC full text const knownPMIDWithPMC = '34686906'; const results = await api.getFullText([knownPMIDWithPMC]); const fullText = results[0]?.fullText; // Full text might be available or not, depending on the article if (fullText !== null) { expect(typeof fullText).toBe('string'); expect(fullText.length).toBeGreaterThan(0); // Should contain structured sections in markdown format expect(fullText).toMatch(/^#\s|^##\s(Abstract|Content)/m); } else { // If no full text available, should return null gracefully expect(fullText).toBeNull(); } }, 15000); it('should get full text for PMID 39090703 with known PMC ID', async () => { // Use the specific PMID that we tested manually const pmid = '39090703'; // PMC ID: 11293181 // First check availability const availability = await api.checkFullTextAvailability(pmid); expect(availability.hasFullText).toBe(true); expect(availability.pmcId).toBe('11293181'); // Then get the full text const results = await api.getFullText([pmid]); const fullText = results[0]?.fullText; expect(fullText).not.toBeNull(); expect(typeof fullText).toBe('string'); expect(fullText!.length).toBeGreaterThan(40000); // Should be substantial content // Should contain all structured sections in markdown format expect(fullText).toMatch(/^#\s/m); // Title as H1 expect(fullText).toMatch(/^## Abstract/m); // Abstract as H2 expect(fullText).toMatch(/^## Content/m); // Content as H2 // Should contain expected content from this specific article expect(fullText).toMatch(/To teach is to learn twice/i); expect(fullText).toMatch(/qualitative study/i); expect(fullText).toMatch(/residents learn through teaching/i); }, 20000); }); describe('Error Handling', () => { it('should handle invalid PMIDs gracefully', async () => { const articles = await api.fetchArticles(['invalid-pmid-12345']); // Should not throw error, but might return empty array expect(Array.isArray(articles)).toBe(true); }, 10000); it('should handle network timeouts gracefully', async () => { // This test might be flaky depending on network conditions // It's more of a documentation of expected behavior try { const result = await api.search('test query', { retMax: 1 }); expect(result).toBeDefined(); } catch (error) { // Network errors should be thrown as expected expect(error).toBeInstanceOf(Error); } }, 10000); }); });

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