Skip to main content
Glama

DHIS2 MCP Server

by Dradebo
dhis2-client.ts50.1 kB
import axios, { AxiosInstance } from 'axios'; export interface DHIS2Config { baseUrl: string; username: string; password: string; } export interface SystemInfo { version: string; revision: string; buildTime: string; serverDate: string; instanceName: string; } export interface DataElement { id: string; name: string; displayName: string; shortName: string; code?: string; valueType: 'NUMBER' | 'INTEGER' | 'POSITIVE_INT' | 'NEGATIVE_INT' | 'ZERO_OR_POSITIVE_INT' | 'TEXT' | 'LONG_TEXT' | 'LETTER' | 'PHONE_NUMBER' | 'EMAIL' | 'BOOLEAN' | 'TRUE_ONLY' | 'DATE' | 'DATETIME' | 'TIME' | 'URL' | 'FILE_RESOURCE' | 'IMAGE' | 'COORDINATE' | 'ORGANISATION_UNIT' | 'REFERENCE' | 'AGE' | 'USERNAME' | 'TRACKER_ASSOCIATE'; domainType: 'AGGREGATE' | 'TRACKER'; aggregationType: 'SUM' | 'AVERAGE' | 'AVERAGE_SUM_ORG_UNIT' | 'COUNT' | 'STDDEV' | 'VARIANCE' | 'MIN' | 'MAX' | 'NONE' | 'CUSTOM' | 'DEFAULT'; categoryCombo?: CategoryCombo; zeroIsSignificant?: boolean; url?: string; description?: string; } export interface OrganisationUnit { id: string; name: string; displayName: string; shortName: string; code?: string; level: number; path: string; } export interface Category { id: string; name: string; displayName: string; shortName: string; code?: string; dataDimension: boolean; dataDimensionType: 'DISAGGREGATION' | 'ATTRIBUTE'; categoryOptions: CategoryOption[]; } export interface CategoryOption { id: string; name: string; displayName: string; shortName: string; code?: string; startDate?: string; endDate?: string; } export interface CategoryCombo { id: string; name: string; displayName: string; shortName: string; code?: string; dataDimensionType: 'DISAGGREGATION' | 'ATTRIBUTE'; categories: Category[]; categoryOptionCombos?: CategoryOptionCombo[]; } export interface CategoryOptionCombo { id: string; name: string; displayName: string; code?: string; categoryOptions: CategoryOption[]; categoryCombo: CategoryCombo; } export interface DataSet { id: string; name: string; displayName: string; shortName: string; code?: string; description?: string; periodType: 'Daily' | 'Weekly' | 'Monthly' | 'Quarterly' | 'SixMonthly' | 'Yearly' | 'FinancialApril' | 'FinancialJuly' | 'FinancialOct'; categoryCombo?: CategoryCombo; dataSetElements: DataSetElement[]; organisationUnits: OrganisationUnit[]; sections?: Section[]; compulsoryDataElementOperands?: DataElementOperand[]; expiryDays?: number; timelyDays?: number; openFuturePeriods?: number; dataEntryForm?: DataEntryForm; } export interface DataSetElement { dataElement: DataElement; categoryCombo?: CategoryCombo; } export interface Section { id: string; name: string; displayName: string; sortOrder: number; dataElements: DataElement[]; categoryCombo?: CategoryCombo; greyedFields?: DataElementOperand[]; } export interface DataElementOperand { dataElement: DataElement; categoryOptionCombo?: CategoryOptionCombo; } export interface DataEntryForm { id: string; name: string; htmlCode: string; format: number; style: 'COMFORTABLE' | 'NORMAL' | 'COMPACT' | 'NONE'; } export interface OrganisationUnitGroup { id: string; name: string; displayName: string; shortName: string; code?: string; organisationUnits: OrganisationUnit[]; symbol?: string; } export interface OrganisationUnitGroupSet { id: string; name: string; displayName: string; shortName: string; code?: string; description?: string; compulsory: boolean; dataDimension: boolean; organisationUnitGroups: OrganisationUnitGroup[]; } export interface DataValue { dataElement: string; period: string; orgUnit: string; categoryOptionCombo?: string; attributeOptionCombo?: string; value: string; storedBy?: string; created?: string; lastUpdated?: string; comment?: string; followup?: boolean; } export interface ValidationRule { id: string; name: string; displayName: string; description?: string; instruction?: string; importance: 'HIGH' | 'MEDIUM' | 'LOW'; operator: 'equal_to' | 'not_equal_to' | 'greater_than' | 'greater_than_or_equal_to' | 'less_than' | 'less_than_or_equal_to' | 'compulsory_pair' | 'exclusive_pair'; leftSide: Expression; rightSide: Expression; periodType: string; organisationUnitLevels: number[]; } export interface Expression { expression: string; description?: string; missingValueStrategy: 'SKIP_IF_ANY_VALUE_MISSING' | 'SKIP_IF_ALL_VALUES_MISSING' | 'NEVER_SKIP'; } export interface ValidationResult { validationRule: ValidationRule; period: string; organisationUnit: OrganisationUnit; dayInPeriod: number; leftSideValue: number; rightSideValue: number; } export interface Program { id: string; name: string; displayName: string; shortName: string; code?: string; description?: string; version?: number; programType: 'WITH_REGISTRATION' | 'WITHOUT_REGISTRATION'; trackedEntityType?: TrackedEntityType; programStages: ProgramStage[]; programRules?: ProgramRule[]; programIndicators?: ProgramIndicator[]; organisationUnits: OrganisationUnit[]; categoryCombo?: CategoryCombo; useFirstStageDuringRegistration?: boolean; displayFrontPageList?: boolean; onlyEnrollOnce?: boolean; selectEnrollmentDatesInFuture?: boolean; selectIncidentDatesInFuture?: boolean; incidentDateLabel?: string; enrollmentDateLabel?: string; } export interface TrackedEntityType { id: string; name: string; displayName: string; shortName: string; code?: string; description?: string; trackedEntityTypeAttributes: TrackedEntityTypeAttribute[]; allowAuditLog?: boolean; minAttributesRequiredToSearch?: number; maxTeiCountToReturn?: number; } export interface TrackedEntityTypeAttribute { id: string; trackedEntityAttribute: TrackedEntityAttribute; displayInList: boolean; mandatory: boolean; searchable: boolean; sortOrder: number; } export interface TrackedEntityAttribute { id: string; name: string; displayName: string; shortName: string; code?: string; description?: string; valueType: string; unique: boolean; inherit: boolean; optionSet?: OptionSet; pattern?: string; confidential?: boolean; } export interface OptionSet { id: string; name: string; displayName: string; code?: string; options: Option[]; valueType: string; } export interface Option { id: string; name: string; displayName: string; code: string; sortOrder: number; } export interface ProgramStage { id: string; name: string; displayName: string; shortName: string; code?: string; description?: string; program: Program; sortOrder: number; repeatable: boolean; minDaysFromStart: number; generatedByEnrollmentDate: boolean; blockEntryForm: boolean; reportDateToUse: string; programStageDataElements: ProgramStageDataElement[]; programStageSections?: ProgramStageSection[]; validationStrategy: 'ON_COMPLETE' | 'ON_UPDATE_AND_INSERT'; executionDateLabel?: string; dueDateLabel?: string; allowGenerateNextVisit: boolean; openAfterEnrollment: boolean; remindCompleted: boolean; } export interface ProgramStageDataElement { id: string; dataElement: DataElement; programStage: ProgramStage; compulsory: boolean; allowProvidedElsewhere: boolean; sortOrder: number; displayInReports: boolean; allowFutureDate: boolean; skipSynchronization: boolean; } export interface ProgramStageSection { id: string; name: string; displayName: string; sortOrder: number; programStage: ProgramStage; dataElements: DataElement[]; programIndicators?: ProgramIndicator[]; } export interface ProgramRule { id: string; name: string; displayName: string; description?: string; program: Program; programStage?: ProgramStage; condition: string; priority?: number; programRuleActions: ProgramRuleAction[]; } export interface ProgramRuleAction { id: string; programRuleActionType: 'DISPLAYTEXT' | 'DISPLAYKEYVALUEPAIR' | 'HIDEFIELD' | 'HIDESECTION' | 'HIDEPROGRAM' | 'ASSIGN' | 'SHOWWARNING' | 'SHOWERROR' | 'WARNINGONFIELDINTERACTION' | 'ERRORONFIELDINTERACTION' | 'CREATEEVENT' | 'SETMANDATORYFIELD' | 'SENDMESSAGE' | 'SCHEDULEMESSAGE'; dataElement?: DataElement; trackedEntityAttribute?: TrackedEntityAttribute; programStageSection?: ProgramStageSection; programStage?: ProgramStage; data?: string; content?: string; location?: string; } export interface ProgramRuleVariable { id: string; name: string; displayName: string; program: Program; programStage?: ProgramStage; dataElement?: DataElement; trackedEntityAttribute?: TrackedEntityAttribute; sourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE' | 'DATAELEMENT_NEWEST_EVENT_PROGRAM' | 'DATAELEMENT_CURRENT_EVENT' | 'DATAELEMENT_PREVIOUS_EVENT' | 'CALCULATED_VALUE' | 'TEI_ATTRIBUTE'; } export interface ProgramIndicator { id: string; name: string; displayName: string; shortName: string; code?: string; description?: string; program: Program; expression: string; filter?: string; aggregationType: string; analyticsType: 'EVENT' | 'ENROLLMENT'; displayInForm: boolean; } export interface TrackedEntityInstance { id: string; trackedEntityType: string; orgUnit: string; attributes: TrackedEntityAttributeValue[]; enrollments?: Enrollment[]; relationships?: Relationship[]; inactive: boolean; deleted: boolean; potentialDuplicate: boolean; created: string; lastUpdated: string; } export interface TrackedEntityAttributeValue { attribute: string; value: string; displayValue?: string; created?: string; lastUpdated?: string; storedBy?: string; } export interface Enrollment { id: string; trackedEntityInstance: string; program: string; orgUnit: string; enrollmentDate: string; incidentDate: string; status: 'ACTIVE' | 'COMPLETED' | 'CANCELLED'; events?: Event[]; attributes?: TrackedEntityAttributeValue[]; notes?: Note[]; followup: boolean; deleted: boolean; created: string; lastUpdated: string; } export interface Event { id: string; enrollment?: string; program: string; programStage: string; orgUnit: string; trackedEntityInstance?: string; status: 'ACTIVE' | 'COMPLETED' | 'VISITED' | 'SCHEDULE' | 'OVERDUE' | 'SKIPPED'; eventDate?: string; dueDate?: string; coordinate?: Coordinate; dataValues: DataValue[]; notes?: Note[]; followup: boolean; deleted: boolean; created: string; lastUpdated: string; } export interface Note { id: string; noteText: string; storedDate: string; storedBy: string; } export interface Coordinate { latitude: number; longitude: number; } export interface Relationship { id: string; relationshipType: RelationshipType; from: RelationshipItem; to: RelationshipItem; created: string; lastUpdated: string; } export interface RelationshipType { id: string; name: string; displayName: string; fromToName: string; toFromName: string; bidirectional: boolean; } export interface RelationshipItem { trackedEntityInstance?: TrackedEntityInstance; enrollment?: Enrollment; event?: Event; } export interface Dashboard { id: string; name: string; displayName: string; description?: string; dashboardItems: DashboardItem[]; created: string; lastUpdated: string; user: User; publicAccess: string; externalAccess: boolean; userAccesses: UserAccess[]; userGroupAccesses: UserGroupAccess[]; } export interface DashboardItem { id: string; type: 'VISUALIZATION' | 'MAP' | 'CHART' | 'REPORT_TABLE' | 'EVENT_CHART' | 'EVENT_REPORT' | 'TEXT' | 'MESSAGES' | 'RESOURCES' | 'REPORTS' | 'USERS' | 'REPORT_TABLES' | 'CHARTS' | 'MAPS'; x: number; y: number; width: number; height: number; visualization?: Visualization; map?: Map; reportTable?: ReportTable; chart?: Chart; text?: string; } export interface Visualization { id: string; name: string; displayName: string; type: 'COLUMN' | 'STACKED_COLUMN' | 'BAR' | 'STACKED_BAR' | 'LINE' | 'AREA' | 'STACKED_AREA' | 'PIE' | 'RADAR' | 'GAUGE' | 'YEAR_OVER_YEAR_LINE' | 'YEAR_OVER_YEAR_COLUMN' | 'SINGLE_VALUE' | 'PIVOT_TABLE' | 'SCATTER' | 'BUBBLE'; dataDimensionItems: DataDimensionItem[]; columns: DimensionItem[]; rows: DimensionItem[]; filters: DimensionItem[]; organisationUnits: OrganisationUnit[]; periods: Period[]; created: string; lastUpdated: string; } export interface DataDimensionItem { id: string; dataDimensionItemType: 'DATA_ELEMENT' | 'DATA_ELEMENT_OPERAND' | 'INDICATOR' | 'REPORTING_RATE' | 'PROGRAM_DATA_ELEMENT' | 'PROGRAM_ATTRIBUTE' | 'PROGRAM_INDICATOR'; dataElement?: DataElement; indicator?: Indicator; programDataElement?: ProgramDataElement; programAttribute?: ProgramAttribute; programIndicator?: ProgramIndicator; } export interface DimensionItem { id: string; name: string; dimensionType: string; items?: DimensionItem[]; } export interface Period { id: string; name: string; displayName: string; periodType: string; startDate: string; endDate: string; } export interface Indicator { id: string; name: string; displayName: string; shortName: string; code?: string; description?: string; numerator: string; denominator: string; indicatorType: IndicatorType; decimals?: number; annualized: boolean; } export interface IndicatorType { id: string; name: string; displayName: string; factor: number; number: boolean; } export interface Map { id: string; name: string; displayName: string; mapViews: MapView[]; } export interface MapView { id: string; name: string; layer: string; organisationUnitGroupSet?: OrganisationUnitGroupSet; organisationUnits: OrganisationUnit[]; periods: Period[]; } export interface ReportTable { id: string; name: string; displayName: string; columns: DimensionItem[]; rows: DimensionItem[]; filters: DimensionItem[]; } export interface Chart { id: string; name: string; displayName: string; type: string; series: DimensionItem[]; category: DimensionItem[]; filter: DimensionItem[]; } export interface Report { id: string; name: string; displayName: string; type: 'JASPER_REPORT_TABLE' | 'JASPER_JDBC'; designContent: string; cacheStrategy: 'NO_CACHE' | 'CACHE_1_HOUR' | 'CACHE_6AM_TOMORROW' | 'CACHE_TWO_WEEKS'; } export interface User { id: string; username: string; firstName: string; surname: string; email?: string; phoneNumber?: string; organisationUnits: OrganisationUnit[]; userCredentials: UserCredentials; } export interface UserCredentials { id: string; username: string; disabled: boolean; twoFA: boolean; externalAuth: boolean; userRoles: UserRole[]; } export interface UserRole { id: string; name: string; displayName: string; description?: string; authorities: string[]; } export interface UserAccess { id: string; displayName: string; access: string; } export interface UserGroupAccess { id: string; displayName: string; access: string; } export interface ProgramDataElement { id: string; dataElement: DataElement; program: Program; } export interface ProgramAttribute { id: string; trackedEntityAttribute: TrackedEntityAttribute; program: Program; } export interface AnalyticsQuery { dimension?: string; filter?: string; startDate?: string; endDate?: string; aggregationType?: string; measureCriteria?: string; preAggregationMeasureCriteria?: string; skipMeta?: boolean; skipData?: boolean; skipRounding?: boolean; hierarchyMeta?: boolean; ignoreLimit?: boolean; tableLayout?: boolean; columns?: string; rows?: string; includeNumDen?: boolean; } export class DHIS2Client { private client: AxiosInstance; private baseUrl: string; constructor(baseUrl: string, username: string, password: string) { this.baseUrl = baseUrl.replace(/\/$/, ''); this.client = axios.create({ baseURL: `${this.baseUrl}/api`, auth: { username, password, }, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, timeout: 30000, }); } get baseURL(): string { return this.baseUrl; } async testConnection(): Promise<boolean> { try { const response = await this.client.get('/me'); return response.status === 200; } catch (error) { throw new Error(`Failed to connect to DHIS2: ${error}`); } } async getCurrentUser(): Promise<any> { const response = await this.client.get('/me', { params: { fields: 'id,displayName,username,userCredentials[username,userRoles[id,name,authorities]],userGroups[id,name],organisationUnits[id,name,level],authorities' } }); return response.data; } async getSystemInfo(): Promise<SystemInfo> { try { const response = await this.client.get('/system/info'); return response.data; } catch (error) { throw new Error(`Failed to get system info: ${error}`); } } async getDataElements(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ dataElements: DataElement[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,shortName,code,valueType,domainType', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/dataElements', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get data elements: ${error}`); } } async getOrganisationUnits(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ organisationUnits: OrganisationUnit[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,shortName,code,level,path', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/organisationUnits', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get organisation units: ${error}`); } } async getAnalytics(query: AnalyticsQuery): Promise<any> { try { const params: Record<string, string> = {}; if (query.dimension) params.dimension = query.dimension; if (query.filter) params.filter = query.filter; if (query.startDate) params.startDate = query.startDate; if (query.endDate) params.endDate = query.endDate; const response = await this.client.get('/analytics', { params }); return response.data; } catch (error) { throw new Error(`Failed to get analytics: ${error}`); } } async createDataElement(dataElement: Partial<DataElement>): Promise<any> { try { const response = await this.client.post('/dataElements', dataElement); return response.data; } catch (error) { throw new Error(`Failed to create data element: ${error}`); } } async updateDataElement(id: string, dataElement: Partial<DataElement>): Promise<any> { try { const response = await this.client.put(`/dataElements/${id}`, dataElement); return response.data; } catch (error) { throw new Error(`Failed to update data element: ${error}`); } } async deleteDataElement(id: string): Promise<any> { try { const response = await this.client.delete(`/dataElements/${id}`); return response.data; } catch (error) { throw new Error(`Failed to delete data element: ${error}`); } } async createDataValue(dataValue: Partial<DataValue>): Promise<any> { try { const response = await this.client.post('/dataValues', dataValue); return response.data; } catch (error) { throw new Error(`Failed to create data value: ${error}`); } } async getDataSets(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ dataSets: DataSet[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,shortName,code,description,periodType,categoryCombo[id,name],dataSetElements[dataElement[id,name,valueType]],organisationUnits[id,name],sections[id,name,sortOrder],expiryDays,timelyDays,openFuturePeriods', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/dataSets', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get data sets: ${error}`); } } async createDataSet(dataSet: Partial<DataSet>): Promise<any> { try { const response = await this.client.post('/dataSets', dataSet); return response.data; } catch (error) { throw new Error(`Failed to create data set: ${error}`); } } async updateDataSet(id: string, dataSet: Partial<DataSet>): Promise<any> { try { const response = await this.client.put(`/dataSets/${id}`, dataSet); return response.data; } catch (error) { throw new Error(`Failed to update data set: ${error}`); } } async getCategories(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ categories: Category[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,shortName,code,dataDimension,dataDimensionType,categoryOptions[id,name,displayName,code]', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/categories', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get categories: ${error}`); } } async createCategory(category: Partial<Category>): Promise<any> { try { const response = await this.client.post('/categories', category); return response.data; } catch (error) { throw new Error(`Failed to create category: ${error}`); } } async getCategoryOptions(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ categoryOptions: CategoryOption[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,shortName,code,startDate,endDate', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/categoryOptions', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get category options: ${error}`); } } async createCategoryOption(categoryOption: Partial<CategoryOption>): Promise<any> { try { const response = await this.client.post('/categoryOptions', categoryOption); return response.data; } catch (error) { throw new Error(`Failed to create category option: ${error}`); } } async getCategoryCombos(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ categoryCombos: CategoryCombo[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,shortName,code,dataDimensionType,categories[id,name],categoryOptionCombos[id,name,displayName]', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/categoryCombos', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get category combos: ${error}`); } } async createCategoryCombo(categoryCombo: Partial<CategoryCombo>): Promise<any> { try { const response = await this.client.post('/categoryCombos', categoryCombo); return response.data; } catch (error) { throw new Error(`Failed to create category combo: ${error}`); } } async getCategoryOptionCombos(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ categoryOptionCombos: CategoryOptionCombo[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,code,categoryOptions[id,name],categoryCombo[id,name]', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/categoryOptionCombos', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get category option combos: ${error}`); } } async getOrganisationUnitGroups(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ organisationUnitGroups: OrganisationUnitGroup[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,shortName,code,symbol,organisationUnits[id,name]', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/organisationUnitGroups', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get organisation unit groups: ${error}`); } } async createOrganisationUnitGroup(orgUnitGroup: Partial<OrganisationUnitGroup>): Promise<any> { try { const response = await this.client.post('/organisationUnitGroups', orgUnitGroup); return response.data; } catch (error) { throw new Error(`Failed to create organisation unit group: ${error}`); } } async getValidationRules(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ validationRules: ValidationRule[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,description,instruction,importance,operator,leftSide[expression,description],rightSide[expression,description],periodType', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/validationRules', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get validation rules: ${error}`); } } async createValidationRule(validationRule: Partial<ValidationRule>): Promise<any> { try { const response = await this.client.post('/validationRules', validationRule); return response.data; } catch (error) { throw new Error(`Failed to create validation rule: ${error}`); } } async runValidation(params: { startDate: string; endDate: string; organisationUnits: string[]; validationRuleGroups?: string[]; sendNotifications?: boolean; }): Promise<{ validationResults: ValidationResult[] }> { try { const response = await this.client.post('/validation', params); return response.data; } catch (error) { throw new Error(`Failed to run validation: ${error}`); } } async getDataValues(params: { dataSet?: string; dataElement?: string[]; period?: string[]; startDate?: string; endDate?: string; orgUnit?: string[]; children?: boolean; categoryOptionCombo?: string[]; attributeOptionCombo?: string[]; includeDeleted?: boolean; lastUpdated?: string; lastUpdatedDuration?: string; limit?: number; }): Promise<{ dataValues: DataValue[] }> { try { const queryParams: Record<string, string | number | boolean> = {}; Object.entries(params).forEach(([key, value]) => { if (value !== undefined) { if (Array.isArray(value)) { queryParams[key] = value.join(','); } else { queryParams[key] = value; } } }); const response = await this.client.get('/dataValues', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get data values: ${error}`); } } async bulkImportDataValues(dataValues: DataValue[]): Promise<any> { try { const payload = { dataValues, }; const response = await this.client.post('/dataValues', payload); return response.data; } catch (error) { throw new Error(`Failed to bulk import data values: ${error}`); } } async deleteDataValue(params: { dataElement: string; period: string; orgUnit: string; categoryOptionCombo?: string; attributeOptionCombo?: string; }): Promise<any> { try { const response = await this.client.delete('/dataValues', { params }); return response.data; } catch (error) { throw new Error(`Failed to delete data value: ${error}`); } } async getPrograms(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ programs: Program[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,shortName,code,description,programType,trackedEntityType[id,name],programStages[id,name,sortOrder],organisationUnits[id,name]', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/programs', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get programs: ${error}`); } } async createProgram(program: Partial<Program>): Promise<any> { try { const response = await this.client.post('/programs', program); return response.data; } catch (error) { throw new Error(`Failed to create program: ${error}`); } } async updateProgram(id: string, program: Partial<Program>): Promise<any> { try { const response = await this.client.put(`/programs/${id}`, program); return response.data; } catch (error) { throw new Error(`Failed to update program: ${error}`); } } async getTrackedEntityTypes(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ trackedEntityTypes: TrackedEntityType[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,shortName,code,description,trackedEntityTypeAttributes[id,trackedEntityAttribute[id,name,valueType,unique],displayInList,mandatory,searchable,sortOrder]', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/trackedEntityTypes', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get tracked entity types: ${error}`); } } async createTrackedEntityType(trackedEntityType: Partial<TrackedEntityType>): Promise<any> { try { const response = await this.client.post('/trackedEntityTypes', trackedEntityType); return response.data; } catch (error) { throw new Error(`Failed to create tracked entity type: ${error}`); } } async getTrackedEntityAttributes(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ trackedEntityAttributes: TrackedEntityAttribute[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,shortName,code,description,valueType,unique,inherit,pattern,confidential,optionSet[id,name,options[id,name,code]]', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/trackedEntityAttributes', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get tracked entity attributes: ${error}`); } } async createTrackedEntityAttribute(attribute: Partial<TrackedEntityAttribute>): Promise<any> { try { const response = await this.client.post('/trackedEntityAttributes', attribute); return response.data; } catch (error) { throw new Error(`Failed to create tracked entity attribute: ${error}`); } } async getProgramStages(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ programStages: ProgramStage[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,shortName,code,description,program[id,name],sortOrder,repeatable,minDaysFromStart,programStageDataElements[id,dataElement[id,name],compulsory,sortOrder]', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/programStages', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get program stages: ${error}`); } } async createProgramStage(programStage: Partial<ProgramStage>): Promise<any> { try { const response = await this.client.post('/programStages', programStage); return response.data; } catch (error) { throw new Error(`Failed to create program stage: ${error}`); } } async getProgramRules(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ programRules: ProgramRule[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,description,program[id,name],programStage[id,name],condition,priority,programRuleActions[id,programRuleActionType,dataElement[id,name],data,content]', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/programRules', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get program rules: ${error}`); } } async createProgramRule(programRule: Partial<ProgramRule>): Promise<any> { try { const response = await this.client.post('/programRules', programRule); return response.data; } catch (error) { throw new Error(`Failed to create program rule: ${error}`); } } async getTrackedEntityInstances(params: { trackedEntityType?: string; program?: string; orgUnit?: string; orgUnitMode?: 'SELECTED' | 'CHILDREN' | 'DESCENDANTS' | 'ACCESSIBLE'; query?: string; attribute?: string[]; filter?: string[]; ou?: string[]; ouMode?: string; programStartDate?: string; programEndDate?: string; programStatus?: 'ACTIVE' | 'COMPLETED' | 'CANCELLED'; followUp?: boolean; eventStartDate?: string; eventEndDate?: string; eventStatus?: 'ACTIVE' | 'COMPLETED' | 'VISITED' | 'SCHEDULE' | 'OVERDUE' | 'SKIPPED'; includeDeleted?: boolean; includeAllAttributes?: boolean; fields?: string; page?: number; pageSize?: number; }): Promise<{ trackedEntityInstances: TrackedEntityInstance[] }> { try { const queryParams: Record<string, string | number | boolean> = {}; Object.entries(params).forEach(([key, value]) => { if (value !== undefined) { if (Array.isArray(value)) { queryParams[key] = value.join(','); } else { queryParams[key] = value; } } }); if (!queryParams.fields) { queryParams.fields = 'id,trackedEntityType,orgUnit,attributes[attribute,value,displayValue],enrollments[id,program,enrollmentDate,status,events[id,programStage,eventDate,status,dataValues[dataElement,value]]]'; } const response = await this.client.get('/trackedEntityInstances', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get tracked entity instances: ${error}`); } } async createTrackedEntityInstance(tei: Partial<TrackedEntityInstance>): Promise<any> { try { const response = await this.client.post('/trackedEntityInstances', tei); return response.data; } catch (error) { throw new Error(`Failed to create tracked entity instance: ${error}`); } } async updateTrackedEntityInstance(id: string, tei: Partial<TrackedEntityInstance>): Promise<any> { try { const response = await this.client.put(`/trackedEntityInstances/${id}`, tei); return response.data; } catch (error) { throw new Error(`Failed to update tracked entity instance: ${error}`); } } async getEnrollments(params: { program?: string; trackedEntityInstance?: string; orgUnit?: string; orgUnitMode?: 'SELECTED' | 'CHILDREN' | 'DESCENDANTS' | 'ACCESSIBLE'; programStartDate?: string; programEndDate?: string; programStatus?: 'ACTIVE' | 'COMPLETED' | 'CANCELLED'; followUp?: boolean; includeDeleted?: boolean; fields?: string; page?: number; pageSize?: number; }): Promise<{ enrollments: Enrollment[] }> { try { const queryParams: Record<string, string | number | boolean> = {}; Object.entries(params).forEach(([key, value]) => { if (value !== undefined) { queryParams[key] = value; } }); if (!queryParams.fields) { queryParams.fields = 'id,trackedEntityInstance,program,orgUnit,enrollmentDate,incidentDate,status,followup,events[id,programStage,eventDate,status,dataValues[dataElement,value]]'; } const response = await this.client.get('/enrollments', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get enrollments: ${error}`); } } async createEnrollment(enrollment: Partial<Enrollment>): Promise<any> { try { const response = await this.client.post('/enrollments', enrollment); return response.data; } catch (error) { throw new Error(`Failed to create enrollment: ${error}`); } } async updateEnrollment(id: string, enrollment: Partial<Enrollment>): Promise<any> { try { const response = await this.client.put(`/enrollments/${id}`, enrollment); return response.data; } catch (error) { throw new Error(`Failed to update enrollment: ${error}`); } } async getEvents(params: { program?: string; programStage?: string; enrollment?: string; trackedEntityInstance?: string; orgUnit?: string; orgUnitMode?: 'SELECTED' | 'CHILDREN' | 'DESCENDANTS' | 'ACCESSIBLE'; startDate?: string; endDate?: string; status?: 'ACTIVE' | 'COMPLETED' | 'VISITED' | 'SCHEDULE' | 'OVERDUE' | 'SKIPPED'; followUp?: boolean; includeDeleted?: boolean; fields?: string; page?: number; pageSize?: number; order?: string; }): Promise<{ events: Event[] }> { try { const queryParams: Record<string, string | number | boolean> = {}; Object.entries(params).forEach(([key, value]) => { if (value !== undefined) { queryParams[key] = value; } }); if (!queryParams.fields) { queryParams.fields = 'id,enrollment,program,programStage,orgUnit,trackedEntityInstance,status,eventDate,dueDate,coordinate,dataValues[dataElement,value],created,lastUpdated'; } const response = await this.client.get('/events', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get events: ${error}`); } } async createEvent(event: Partial<Event>): Promise<any> { try { const response = await this.client.post('/events', event); return response.data; } catch (error) { throw new Error(`Failed to create event: ${error}`); } } async updateEvent(id: string, event: Partial<Event>): Promise<any> { try { const response = await this.client.put(`/events/${id}`, event); return response.data; } catch (error) { throw new Error(`Failed to update event: ${error}`); } } async bulkImportEvents(events: Event[]): Promise<any> { try { const payload = { events, }; const response = await this.client.post('/events', payload); return response.data; } catch (error) { throw new Error(`Failed to bulk import events: ${error}`); } } async getEventAnalytics(params: { program: string; stage?: string; startDate: string; endDate: string; orgUnit: string; dimension?: string[]; filter?: string[]; value?: string; outputType?: 'EVENT' | 'ENROLLMENT' | 'TRACKED_ENTITY_INSTANCE'; coordinatesOnly?: boolean; page?: number; pageSize?: number; }): Promise<any> { try { const queryParams: Record<string, string | number | boolean> = { program: params.program, startDate: params.startDate, endDate: params.endDate, orgUnit: params.orgUnit, outputType: params.outputType || 'EVENT', }; if (params.stage) queryParams.stage = params.stage; if (params.dimension) queryParams.dimension = params.dimension.join(','); if (params.filter) queryParams.filter = params.filter.join(','); if (params.value) queryParams.value = params.value; if (params.coordinatesOnly) queryParams.coordinatesOnly = params.coordinatesOnly; if (params.page) queryParams.page = params.page; if (params.pageSize) queryParams.pageSize = params.pageSize; const response = await this.client.get('/analytics/events/query', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get event analytics: ${error}`); } } async getEnrollmentAnalytics(params: { program: string; startDate: string; endDate: string; orgUnit: string; dimension?: string[]; filter?: string[]; page?: number; pageSize?: number; }): Promise<any> { try { const queryParams: Record<string, string | number | boolean> = { program: params.program, startDate: params.startDate, endDate: params.endDate, orgUnit: params.orgUnit, }; if (params.dimension) queryParams.dimension = params.dimension.join(','); if (params.filter) queryParams.filter = params.filter.join(','); if (params.page) queryParams.page = params.page; if (params.pageSize) queryParams.pageSize = params.pageSize; const response = await this.client.get('/analytics/enrollments/query', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get enrollment analytics: ${error}`); } } async getDataStatistics(): Promise<any> { try { const response = await this.client.get('/dataStatistics'); return response.data; } catch (error) { throw new Error(`Failed to get data statistics: ${error}`); } } async getDashboards(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ dashboards: Dashboard[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,dashboardItems[id,type,visualization[id,name],map[id,name],reportTable[id,name],chart[id,name]]', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/dashboards', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get dashboards: ${error}`); } } async createDashboard(dashboard: Partial<Dashboard>): Promise<any> { try { const response = await this.client.post('/dashboards', dashboard); return response.data; } catch (error) { throw new Error(`Failed to create dashboard: ${error}`); } } async getVisualizations(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ visualizations: Visualization[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,type,dataDimensionItems,columns,rows,filters,organisationUnits,periods', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/visualizations', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get visualizations: ${error}`); } } async createVisualization(visualization: Partial<Visualization>): Promise<any> { try { const response = await this.client.post('/visualizations', visualization); return response.data; } catch (error) { throw new Error(`Failed to create visualization: ${error}`); } } async getReports(params?: { fields?: string; filter?: string; paging?: boolean; pageSize?: number; }): Promise<{ reports: Report[] }> { try { const queryParams = { fields: params?.fields || 'id,name,displayName,type,designContent', filter: params?.filter, paging: params?.paging ?? false, pageSize: params?.pageSize || 50, }; const response = await this.client.get('/reports', { params: queryParams }); return response.data; } catch (error) { throw new Error(`Failed to get reports: ${error}`); } } async generateReport(reportId: string, params?: { organisationUnit?: string; period?: string; date?: string; }): Promise<any> { try { const queryParams: Record<string, string> = {}; if (params?.organisationUnit) queryParams.organisationUnit = params.organisationUnit; if (params?.period) queryParams.period = params.period; if (params?.date) queryParams.date = params.date; const response = await this.client.get(`/reports/${reportId}/data.pdf`, { params: queryParams, responseType: 'blob', }); return response.data; } catch (error) { throw new Error(`Failed to generate report: ${error}`); } } // DataStore operations for Web App Platform integration async createDataStoreNamespace(namespace: string, options?: { description?: string; sharing?: any; initialKeys?: Array<{ key: string; value: any }>; }): Promise<any> { try { // Create namespace metadata (if supported) if (options?.description || options?.sharing) { const namespaceConfig = { description: options.description, sharing: options.sharing }; try { await this.client.put(`/dataStore/${namespace}/__metadata__`, namespaceConfig); } catch (error) { // Metadata creation is optional, continue with key creation console.warn('Could not create namespace metadata:', error); } } // Create initial keys if provided if (options?.initialKeys) { const results = []; for (const { key, value } of options.initialKeys) { try { const response = await this.client.post(`/dataStore/${namespace}/${key}`, value); results.push({ key, status: 'created', data: response.data }); } catch (error) { results.push({ key, status: 'error', error: error }); } } return { namespace, results }; } return { namespace, status: 'created' }; } catch (error) { throw new Error(`Failed to create DataStore namespace: ${error}`); } } async manageDataStoreKey(params: { operation: 'create' | 'read' | 'update' | 'delete' | 'list'; namespace: string; key?: string; value?: any; encrypt?: boolean; }): Promise<any> { try { const { operation, namespace, key, value, encrypt } = params; switch (operation) { case 'list': const response = await this.client.get(`/dataStore/${namespace}`); return response.data; case 'read': if (!key) throw new Error('Key is required for read operation'); const readResponse = await this.client.get(`/dataStore/${namespace}/${key}`); return readResponse.data; case 'create': case 'update': if (!key || value === undefined) { throw new Error('Key and value are required for create/update operations'); } const data = encrypt ? this.encryptValue(value) : value; const method = operation === 'create' ? 'post' : 'put'; const writeResponse = await this.client[method](`/dataStore/${namespace}/${key}`, data); return writeResponse.data; case 'delete': if (!key) throw new Error('Key is required for delete operation'); await this.client.delete(`/dataStore/${namespace}/${key}`); return { status: 'deleted', namespace, key }; default: throw new Error(`Unsupported operation: ${operation}`); } } catch (error) { throw new Error(`Failed to manage DataStore key: ${error}`); } } private encryptValue(value: any): any { // Simple base64 encoding for demonstration // In production, use proper encryption const jsonString = JSON.stringify(value); return { __encrypted__: true, data: Buffer.from(jsonString).toString('base64') }; } }

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