monica_manage_call
Manage logged phone calls in Monica CRM by creating, viewing, updating, or deleting call records to track conversations with contacts.
Instructions
List, inspect, create, update, or delete logged phone calls. Use this to capture quick notes about conversations with contacts.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | ||
| callId | No | ||
| contactId | No | ||
| limit | No | ||
| page | No | ||
| payload | No |
Implementation Reference
- src/tools/modules/communications.ts:395-409 (registration)Registers the 'monica_manage_call' tool using server.registerTool, providing title, description, and input schema.server.registerTool( 'monica_manage_call', { title: 'Log Monica calls', description: 'List, inspect, create, update, or delete logged phone calls. Use this to capture quick notes about conversations with contacts.', inputSchema: { action: z.enum(['list', 'get', 'create', 'update', 'delete']), callId: z.number().int().positive().optional(), contactId: z.number().int().positive().optional(), limit: z.number().int().min(1).max(100).optional(), page: z.number().int().min(1).optional(), payload: callPayloadSchema.optional() } },
- The async handler function that implements the core logic for all actions (list, get, create, update, delete) of the monica_manage_call tool, using MonicaClient methods and normalization.async ({ action, callId, contactId, limit, page, payload }) => { switch (action) { case 'list': { const response = await client.listCalls({ contactId, limit, page }); const calls = response.data.map(normalizeCall); const scope = contactId ? `contact ${contactId}` : 'your account'; const textSummary = calls.length ? `Found ${calls.length} call${calls.length === 1 ? '' : 's'} for ${scope}.` : `No calls found for ${scope}.`; return { content: [ { type: 'text' as const, text: textSummary } ], structuredContent: { action, contactId, calls, pagination: { currentPage: response.meta.current_page, lastPage: response.meta.last_page, perPage: response.meta.per_page, total: response.meta.total } } }; } case 'get': { if (!callId) { return { isError: true as const, content: [ { type: 'text' as const, text: 'Provide callId when retrieving a call.' } ] }; } const response = await client.getCall(callId); const call = normalizeCall(response.data); const contactName = call.contact?.name || `Contact ${call.contactId}`; return { content: [ { type: 'text' as const, text: `Call ${call.id} with ${contactName} on ${call.calledAt ?? 'unknown date'}.` } ], structuredContent: { action, callId, call } }; } case 'create': { if (!payload) { return { isError: true as const, content: [ { type: 'text' as const, text: 'Provide calledAt, contactId, and optional content when logging a call.' } ] }; } let input: CreateCallPayload; try { input = toCallCreatePayload(payload); } catch (error) { return { isError: true as const, content: [ { type: 'text' as const, text: (error as Error).message } ] }; } const response = await client.createCall(input); const call = normalizeCall(response.data); logger.info({ callId: call.id, contactId: call.contactId }, 'Logged Monica call'); return { content: [ { type: 'text' as const, text: `Logged call ${call.id} for contact ${call.contactId}.` } ], structuredContent: { action, call } }; } case 'update': { if (!callId) { return { isError: true as const, content: [ { type: 'text' as const, text: 'Provide callId when updating a call.' } ] }; } if (!payload) { return { isError: true as const, content: [ { type: 'text' as const, text: 'Provide call details when updating a call.' } ] }; } const patch = toCallUpdatePayload(payload); if (patch.calledAt === undefined && patch.contactId === undefined && patch.content === undefined) { return { isError: true as const, content: [ { type: 'text' as const, text: 'Include at least one field (calledAt, contactId, or content) to update the call.' } ] }; } const response = await client.updateCall(callId, patch); const call = normalizeCall(response.data); logger.info({ callId, contactId: call.contactId }, 'Updated Monica call'); return { content: [ { type: 'text' as const, text: `Updated call ${callId}.` } ], structuredContent: { action, callId, call } }; } case 'delete': { if (!callId) { return { isError: true as const, content: [ { type: 'text' as const, text: 'Provide callId when deleting a call.' } ] }; } const result = await client.deleteCall(callId); logger.info({ callId }, 'Deleted Monica call'); return { content: [ { type: 'text' as const, text: `Deleted call ID ${callId}.` } ], structuredContent: { action, callId, result } }; } default: return { isError: true as const, content: [ { type: 'text' as const, text: `Unsupported action: ${action}.` } ] }; } }
- Zod schema for validating call payload inputs used in create, update actions.const callPayloadSchema = z.object({ calledAt: z .string() .regex(/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/u, 'calledAt must use YYYY-MM-DD format.') .optional(), contactId: z.number().int().positive().optional(), content: z.string().max(1_000_000).optional().nullable() }); type CallPayloadForm = z.infer<typeof callPayloadSchema>;
- Helper to convert user payload form to CreateCallPayload for the Monica API.function toCallCreatePayload(payload: CallPayloadForm): CreateCallPayload { if (!payload.calledAt || typeof payload.contactId !== 'number') { throw new Error('Provide calledAt and contactId when creating a call.'); } return { contactId: payload.contactId, calledAt: payload.calledAt, content: payload.content ?? null }; }
- Helper to convert partial user payload to UpdateCallPayload, only including provided fields.function toCallUpdatePayload(payload: CallPayloadForm): UpdateCallPayload { const result: UpdateCallPayload = {}; if (payload.contactId !== undefined) { result.contactId = payload.contactId; } if (payload.calledAt !== undefined) { result.calledAt = payload.calledAt; } if (payload.content !== undefined) { result.content = payload.content ?? null; } return result; }