Skip to main content
Glama
medicaid-api.js9.54 kB
/** * Medicaid API Implementation * * CSV-based data retrieval from data.medicaid.gov * Uses in-memory caching with TTL for performance */ const { cache } = require('./cache-manager'); const { getDataset } = require('./datasets'); const { formatDateRange, parseEnrollmentData, parseNADACData, parseDrugRebateData, calculateGrowthRate, groupByState, getLatestDate, getDateMonthsAgo, validateStateCode, formatResponse } = require('./utils'); /** * Get NADAC data (downloads and caches CSV) */ async function getNADACData() { const dataset = getDataset('nadac'); if (!dataset.downloadUrl) { throw new Error('NADAC CSV download URL not configured'); } return cache.get('NADAC', async () => { return cache.downloadAndParseCSV(dataset.downloadUrl, 'NADAC'); }, dataset.cacheTime); } /** * Get Enrollment data (downloads and caches CSV) */ async function getEnrollmentData() { const dataset = getDataset('enrollment'); if (!dataset.downloadUrl) { throw new Error('Enrollment CSV download URL not configured'); } return cache.get('ENROLLMENT', async () => { return cache.downloadAndParseCSV(dataset.downloadUrl, 'Enrollment'); }, dataset.cacheTime); } /** * Get NADAC pricing data */ async function getNADACPricing(params) { const dataset = getDataset('nadac'); const allData = await getNADACData(); // Filter data based on parameters let filtered = allData; // Filter by NDC code (exact match) if (params.ndc_code) { const ndc = params.ndc_code.replace(/-/g, ''); // Remove dashes filtered = filtered.filter(row => { const rowNdc = (row['NDC'] || '').replace(/-/g, ''); return rowNdc === ndc; }); } // Filter by drug name (case-insensitive partial match) if (params.drug_name) { const searchTerm = params.drug_name.toLowerCase(); filtered = filtered.filter(row => { const description = (row['NDC Description'] || '').toLowerCase(); return description.includes(searchTerm); }); } // Filter by date if (params.price_date) { filtered = filtered.filter(row => { const effectiveDate = row['Effective Date'] || ''; return effectiveDate === params.price_date; }); } // Pagination const limit = params.limit || 100; const offset = params.offset || 0; const paginated = filtered.slice(offset, offset + limit); // Parse and format const parsed = parseNADACData(paginated); return formatResponse(parsed, { dataset: dataset.name, total_count: filtered.length, returned_count: paginated.length, effective_date: params.price_date || 'latest', query_type: 'nadac_pricing', cache_status: 'loaded from cache' }); } /** * Compare drug pricing across time or multiple drugs */ async function compareDrugPricing(params) { const dataset = getDataset('nadac'); const allData = await getNADACData(); const ndc_codes = params.ndc_codes || []; const drug_names = params.drug_names || []; if (ndc_codes.length === 0 && drug_names.length === 0) { throw new Error('Either ndc_codes or drug_names must be provided'); } let filtered = allData; // Filter by date range if (params.start_date && params.end_date) { filtered = filtered.filter(row => { const effectiveDate = row['Effective Date'] || ''; return effectiveDate >= params.start_date && effectiveDate <= params.end_date; }); } // Filter by NDC codes if (ndc_codes.length > 0) { const normalizedCodes = ndc_codes.map(ndc => ndc.replace(/-/g, '')); filtered = filtered.filter(row => { const rowNdc = (row['NDC'] || '').replace(/-/g, ''); return normalizedCodes.includes(rowNdc); }); } // Filter by drug names if (drug_names.length > 0) { const searchTerms = drug_names.map(name => name.toLowerCase()); filtered = filtered.filter(row => { const description = (row['NDC Description'] || '').toLowerCase(); return searchTerms.some(term => description.includes(term)); }); } // Sort by date filtered.sort((a, b) => { const dateA = a['Effective Date'] || ''; const dateB = b['Effective Date'] || ''; return dateB.localeCompare(dateA); // Descending }); // Pagination const limit = params.limit || 100; const offset = params.offset || 0; const paginated = filtered.slice(offset, offset + limit); const parsed = parseNADACData(paginated); return formatResponse(parsed, { dataset: dataset.name, total_count: filtered.length, returned_count: paginated.length, date_range: { start: params.start_date, end: params.end_date }, query_type: 'drug_pricing_comparison' }); } /** * Get enrollment trends over time */ async function getEnrollmentTrends(params) { const dataset = getDataset('enrollment'); const allData = await getEnrollmentData(); let filtered = allData; // Filter by state if (params.state) { const stateUpper = params.state.toUpperCase(); filtered = filtered.filter(row => { const state = (row['State Abbreviation'] || '').toUpperCase(); return state === stateUpper; }); } // Filter by date range (using Reporting Period YYYYMM format) if (params.start_date && params.end_date) { // Convert YYYY-MM-DD to YYYYMM for comparison const startPeriod = params.start_date.replace(/-/g, '').substring(0, 6); const endPeriod = params.end_date.replace(/-/g, '').substring(0, 6); filtered = filtered.filter(row => { const reportPeriod = row['Reporting Period'] || ''; return reportPeriod >= startPeriod && reportPeriod <= endPeriod; }); } // Filter by enrollment type if (params.enrollment_type) { // This depends on the actual column names in the enrollment CSV // Will need to map enrollment_type to actual columns } // Sort by date (Reporting Period YYYYMM format) filtered.sort((a, b) => { const periodA = a['Reporting Period'] || ''; const periodB = b['Reporting Period'] || ''; return periodA.localeCompare(periodB); // Ascending for trends }); // Pagination const limit = params.limit || 100; const offset = params.offset || 0; const paginated = filtered.slice(offset, offset + limit); const parsed = parseEnrollmentData(paginated); return formatResponse(parsed, { dataset: dataset.name, total_count: filtered.length, returned_count: paginated.length, state: params.state || 'all', date_range: { start: params.start_date, end: params.end_date }, query_type: 'enrollment_trends' }); } /** * Compare state enrollment data */ async function compareStateEnrollment(params) { const dataset = getDataset('enrollment'); const allData = await getEnrollmentData(); const states = params.states || []; if (states.length === 0) { throw new Error('states parameter is required'); } let filtered = allData; // Filter by states const statesUpper = states.map(s => s.toUpperCase()); filtered = filtered.filter(row => { const state = (row['State Abbreviation'] || '').toUpperCase(); return statesUpper.includes(state); }); // Filter by month (if specified, convert YYYY-MM to YYYYMM) if (params.month) { const monthPeriod = params.month.replace(/-/g, ''); // Convert "2024-09" to "202409" filtered = filtered.filter(row => { const reportPeriod = row['Reporting Period'] || ''; return reportPeriod === monthPeriod; }); } // Group by state const grouped = groupByState(filtered); return formatResponse(grouped, { dataset: dataset.name, states: states, month: params.month || 'latest', query_type: 'state_enrollment_comparison' }); } /** * Get drug rebate information * NOTE: Not implemented yet - need CSV download URL */ async function getDrugRebateInfo(params) { const dataset = getDataset('drug_pricing', 'rebate'); if (!dataset.downloadUrl) { throw new Error('Drug rebate data not yet implemented - CSV download URL needed'); } // TODO: Implement when CSV URL is available throw new Error('Drug rebate data coming in Phase 2'); } /** * List available datasets */ async function listAvailableDatasets(params) { const { listDatasets } = require('./datasets'); const datasets = listDatasets(); const available = datasets.map(ds => ({ name: ds.name, category: ds.category, update_frequency: ds.update_frequency, description: ds.description, estimated_size: ds.estimatedSize, estimated_records: ds.estimatedRecords, available: !!ds.downloadUrl, cache_time_hours: ds.cacheTime / (60 * 60 * 1000) })); return formatResponse(available, { total_datasets: datasets.length, available_datasets: available.filter(ds => ds.available).length, query_type: 'list_datasets' }); } /** * Generic dataset search (advanced) */ async function searchDatasets(params) { const datasetId = params.dataset_id; if (!datasetId) { throw new Error('dataset_id parameter is required'); } // Map dataset_id to known datasets const { getDataset } = require('./datasets'); if (datasetId === 'nadac' || datasetId === 'drug_pricing') { return getNADACPricing(params); } else if (datasetId === 'enrollment') { return getEnrollmentTrends(params); } else { throw new Error(`Unknown dataset_id: ${datasetId}`); } } module.exports = { getNADACPricing, compareDrugPricing, getEnrollmentTrends, compareStateEnrollment, getDrugRebateInfo, listAvailableDatasets, searchDatasets };

Implementation Reference

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/openpharma-org/medicaid-mcp-server'

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