Skip to main content
Glama
contactWrappers.ts6.16 kB
import { z } from 'zod'; import type { ToolRegistrationContext } from '../context.js'; import { handleContactOperation } from './contacts.js'; /** * Thin wrapper tools that delegate to monica_manage_contact with pre-selected sections. * These improve tool discoverability while reusing the underlying contact handling logic. */ // Schemas matching the parent contact module const birthdateSchema = z.discriminatedUnion('type', [ z.object({ type: z.literal('exact'), day: z.number().int().min(1).max(31), month: z.number().int().min(1).max(12), year: z.number().int().min(1900).max(9999) }), z.object({ type: z.literal('age'), age: z.number().int().min(0).max(150) }), z.object({ type: z.literal('unknown') }) ]); const deceasedDateSchema = z.discriminatedUnion('type', [ z.object({ type: z.literal('exact'), day: z.number().int().min(1).max(31), month: z.number().int().min(1).max(12), year: z.number().int().min(1900).max(9999) }), z.object({ type: z.literal('age'), age: z.number().int().min(0).max(150) }), z.object({ type: z.literal('unknown') }) ]); const contactProfileSchema = z.object({ firstName: z.string().min(1).max(50), lastName: z.string().max(100).optional().nullable(), nickname: z.string().max(100).optional().nullable(), description: z.string().max(2000).optional().nullable(), genderId: z.number().int().positive().optional(), genderName: z.string().min(1).max(50).optional(), isPartial: z.boolean().optional(), isDeceased: z.boolean().optional(), birthdate: birthdateSchema.optional(), deceasedDate: deceasedDateSchema.optional(), remindOnDeceasedDate: z.boolean().optional() }); const contactFieldPayloadSchema = z.object({ contactId: z.number().int().positive(), contactFieldTypeId: z.number().int().positive().optional(), contactFieldTypeName: z.string().min(1).max(255).optional(), data: z.string().min(1).max(255) }); const addressPayloadSchema = z.object({ contactId: z.number().int().positive(), name: z.string().min(1).max(255), street: z.string().max(255).optional().nullable(), city: z.string().max(255).optional().nullable(), province: z.string().max(255).optional().nullable(), postalCode: z.string().max(255).optional().nullable(), countryId: z.string().max(3).optional().nullable(), countryIso: z.string().max(3).optional().nullable(), countryName: z.string().max(255).optional().nullable() }); export function registerContactWrapperTools(context: ToolRegistrationContext): void { const { server } = context; // Profile wrapper const profileInputSchema = { action: z.enum(['create', 'update', 'delete']), contactId: z.number().int().positive().optional(), profile: contactProfileSchema.optional() }; server.registerTool( 'monica_manage_contact_profile', { title: 'Manage contact profile', description: 'Create, update, or delete a contact profile. Use this simplified tool instead of monica_manage_contact when working with contact profiles. Provide firstName, lastName, and optional fields like nickname, description, genderName, birthdate, etc. Gender is optional - omit if unknown.', inputSchema: profileInputSchema }, async (rawInput) => { const input = z.object(profileInputSchema).parse(rawInput); return handleContactOperation( { section: 'profile', action: input.action, contactId: input.contactId, profile: input.profile }, context ); } ); // Contact field wrapper const fieldInputSchema = { action: z.enum(['list', 'get', 'create', 'update', 'delete']), contactId: z.number().int().positive().optional(), contactFieldId: z.number().int().positive().optional(), fieldPayload: contactFieldPayloadSchema.optional(), limit: z.number().int().min(1).max(100).optional(), page: z.number().int().min(1).optional() }; server.registerTool( 'monica_manage_contact_field', { title: 'Manage contact fields', description: 'List, get, create, update, or delete contact fields like email addresses, phone numbers, social media handles, etc. Use this simplified tool instead of monica_manage_contact when managing contact fields. Provide contactId and fieldPayload with data and contactFieldTypeName (e.g., "Email", "Phone").', inputSchema: fieldInputSchema }, async (rawInput) => { const input = z.object(fieldInputSchema).parse(rawInput); return handleContactOperation( { section: 'field', action: input.action, contactId: input.contactId, contactFieldId: input.contactFieldId, fieldPayload: input.fieldPayload, limit: input.limit, page: input.page }, context ); } ); // Address wrapper const addressInputSchema = { action: z.enum(['list', 'get', 'create', 'update', 'delete']), contactId: z.number().int().positive().optional(), addressId: z.number().int().positive().optional(), addressPayload: addressPayloadSchema.optional(), limit: z.number().int().min(1).max(100).optional(), page: z.number().int().min(1).optional() }; server.registerTool( 'monica_manage_contact_address', { title: 'Manage contact addresses', description: 'List, get, create, update, or delete contact addresses. Use this simplified tool instead of monica_manage_contact when managing addresses. Provide contactId and addressPayload with name, street, city, province, postalCode, and countryName (country lookup is automatic).', inputSchema: addressInputSchema }, async (rawInput) => { const input = z.object(addressInputSchema).parse(rawInput); return handleContactOperation( { section: 'address', action: input.action, contactId: input.contactId, addressId: input.addressId, addressPayload: input.addressPayload, limit: input.limit, page: input.page }, context ); } ); }

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/Jacob-Stokes/monica-mcp'

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