Skip to main content
Glama

DHIS2 MCP Server

by Dradebo
parameter-completion.ts12.7 kB
import { DHIS2Client } from './dhis2-client.js'; export interface CompletionValue { value: string; label: string; description?: string; } export interface CompletionResult { values: CompletionValue[]; } export class ParameterCompletion { constructor(private dhis2Client: DHIS2Client | null) {} async getCompletion(toolName: string, argumentName: string, partialValue?: string): Promise<CompletionResult> { if (!this.dhis2Client) { return { values: [] }; } try { switch (argumentName) { case 'dataElement': case 'dataElementId': return await this.getDataElementCompletions(partialValue); case 'orgUnit': case 'organisationUnit': case 'orgUnitId': return await this.getOrganisationUnitCompletions(partialValue); case 'period': return this.getPeriodCompletions(); case 'categoryOptionCombo': return await this.getCategoryOptionComboCompletions(partialValue); case 'program': case 'programId': return await this.getProgramCompletions(partialValue); case 'trackedEntityType': return await this.getTrackedEntityTypeCompletions(partialValue); case 'valueType': return this.getValueTypeCompletions(); case 'domainType': return this.getDomainTypeCompletions(); case 'aggregationType': return this.getAggregationTypeCompletions(); case 'periodType': return this.getPeriodTypeCompletions(); default: return { values: [] }; } } catch (error) { console.error(`Error getting completion for ${argumentName}:`, error); return { values: [] }; } } private async getDataElementCompletions(partialValue?: string): Promise<CompletionResult> { const params: any = { pageSize: 50, fields: 'id,displayName,valueType,domainType' }; if (partialValue) { params.filter = `name:ilike:${partialValue}`; } const response = await this.dhis2Client!.getDataElements(params); return { values: response.dataElements.map(de => ({ value: de.id, label: de.displayName, description: `${de.valueType} - ${de.domainType}` })) }; } private async getOrganisationUnitCompletions(partialValue?: string): Promise<CompletionResult> { const params: any = { pageSize: 50, fields: 'id,displayName,level,path' }; if (partialValue) { params.filter = `name:ilike:${partialValue}`; } const response = await this.dhis2Client!.getOrganisationUnits(params); return { values: response.organisationUnits.map(ou => ({ value: ou.id, label: ou.displayName, description: `Level ${ou.level} - ${ou.path?.split('/').length - 1} parents` })) }; } private getPeriodCompletions(): CompletionResult { const currentYear = new Date().getFullYear(); const values: CompletionValue[] = []; // Current and previous years (yearly periods) for (let year = currentYear; year >= currentYear - 3; year--) { values.push({ value: year.toString(), label: `Year ${year}`, description: 'Yearly period' }); // Quarterly periods for (let q = 1; q <= 4; q++) { values.push({ value: `${year}Q${q}`, label: `Q${q} ${year}`, description: 'Quarterly period' }); } // Monthly periods for (let m = 1; m <= 12; m++) { const month = m.toString().padStart(2, '0'); values.push({ value: `${year}${month}`, label: `${year}-${month}`, description: 'Monthly period' }); } } return { values: values.slice(0, 50) }; // Limit to 50 most recent } private async getCategoryOptionComboCompletions(partialValue?: string): Promise<CompletionResult> { const params: any = { pageSize: 30, fields: 'id,displayName' }; if (partialValue) { params.filter = `name:ilike:${partialValue}`; } const response = await this.dhis2Client!.getCategoryOptionCombos(params); return { values: response.categoryOptionCombos.map(coc => ({ value: coc.id, label: coc.displayName, description: 'Category option combination' })) }; } private async getProgramCompletions(partialValue?: string): Promise<CompletionResult> { const params: any = { pageSize: 30, fields: 'id,displayName,programType' }; if (partialValue) { params.filter = `name:ilike:${partialValue}`; } const response = await this.dhis2Client!.getPrograms(params); return { values: response.programs.map(program => ({ value: program.id, label: program.displayName, description: program.programType || 'Program' })) }; } private async getTrackedEntityTypeCompletions(partialValue?: string): Promise<CompletionResult> { const params: any = { pageSize: 30, fields: 'id,displayName' }; if (partialValue) { params.filter = `name:ilike:${partialValue}`; } const response = await this.dhis2Client!.getTrackedEntityTypes(params); return { values: response.trackedEntityTypes.map(tet => ({ value: tet.id, label: tet.displayName, description: 'Tracked entity type' })) }; } private getValueTypeCompletions(): CompletionResult { return { values: [ { value: 'TEXT', label: 'Text', description: 'Free text input' }, { value: 'LONG_TEXT', label: 'Long Text', description: 'Multi-line text input' }, { value: 'NUMBER', label: 'Number', description: 'Numeric value with decimals' }, { value: 'INTEGER', label: 'Integer', description: 'Whole numbers only' }, { value: 'INTEGER_POSITIVE', label: 'Positive Integer', description: 'Positive whole numbers only' }, { value: 'INTEGER_NEGATIVE', label: 'Negative Integer', description: 'Negative whole numbers only' }, { value: 'INTEGER_ZERO_OR_POSITIVE', label: 'Zero or Positive Integer', description: 'Zero or positive whole numbers' }, { value: 'PERCENTAGE', label: 'Percentage', description: 'Percentage value (0-100)' }, { value: 'BOOLEAN', label: 'Yes/No', description: 'True/false value' }, { value: 'TRUE_ONLY', label: 'Yes Only', description: 'Only true values allowed' }, { value: 'DATE', label: 'Date', description: 'Date value' }, { value: 'DATETIME', label: 'Date & Time', description: 'Date and time value' }, { value: 'TIME', label: 'Time', description: 'Time value' }, { value: 'EMAIL', label: 'Email', description: 'Email address' }, { value: 'PHONE_NUMBER', label: 'Phone Number', description: 'Phone number' }, { value: 'URL', label: 'URL', description: 'Web address' }, { value: 'FILE_RESOURCE', label: 'File', description: 'File attachment' }, { value: 'COORDINATE', label: 'Coordinate', description: 'GPS coordinates' }, { value: 'ORGANISATION_UNIT', label: 'Organisation Unit', description: 'Organisation unit reference' }, { value: 'REFERENCE', label: 'Reference', description: 'Reference to another object' }, { value: 'AGE', label: 'Age', description: 'Age in years' } ] }; } private getDomainTypeCompletions(): CompletionResult { return { values: [ { value: 'AGGREGATE', label: 'Aggregate', description: 'For aggregate data collection' }, { value: 'TRACKER', label: 'Tracker', description: 'For individual tracking programs' } ] }; } private getAggregationTypeCompletions(): CompletionResult { return { values: [ { value: 'SUM', label: 'Sum', description: 'Add all values' }, { value: 'AVERAGE', label: 'Average', description: 'Calculate mean value' }, { value: 'AVERAGE_SUM_ORG_UNIT', label: 'Average (Sum in Org Unit)', description: 'Average across periods, sum across org units' }, { value: 'COUNT', label: 'Count', description: 'Count number of values' }, { value: 'STDDEV', label: 'Standard Deviation', description: 'Statistical standard deviation' }, { value: 'VARIANCE', label: 'Variance', description: 'Statistical variance' }, { value: 'MIN', label: 'Minimum', description: 'Lowest value' }, { value: 'MAX', label: 'Maximum', description: 'Highest value' }, { value: 'NONE', label: 'None', description: 'No aggregation' } ] }; } private getPeriodTypeCompletions(): CompletionResult { return { values: [ { value: 'Daily', label: 'Daily', description: 'Daily periods' }, { value: 'Weekly', label: 'Weekly', description: 'Weekly periods' }, { value: 'WeeklyWednesday', label: 'Weekly (Wednesday)', description: 'Weekly starting Wednesday' }, { value: 'WeeklyThursday', label: 'Weekly (Thursday)', description: 'Weekly starting Thursday' }, { value: 'WeeklySaturday', label: 'Weekly (Saturday)', description: 'Weekly starting Saturday' }, { value: 'WeeklySunday', label: 'Weekly (Sunday)', description: 'Weekly starting Sunday' }, { value: 'BiWeekly', label: 'Bi-Weekly', description: '2-week periods' }, { value: 'Monthly', label: 'Monthly', description: 'Monthly periods' }, { value: 'BiMonthly', label: 'Bi-Monthly', description: '2-month periods' }, { value: 'Quarterly', label: 'Quarterly', description: 'Quarterly periods' }, { value: 'SixMonthly', label: 'Six Monthly', description: '6-month periods' }, { value: 'SixMonthlyApril', label: 'Six Monthly (April)', description: '6-month starting April' }, { value: 'SixMonthlyNov', label: 'Six Monthly (November)', description: '6-month starting November' }, { value: 'Yearly', label: 'Yearly', description: 'Yearly periods' }, { value: 'FinancialApril', label: 'Financial Year (April)', description: 'Financial year starting April' }, { value: 'FinancialJuly', label: 'Financial Year (July)', description: 'Financial year starting July' }, { value: 'FinancialOct', label: 'Financial Year (October)', description: 'Financial year starting October' }, { value: 'FinancialNov', label: 'Financial Year (November)', description: 'Financial year starting November' } ] }; } // Tool-specific completions async getToolSpecificCompletion(toolName: string, argumentName: string, context: Record<string, any>): Promise<CompletionResult> { switch (toolName) { case 'dhis2_create_data_value': if (argumentName === 'categoryOptionCombo' && context.dataElement) { // Get category combos specific to the data element return await this.getCategoryComboForDataElement(context.dataElement); } break; case 'dhis2_create_event': if (argumentName === 'orgUnit' && context.program) { // Get org units assigned to the program return await this.getOrgUnitsForProgram(context.program); } break; } return { values: [] }; } private async getCategoryComboForDataElement(dataElementId: string): Promise<CompletionResult> { try { // Since getDataElement doesn't exist, we'll use a generic completion const response = await this.dhis2Client!.getCategoryOptionCombos({ pageSize: 20, fields: 'id,displayName' }); return { values: response.categoryOptionCombos.map((coc: any) => ({ value: coc.id, label: coc.displayName, description: 'Category option combination' })) }; } catch (error) { console.warn('Could not fetch category combos for data element:', error); } return { values: [] }; } private async getOrgUnitsForProgram(programId: string): Promise<CompletionResult> { try { // Since getProgram doesn't exist, we'll use a generic completion const response = await this.dhis2Client!.getOrganisationUnits({ pageSize: 20, fields: 'id,displayName,level' }); return { values: response.organisationUnits.map((ou: any) => ({ value: ou.id, label: ou.displayName, description: `Level ${ou.level} - Organization unit` })) }; } catch (error) { console.warn('Could not fetch org units for program:', error); } return { values: [] }; } }

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/Dradebo/dhis2-mcp'

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