Skip to main content
Glama

Manage Monica tasks and reminders

monica_manage_task_reminder

Manage tasks and reminders in Monica CRM by creating, updating, deleting, listing, or viewing to-dos and stay-in-touch nudges for contacts.

Instructions

List, inspect, create, update, or delete Monica tasks and reminders. Choose itemType="task" for to-dos or itemType="reminder" for stay-in-touch nudges.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
itemTypeYes
actionYes
taskIdNo
reminderIdNo
contactIdNo
statusNo
limitNo
pageNo
taskPayloadNo
reminderPayloadNo

Implementation Reference

  • Main tool handler function: validates input and dispatches to task or reminder handler based on itemType.
    async (rawInput) => {
      const input = actionItemSchema.parse(rawInput);
    
      if (input.itemType === 'task') {
        return handleTaskAction({ input: input as TaskActionInput, client, logger });
      }
    
      return handleReminderAction({ input: input as ReminderActionInput, client, logger });
    }
  • Handler for task actions: list, get, create, update, delete tasks using Monica API.
    async function handleTaskAction({
      input,
      client,
      logger
    }: {
      input: TaskActionInput;
      client: ToolRegistrationContext['client'];
      logger: ToolRegistrationContext['logger'];
    }) {
      switch (input.action) {
        case 'list': {
          const response = await client.listTasks({
            contactId: input.contactId,
            status: input.status,
            limit: input.limit,
            page: input.page
          });
          const tasks = response.data.map(normalizeTask);
          const scope = input.contactId ? `contact ${input.contactId}` : 'your account';
          const summary = tasks.length
            ? `Fetched ${tasks.length} task${tasks.length === 1 ? '' : 's'} for ${scope}.`
            : `No tasks found for ${scope}.`;
    
          return {
            content: [
              {
                type: 'text' as const,
                text: summary
              }
            ],
            structuredContent: {
              itemType: input.itemType,
              action: input.action,
              contactId: input.contactId,
              status: input.status,
              tasks,
              pagination: {
                currentPage: response.meta.current_page,
                lastPage: response.meta.last_page,
                perPage: response.meta.per_page,
                total: response.meta.total
              }
            }
          };
        }
    
        case 'get': {
          const response = await client.getTask(input.taskId!);
          const task = normalizeTask(response.data);
    
          return {
            content: [
              {
                type: 'text' as const,
                text: `Task ${task.title} (ID ${task.id}).`
              }
            ],
            structuredContent: {
              itemType: input.itemType,
              action: input.action,
              task
            }
          };
        }
    
        case 'create': {
          const payload = input.taskPayload!;
          const result = await client.createTask(toTaskCreatePayload(payload));
          const task = normalizeTask(result.data);
          logger.info({ taskId: task.id }, 'Created Monica task');
    
          return {
            content: [
              {
                type: 'text' as const,
                text: `Created task ${task.title || `#${task.id}`} (ID ${task.id}).`
              }
            ],
            structuredContent: {
              itemType: input.itemType,
              action: input.action,
              task
            }
          };
        }
    
        case 'update': {
          const payload = input.taskPayload!;
          const result = await client.updateTask(input.taskId!, toTaskUpdatePayload(payload));
          const task = normalizeTask(result.data);
          logger.info({ taskId: input.taskId }, 'Updated Monica task');
    
          return {
            content: [
              {
                type: 'text' as const,
                text: `Updated task ${task.title || `#${task.id}`} (ID ${task.id}).`
              }
            ],
            structuredContent: {
              itemType: input.itemType,
              action: input.action,
              taskId: input.taskId,
              task
            }
          };
        }
    
        case 'delete': {
          const result = await client.deleteTask(input.taskId!);
          logger.info({ taskId: input.taskId }, 'Deleted Monica task');
    
          return {
            content: [
              {
                type: 'text' as const,
                text: `Deleted task ID ${input.taskId}.`
              }
            ],
            structuredContent: {
              itemType: input.itemType,
              action: input.action,
              taskId: input.taskId,
              result
            }
          };
        }
    
        default:
          return unreachable(input.action as never);
      }
    }
  • Handler for reminder actions: list, get, create, update, delete reminders using Monica API.
    async function handleReminderAction({
      input,
      client,
      logger
    }: {
      input: ReminderActionInput;
      client: ToolRegistrationContext['client'];
      logger: ToolRegistrationContext['logger'];
    }) {
      switch (input.action) {
        case 'list': {
          const response = await client.listReminders({
            contactId: input.contactId,
            limit: input.limit,
            page: input.page
          });
          const reminders = response.data.map(normalizeReminder);
          const scope = input.contactId ? `contact ${input.contactId}` : 'your account';
          const text = reminders.length
            ? `Found ${reminders.length} reminder${reminders.length === 1 ? '' : 's'} for ${scope}.`
            : `No reminders found for ${scope}.`;
    
          return {
            content: [
              {
                type: 'text' as const,
                text
              }
            ],
            structuredContent: {
              itemType: input.itemType,
              action: input.action,
              contactId: input.contactId,
              reminders,
              pagination: {
                currentPage: response.meta.current_page,
                lastPage: response.meta.last_page,
                perPage: response.meta.per_page,
                total: response.meta.total
              }
            }
          };
        }
    
        case 'get': {
          const response = await client.getReminder(input.reminderId!);
          const reminder = normalizeReminder(response.data);
          const contactName = reminder.contact?.name || `Contact ${reminder.contactId}`;
    
          return {
            content: [
              {
                type: 'text' as const,
                text: `Reminder "${reminder.title}" for ${contactName}. Next due ${reminder.nextExpectedDate ?? 'unknown'}.`
              }
            ],
            structuredContent: {
              itemType: input.itemType,
              action: input.action,
              reminder
            }
          };
        }
    
        case 'create': {
          const payload = input.reminderPayload!;
          let createPayload: CreateReminderPayload;
          try {
            createPayload = toReminderCreatePayload(payload);
          } catch (error) {
            return {
              isError: true as const,
              content: [
                { type: 'text' as const, text: (error as Error).message }
              ]
            };
          }
    
          try {
            const response = await client.createReminder(createPayload);
            const reminder = normalizeReminder(response.data);
            logger.info({ reminderId: reminder.id, contactId: reminder.contactId }, 'Created Monica reminder');
    
            return {
              content: [
                {
                  type: 'text' as const,
                  text: `Created reminder "${reminder.title}" for contact ${reminder.contactId}.`
                }
              ],
              structuredContent: {
                itemType: input.itemType,
                action: input.action,
                reminder
              }
            };
          } catch (error) {
            if (error instanceof MonicaApiError) {
              return buildErrorResponse(formatMonicaApiError(error));
            }
            throw error;
          }
        }
    
        case 'update': {
          const payload = input.reminderPayload!;
          let updatePayload: UpdateReminderPayload;
          try {
            updatePayload = toReminderUpdatePayload(payload);
          } catch (error) {
            return {
              isError: true as const,
              content: [
                { type: 'text' as const, text: (error as Error).message }
              ]
            };
          }
    
          try {
            const response = await client.updateReminder(input.reminderId!, updatePayload);
            const reminder = normalizeReminder(response.data);
            logger.info({ reminderId: input.reminderId }, 'Updated Monica reminder');
    
            return {
              content: [
                {
                  type: 'text' as const,
                  text: `Updated reminder "${reminder.title}" (ID ${reminder.id}).`
                }
              ],
              structuredContent: {
                itemType: input.itemType,
                action: input.action,
                reminderId: input.reminderId,
                reminder
              }
            };
          } catch (error) {
            if (error instanceof MonicaApiError) {
              return buildErrorResponse(formatMonicaApiError(error));
            }
            throw error;
          }
        }
    
        case 'delete': {
          try {
            const result = await client.deleteReminder(input.reminderId!);
            logger.info({ reminderId: input.reminderId }, 'Deleted Monica reminder');
    
            return {
              content: [
                {
                  type: 'text' as const,
                  text: `Deleted reminder ID ${input.reminderId}.`
                }
              ],
              structuredContent: {
                itemType: input.itemType,
                action: input.action,
                reminderId: input.reminderId,
                result
              }
            };
          } catch (error) {
            if (error instanceof MonicaApiError) {
              return buildErrorResponse(formatMonicaApiError(error));
            }
            throw error;
          }
        }
    
        default:
          return unreachable(input.action as never);
      }
    }
  • Zod schemas for tool input validation, including sub-schemas for task and reminder payloads and superRefine for action-specific checks.
    const actionItemInputShape = {
      itemType: z.enum(['task', 'reminder']),
      action: z.enum(['list', 'get', 'create', 'update', 'delete']),
      taskId: z.number().int().positive().optional(),
      reminderId: z.number().int().positive().optional(),
      contactId: z.number().int().positive().optional(),
      status: z.enum(['open', 'completed', 'all']).optional(),
      limit: z.number().int().min(1).max(100).optional(),
      page: z.number().int().min(1).optional(),
      taskPayload: taskPayloadSchema.optional(),
      reminderPayload: reminderPayloadSchema.optional()
    } as const;
    
    const actionItemSchema = z.object(actionItemInputShape).superRefine((data, ctx) => {
      if (data.itemType === 'task') {
        switch (data.action) {
          case 'list':
            break;
          case 'get':
          case 'delete':
            if (typeof data.taskId !== 'number') {
              ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Provide taskId for this action.' });
            }
            break;
          case 'create':
            if (!data.taskPayload) {
              ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Provide task details when creating a task.' });
            }
            break;
          case 'update':
            if (typeof data.taskId !== 'number') {
              ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Provide taskId when updating a task.' });
            }
            if (!data.taskPayload) {
              ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Provide task details when updating a task.' });
            }
            break;
          default:
            break;
        }
      } else {
        switch (data.action) {
          case 'list':
            break;
          case 'get':
          case 'delete':
            if (typeof data.reminderId !== 'number') {
              ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Provide reminderId for this action.' });
            }
            break;
          case 'create':
            if (!data.reminderPayload) {
              ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Provide reminder details when creating a reminder.' });
            }
            break;
          case 'update':
            if (typeof data.reminderId !== 'number') {
              ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Provide reminderId when updating a reminder.' });
            }
            if (!data.reminderPayload) {
              ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Provide reminder details when updating a reminder.' });
            }
            break;
          default:
            break;
        }
      }
    });
  • Registers the 'monica_manage_task_reminder' tool with the MCP server.
    server.registerTool(
      'monica_manage_task_reminder',
      {
        title: 'Manage Monica tasks and reminders',
        description:
          'List, inspect, create, update, or delete Monica tasks and reminders. Choose itemType="task" for to-dos or itemType="reminder" for stay-in-touch nudges.',
        inputSchema: actionItemInputShape
      },
      async (rawInput) => {
        const input = actionItemSchema.parse(rawInput);
    
        if (input.itemType === 'task') {
          return handleTaskAction({ input: input as TaskActionInput, client, logger });
        }
    
        return handleReminderAction({ input: input as ReminderActionInput, client, logger });
      }
    );
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. While it lists the possible actions (list, get, create, update, delete), it doesn't describe what these operations actually do, their side effects, authentication requirements, rate limits, or response formats. For a tool with 10 parameters and complex nested objects, this leaves significant behavioral gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately concise with two sentences that directly address the tool's core functionality. The first sentence states the purpose, and the second provides the key parameter guidance. There's no wasted text, though it could be slightly more structured for a tool of this complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (10 parameters, nested objects, no output schema, and no annotations), the description is incomplete. It doesn't explain how the various parameters interact, what the different actions actually do, what the tool returns, or how to handle the payload objects. For a multi-function tool with significant parameter complexity, this description leaves too many questions unanswered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage and 10 parameters, the description adds minimal value beyond what the schema provides. It only explains the semantics of 'itemType' (task vs reminder) and mentions 'action' implicitly through the opening verb list. The other 8 parameters (taskId, reminderId, contactId, status, limit, page, taskPayload, reminderPayload) receive no explanation in the description, leaving their purposes unclear.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose as 'List, inspect, create, update, or delete Monica tasks and reminders,' which is a specific verb+resource combination. It distinguishes between tasks and reminders by explaining 'itemType="task" for to-dos or itemType="reminder" for stay-in-touch nudges.' However, it doesn't explicitly differentiate this tool from its siblings like monica_manage_activity or monica_manage_note, which prevents a score of 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides implied usage guidance by explaining when to choose 'task' vs 'reminder' item types, but it doesn't offer explicit when-to-use or when-not-to-use instructions relative to sibling tools. There's no mention of alternatives or prerequisites, leaving the agent to infer usage from the action and itemType parameters alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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