Skip to main content
Glama
practitionerUtils.ts7.51 kB
import { medplum, ensureAuthenticated } from '../config/medplumClient'; import { Practitioner, OperationOutcome, HumanName, Identifier, ContactPoint } from '@medplum/fhirtypes'; import { normalizeErrorString } from '@medplum/core'; // Interface for searchPractitionersByName (existing function) interface PractitionerNameSearchParams { givenName?: string; familyName?: string; name?: string; // For a general name search } /** * Searches for Practitioner resources based on specific name criteria. * @param params - The search parameters for the practitioner's name. * @returns A promise that resolves to an array of Practitioner resources. */ export async function searchPractitionersByName( params: PractitionerNameSearchParams ): Promise<Practitioner[]> { await ensureAuthenticated(); const searchCriteria: string[] = []; if (params.givenName) { searchCriteria.push(`given:contains=${params.givenName}`); } if (params.familyName) { searchCriteria.push(`family:contains=${params.familyName}`); } if (params.name) { searchCriteria.push(`name:contains=${params.name}`); } if (searchCriteria.length === 0) { return []; } const queryString = searchCriteria.join('&'); return medplum.searchResources('Practitioner', queryString); } // New functions to be added based on IMPLEMENTATION_PLAN.md export interface CreatePractitionerArgs { family?: string; given?: string[]; gender?: 'male' | 'female' | 'other' | 'unknown'; birthDate?: string; // phone?: string; // Deprecate in favor of telecom array // email?: string; // Deprecate in favor of telecom array telecom?: ContactPoint[]; // Added for FHIR alignment and test compatibility qualification?: string; identifier?: Identifier[]; active?: boolean; // Allow setting active status on create // Backward compatibility fields givenName?: string; familyName?: string; } /** * Creates a new Practitioner resource. * @param args - The details for the new practitioner. * @returns The created Practitioner resource. */ export async function createPractitioner(args: CreatePractitionerArgs): Promise<Practitioner> { await ensureAuthenticated(); // Handle backward compatibility let family = args.family; let given = args.given; if (args.familyName && !family) { family = args.familyName; } if (args.givenName && (!given || given.length === 0)) { given = [args.givenName]; } if (!family) { throw new Error('Family name is required to create a practitioner.'); } if (!given || given.length === 0) { throw new Error('At least one given name is required to create a practitioner.'); } const practitionerResource: Practitioner = { resourceType: 'Practitioner', name: [{ family: family, given: given, }], active: true, }; // Handle identifier (now an array) if (args.identifier && args.identifier.length > 0) { practitionerResource.identifier = args.identifier; } // Handle telecom directly if provided if (args.telecom && args.telecom.length > 0) { practitionerResource.telecom = args.telecom; } // Handle other fields if (args.gender) { practitionerResource.gender = args.gender; } if (args.birthDate) { practitionerResource.birthDate = args.birthDate; } if (args.qualification) { practitionerResource.qualification = [{ code: { text: args.qualification } }]; } // Allow setting active status on create if (typeof args.active === 'boolean') { practitionerResource.active = args.active; } else { practitionerResource.active = true; // Default to true if not specified } return medplum.createResource<Practitioner>(practitionerResource); } export interface GetPractitionerByIdArgs { practitionerId: string; } /** * Retrieves a Practitioner resource by its ID. * @param practitionerId - The ID of the practitioner to retrieve. * @returns The Practitioner resource, or undefined if not found. */ export async function getPractitionerById(args: GetPractitionerByIdArgs | string): Promise<Practitioner | null> { await ensureAuthenticated(); // Handle both string and object parameter formats const practitionerId = typeof args === 'string' ? args : args.practitionerId; if (!practitionerId) { throw new Error('Practitioner ID is required to fetch a practitioner.'); } try { // No generic type needed, Medplum infers it from 'Practitioner' string return await medplum.readResource('Practitioner', practitionerId); } catch (error: any) { if (error.outcome?.issue?.[0]?.code === 'not-found') { return null; } throw error; } } export interface UpdatePractitionerArgs extends Omit<Partial<Practitioner>, 'resourceType' | 'id'> { // Add simplified fields if LLM struggles with full FHIR structure } /** * Updates an existing Practitioner resource. * @param practitionerId - The ID of the practitioner to update. * @param updates - The partial data to update the practitioner with. * @returns The updated Practitioner resource. */ export async function updatePractitioner(practitionerId: string, updates: UpdatePractitionerArgs): Promise<Practitioner> { await ensureAuthenticated(); if (!practitionerId) { throw new Error('Practitioner ID is required to update a practitioner.'); } if (!updates || Object.keys(updates).length === 0) { throw new Error('Updates object cannot be empty for updating a practitioner.'); } const existingPractitioner = await medplum.readResource('Practitioner', practitionerId); if (!existingPractitioner) { throw new Error(`Practitioner with ID ${practitionerId} not found.`); } const { resourceType, id, ...safeUpdates } = updates as any; const practitionerToUpdate: Practitioner = { ...existingPractitioner, ...safeUpdates, resourceType: 'Practitioner', id: practitionerId, }; return medplum.updateResource(practitionerToUpdate); } export interface PractitionerSearchCriteria { identifier?: string; // Search by identifier (e.g., NPI) name?: string; // General name search givenName?: string; familyName?: string; addressCity?: string; addressState?: string; telecom?: string; _lastUpdated?: string; // Add other relevant criteria as needed } /** * Searches for Practitioner resources based on general criteria. * @param criteria - The search criteria. * @returns An array of Practitioner resources matching the criteria. */ export async function searchPractitioners(criteria: PractitionerSearchCriteria): Promise<Practitioner[]> { await ensureAuthenticated(); const searchParams: string[] = []; if (criteria.identifier) searchParams.push(`identifier=${criteria.identifier}`); if (criteria.name) searchParams.push(`name:contains=${criteria.name}`); if (criteria.givenName) searchParams.push(`given:contains=${criteria.givenName}`); if (criteria.familyName) searchParams.push(`family:contains=${criteria.familyName}`); if (criteria.addressCity) searchParams.push(`address-city:contains=${criteria.addressCity}`); if (criteria.addressState) searchParams.push(`address-state:contains=${criteria.addressState}`); if (criteria.telecom) searchParams.push(`telecom=${criteria.telecom}`); if (criteria._lastUpdated) searchParams.push(`_lastUpdated=${criteria._lastUpdated}`); if (searchParams.length === 0) { return []; } const queryString = searchParams.join('&'); return medplum.searchResources('Practitioner', queryString); }

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/rkirkendall/medplum-mcp'

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