monica_browse_metadata
Look up Monica CRM reference data like countries, genders, and activity types to verify names and IDs before creating or updating records.
Instructions
Inspect Monica lookup catalogs (genders, countries, contact field types, activity types, relationship types). Helpful when you need to confirm the exact name/ID before performing other actions.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| resource | Yes | ||
| search | No | ||
| limit | No | ||
| page | No |
Implementation Reference
- src/tools/modules/metadata.ts:28-64 (registration)Registers the monica_browse_metadata tool with input schema and handler function.server.registerTool( 'monica_browse_metadata', { title: 'Browse Monica metadata catalogs', description: 'Inspect Monica lookup catalogs (genders, countries, contact field types, activity types, relationship types). Helpful when you need to confirm the exact name/ID before performing other actions.', inputSchema: { resource: metadataResourceSchema, search: z.string().min(1).max(255).optional(), limit: z.number().int().min(1).max(250).optional(), page: z.number().int().min(1).optional() } }, async ({ resource, search, limit, page }) => { const query = search?.trim().toLowerCase(); const { items, meta } = await fetchResource({ client, resource, limit, page }); const filteredItems = query ? filterByQuery(resource, items, query) : items; const label = resourceLabels[resource]; const summary = buildSummary(label, filteredItems.length, query, meta.currentPage, meta.lastPage); return { content: [ { type: 'text' as const, text: summary } ], structuredContent: { resource, search: search ?? null, items: filteredItems, pagination: meta } }; } );
- src/tools/modules/metadata.ts:13-21 (schema)Zod schema defining the supported metadata resources (genders, countries, etc.). Used in the tool's inputSchema.const metadataResourceSchema = z.enum([ 'genders', 'countries', 'contactFieldTypes', 'activityTypes', 'relationshipTypes', 'currencies', 'occupations' ]);
- src/tools/modules/metadata.ts:41-63 (handler)Handler logic: fetches metadata for the given resource, applies search filter if provided, generates summary text, and returns structured items with pagination.async ({ resource, search, limit, page }) => { const query = search?.trim().toLowerCase(); const { items, meta } = await fetchResource({ client, resource, limit, page }); const filteredItems = query ? filterByQuery(resource, items, query) : items; const label = resourceLabels[resource]; const summary = buildSummary(label, filteredItems.length, query, meta.currentPage, meta.lastPage); return { content: [ { type: 'text' as const, text: summary } ], structuredContent: { resource, search: search ?? null, items: filteredItems, pagination: meta } }; }
- src/tools/modules/metadata.ts:74-135 (helper)Core helper function that fetches raw data from Monica client APIs based on the resource type, normalizes items and meta.async function fetchResource({ client, resource, limit, page }: FetchResourceArgs) { switch (resource) { case 'genders': { const response = await client.listGenders(limit, page); return { items: response.data.map(normalizeGender), meta: normalizeMeta(response.meta) }; } case 'countries': { const response = await client.listCountries(limit, page); return { items: Object.values(response.data).map(normalizeCountry), meta: normalizeMeta(response.meta) }; } case 'contactFieldTypes': { const response = await client.listContactFieldTypes({ limit, page }); return { items: response.data.map(normalizeContactFieldType), meta: normalizeMeta(response.meta) }; } case 'activityTypes': { const response = await client.listActivityTypes({ limit, page }); return { items: response.data.map(normalizeActivityType), meta: normalizeMeta(response.meta) }; } case 'relationshipTypes': { const response = await client.listRelationshipTypes({ limit, page }); return { items: response.data.map(normalizeRelationshipType), meta: normalizeMeta(response.meta) }; } case 'currencies': { const response = await client.listCurrencies({ limit, page }); return { items: response.data.map(normalizeCurrency), meta: normalizeMeta(response.meta) }; } case 'occupations': { const response = await client.listOccupations({ limit, page }); return { items: response.data.map(normalizeOccupation), meta: normalizeMeta(response.meta) }; } default: throw new Error(`Unsupported resource: ${resource satisfies never}`); } }
- Filters the fetched items by the search query string, with resource-specific filtering logic.function filterByQuery(resource: MetadataResource, items: unknown[], query: string) { switch (resource) { case 'genders': return (items as ReturnType<typeof normalizeGender>[]).filter((gender) => gender.name.toLowerCase().includes(query) ); case 'countries': return (items as ReturnType<typeof normalizeCountry>[]).filter((country) => country.name.toLowerCase().includes(query) || country.iso?.toLowerCase().includes(query) ); case 'contactFieldTypes': return (items as ReturnType<typeof normalizeContactFieldType>[]).filter((type) => type.name.toLowerCase().includes(query) || type.kind?.toLowerCase().includes(query) ); case 'activityTypes': return (items as ReturnType<typeof normalizeActivityType>[]).filter((activityType) => activityType.name.toLowerCase().includes(query) || activityType.category?.name?.toLowerCase().includes(query) ); case 'relationshipTypes': return (items as ReturnType<typeof normalizeRelationshipType>[]).filter((relationshipType) => relationshipType.name.toLowerCase().includes(query) || relationshipType.reverseName.toLowerCase().includes(query) ); case 'currencies': return (items as ReturnType<typeof normalizeCurrency>[]).filter((currency) => currency.iso.toLowerCase().includes(query) || currency.name.toLowerCase().includes(query) ); case 'occupations': return (items as ReturnType<typeof normalizeOccupation>[]).filter((occupation) => occupation.title.toLowerCase().includes(query) || (occupation.company?.name?.toLowerCase().includes(query) ?? false) ); default: return items; } }