Skip to main content
Glama
organizationUtils.ts9.68 kB
import { MedplumClient, normalizeErrorString } from '@medplum/core'; import { Organization, BundleEntry, Bundle, OperationOutcome, Identifier } from '@medplum/fhirtypes'; import { medplum, ensureAuthenticated } from '../config/medplumClient'; export interface CreateOrganizationArgs { name: string; alias?: string[]; typeCode?: string; typeSystem?: string; typeDisplay?: string; phone?: string; email?: string; address?: { use?: 'home' | 'work' | 'temp' | 'old' | 'billing'; line?: string[]; city?: string; state?: string; postalCode?: string; country?: string; }; identifierSystem?: string; identifierValue?: string; contact?: any[]; // Added for test compatibility } export interface GetOrganizationByIdArgs { organizationId: string; } export interface UpdateOrganizationArgs extends Omit<Partial<Organization>, 'resourceType' | 'id'> { // if specific simplified fields are needed, they can be added here } export interface OrganizationSearchArgs { name?: string; addressCity?: string; addressState?: string; identifier?: string; type?: string; // search by type code, optionally with system (system|code) _lastUpdated?: string; active?: boolean; address?: string; city?: string; state?: string; postalCode?: string; country?: string; } /** * Creates a new Organization resource. * @param args - The details for the new organization. * @returns The created Organization resource. */ export async function createOrganization(args: CreateOrganizationArgs): Promise<Organization> { await ensureAuthenticated(); if (!args.name) { throw new Error('Organization name is required.'); } const organizationResource: Organization = { resourceType: "Organization", name: args.name, active: true, // Default to active }; if (args.alias && args.alias.length > 0) { organizationResource.alias = args.alias; } if (args.typeCode) { organizationResource.type = [{ coding: [{ system: args.typeSystem || 'http://terminology.hl7.org/CodeSystem/organization-type', code: args.typeCode, display: args.typeDisplay || args.typeCode, }], text: args.typeDisplay || args.typeCode }]; } if (args.phone || args.email) { organizationResource.telecom = []; if (args.phone) { organizationResource.telecom.push({ system: 'phone', value: args.phone, use: 'work' }); } if (args.email) { organizationResource.telecom.push({ system: 'email', value: args.email, use: 'work' }); } } if (args.address) { organizationResource.address = [{ use: args.address.use || 'work', line: args.address.line, city: args.address.city, state: args.address.state, postalCode: args.address.postalCode, country: args.address.country, }]; } if (args.identifierValue) { const identifier: Identifier = { value: args.identifierValue }; if (args.identifierSystem) { identifier.system = args.identifierSystem; } organizationResource.identifier = [identifier]; } return medplum.createResource<Organization>(organizationResource); } /** * Retrieves an Organization resource by its ID. * @param args - The ID of the organization to retrieve. * @returns The Organization resource. */ export async function getOrganizationById(args: { organizationId: string } | string): Promise<Organization | null> { await ensureAuthenticated(); // Handle both string and object parameter formats const organizationId = typeof args === 'string' ? args : args.organizationId; if (!organizationId) { throw new Error('Organization ID is required to fetch an organization.'); } try { // Remove generic type, let Medplum infer it return await medplum.readResource("Organization", organizationId); } catch (error: any) { if (error.outcome?.issue?.[0]?.code === 'not-found') { return null; } throw error; } } /** * Updates an existing Organization resource. * @param organizationId - The ID of the organization to update. * @param updates - The partial data to update the organization with. * @returns The updated Organization resource. */ export async function updateOrganization(organizationId: string, updates: UpdateOrganizationArgs): Promise<Organization> { await ensureAuthenticated(); if (!organizationId) { throw new Error('Organization ID is required to update an organization.'); } if (!updates || Object.keys(updates).length === 0) { throw new Error('Updates object cannot be empty for updating an organization.'); } const existingOrganization = await medplum.readResource("Organization", organizationId); if (!existingOrganization) { throw new Error(`Organization with ID ${organizationId} not found.`); } const { resourceType, id, ...safeUpdates } = updates as any; const organizationToUpdate: Organization = { ...existingOrganization, ...safeUpdates, resourceType: "Organization", id: organizationId, }; return medplum.updateResource(organizationToUpdate); } export interface OrganizationSearchCriteria { name?: string; address?: string; // Add other searchable fields as needed, e.g., 'address-city', 'address-postalcode' // Medplum search parameters: https://www.medplum.com/docs/search/clinical-resources/organization } /** * Searches for Organization resources based on criteria. * @param args - The search criteria. * @returns A bundle of Organization resources matching the criteria. */ export async function searchOrganizations(searchArgs: OrganizationSearchArgs): Promise<Organization[]> { await ensureAuthenticated(); const searchCriteria: string[] = []; if (searchArgs.name) { searchCriteria.push(`name=${encodeURIComponent(searchArgs.name)}`); } if (searchArgs.identifier) { searchCriteria.push(`identifier=${encodeURIComponent(searchArgs.identifier)}`); } if (searchArgs.type) { searchCriteria.push(`type=${encodeURIComponent(searchArgs.type)}`); } if (searchArgs.active !== undefined) { searchCriteria.push(`active=${searchArgs.active}`); } if (searchArgs.address) { searchCriteria.push(`address=${encodeURIComponent(searchArgs.address)}`); } if (searchArgs.city) { searchCriteria.push(`address-city=${encodeURIComponent(searchArgs.city)}`); } if (searchArgs.state) { searchCriteria.push(`address-state=${encodeURIComponent(searchArgs.state)}`); } if (searchArgs.postalCode) { searchCriteria.push(`address-postalcode=${encodeURIComponent(searchArgs.postalCode)}`); } if (searchArgs.country) { searchCriteria.push(`address-country=${encodeURIComponent(searchArgs.country)}`); } if (searchCriteria.length === 0) { return []; } const queryString = searchCriteria.join('&'); return medplum.searchResources("Organization", queryString); } // Example usage (for testing purposes, can be removed or moved to a test file) /* async function testOrganizationTools() { // Make sure Medplum is authenticated // await ensureAuthenticated(); // You'd need to import and call this if running standalone let orgId = ''; // Test createOrganization try { const newOrg = await createOrganization({ name: 'Sunset General Hospital', alias: ['SGH', 'Sunset General'], contact: [{ purpose: { coding: [{ system: 'http://terminology.hl7.org/CodeSystem/contactentity-type', code: 'ADMIN' }] }, telecom: [{ system: 'phone', value: '555-123-4567' }] }] }); orgId = newOrg.id as string; console.log('Created Org ID:', orgId); } catch (e) { console.error(e); } if (!orgId) { console.error('Organization creation failed, aborting further tests.'); return; } // Test getOrganizationById try { const fetchedOrg = await getOrganizationById({ organizationId: orgId }); if (fetchedOrg) { console.log('Fetched Org Name:', fetchedOrg.name); } else { console.log('Fetched Org not found by ID:', orgId); } } catch (e) { console.error(e); } // Test updateOrganization try { const updatedOrg = await updateOrganization(orgId, { alias: ['SGH', 'Sunset General', 'Sunset Community Hospital'] }); console.log('Updated Org Aliases:', updatedOrg.alias); } catch (e) { console.error(e); } // Test searchOrganizations try { console.log('\nSearching for organizations with name "Sunset":'); const orgsByName = await searchOrganizations({ name: 'Sunset' }); orgsByName.forEach(entry => console.log('-', entry.name)); console.log('\nSearching for organizations with specific name "Sunset General Hospital":'); const orgsExactName = await searchOrganizations({ name: 'Sunset General Hospital' }); orgsExactName.forEach(entry => console.log('-', entry.name)); // console.log('\nSearching for organizations with address containing "123 Main St":'); // const orgsByAddress = await searchOrganizations({ address: '123 Main St' }); // Assuming an org with this address exists // orgsByAddress.forEach(entry => console.log('-', entry.resource?.name, entry.resource?.address?.[0]?.line?.join(' '))); console.log('\nAttempting search with no criteria (should fail or return none based on implementation):'); try { const noCriteriaSearch = await searchOrganizations({}); console.log('Search with no criteria returned:', noCriteriaSearch.length, 'organizations'); } catch (e) { console.error('Search with no criteria failed as expected:', e); } } catch (e) { console.error(e); } } // testOrganizationTools(); */

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