Skip to main content
Glama

add_todo

Create a new to-do item in Things.app with title, notes, tags, checklist items, and assign to projects or areas for task management.

Instructions

Create a new to-do item in Things.app. Add notes, tags, checklist items, and assign to projects or areas.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
titleYesTo-do title (required). Clear, actionable description of the task
notesNoAdditional notes or details for the to-do (max 10,000 characters). Supports markdown formatting for rich text
whenNoSchedule the to-do for a specific time. Use "today" for immediate action, "tomorrow" for next day, "evening" for later today, "anytime" for no specific time, "someday" for future consideration, or ISO date format (YYYY-MM-DD) for specific date
deadlineNoSet a deadline for the to-do in ISO date format (YYYY-MM-DD). Creates a deadline reminder in Things.app
tagsNoArray of tag names for organizing and categorizing the to-do (max 20 tags). Tags help with filtering and organization
checklistItemsNoArray of checklist item descriptions to add as sub-tasks (max 100 items). Each item becomes a checkable sub-task within the to-do
projectIdNoID of the project to add this to-do to. Use this when you know the specific project ID
projectNameNoName of the project to add this to-do to. Things.app will find the project by name and add the to-do there
areaIdNoID of the area of responsibility to assign this to-do to. Use this when you know the specific area ID
areaNameNoName of the area of responsibility to assign this to-do to (e.g., "Work", "Personal", "Health")
headingIdNoID of a specific heading within the target project to organize the to-do under
headingNameNoName of a heading within the target project to organize the to-do under (e.g., "Phase 1", "Research")
completedNoMark the to-do as completed immediately upon creation (default: false). Useful for logging already completed tasks
canceledNoMark the to-do as canceled immediately upon creation (default: false). Useful for recording tasks that are no longer needed
creationDateNoOverride the creation date with a specific ISO8601 datetime (YYYY-MM-DDTHH:MM:SS). Useful for importing historical data
completionDateNoSet a specific completion date using ISO8601 datetime (YYYY-MM-DDTHH:MM:SS). Only used when completed is true

Implementation Reference

  • The asynchronous handler function that maps input parameters to Things.app URL scheme parameters, constructs the URL, opens it to create the todo, handles errors, and returns a success response.
    async (params) => {
      try {
        logger.info('Adding new to-do', { title: params.title });
        
        const urlParams: Record<string, any> = {
          title: params.title
        };
    
        // Map schema parameters to Things URL scheme parameters
        if (params.notes) urlParams.notes = params.notes;
        if (params.when) urlParams.when = params.when;
        if (params.deadline) urlParams.deadline = params.deadline;
        if (params.tags) urlParams.tags = params.tags.join(',');
        if (params.checklistItems) urlParams['checklist-items'] = params.checklistItems.join(',');
        if (params.projectId) urlParams['list-id'] = params.projectId;
        if (params.projectName) urlParams.list = params.projectName;
        if (params.areaId) urlParams['area-id'] = params.areaId;
        if (params.areaName) urlParams.area = params.areaName;
        if (params.headingId) urlParams['heading-id'] = params.headingId;
        if (params.headingName) urlParams.heading = params.headingName;
        if (params.completed) urlParams.completed = params.completed;
        if (params.canceled) urlParams.canceled = params.canceled;
        if (params.creationDate) urlParams['creation-date'] = params.creationDate;
        if (params.completionDate) urlParams['completion-date'] = params.completionDate;
        
        const url = buildThingsUrl('add', urlParams);
        logger.debug('Generated URL', { url });
        
        await openThingsUrl(url);
        
        return {
          content: [{
            type: "text",
            text: `Successfully created to-do: ${params.title}`
          }]
        };
      } catch (error) {
        logger.error('Failed to add to-do', { error: error instanceof Error ? error.message : error });
        throw error;
      }
    }
  • Zod schema defining the structure, validation rules, and descriptions for all input parameters of the 'add_todo' tool.
    const addTodoSchema = z.object({
      title: z.string().min(1).describe('To-do title (required). Clear, actionable description of the task'),
      notes: z.string().max(10000).optional().describe('Additional notes or details for the to-do (max 10,000 characters). Supports markdown formatting for rich text'),
      when: z.enum(['today', 'tomorrow', 'evening', 'anytime', 'someday'])
        .or(z.string().regex(/^\d{4}-\d{2}-\d{2}$/))
        .optional()
        .describe('Schedule the to-do for a specific time. Use "today" for immediate action, "tomorrow" for next day, "evening" for later today, "anytime" for no specific time, "someday" for future consideration, or ISO date format (YYYY-MM-DD) for specific date'),
      deadline: z.string()
        .regex(/^\d{4}-\d{2}-\d{2}$/)
        .optional()
        .describe('Set a deadline for the to-do in ISO date format (YYYY-MM-DD). Creates a deadline reminder in Things.app'),
      tags: z.array(z.string().min(1))
        .max(20)
        .optional()
        .describe('Array of tag names for organizing and categorizing the to-do (max 20 tags). Tags help with filtering and organization'),
      checklistItems: z.array(z.string().min(1))
        .max(100)
        .optional()
        .describe('Array of checklist item descriptions to add as sub-tasks (max 100 items). Each item becomes a checkable sub-task within the to-do'),
      projectId: z.string()
        .optional()
        .describe('ID of the project to add this to-do to. Use this when you know the specific project ID'),
      projectName: z.string()
        .optional()
        .describe('Name of the project to add this to-do to. Things.app will find the project by name and add the to-do there'),
      areaId: z.string()
        .optional()
        .describe('ID of the area of responsibility to assign this to-do to. Use this when you know the specific area ID'),
      areaName: z.string()
        .optional()
        .describe('Name of the area of responsibility to assign this to-do to (e.g., "Work", "Personal", "Health")'),
      headingId: z.string()
        .optional()
        .describe('ID of a specific heading within the target project to organize the to-do under'),
      headingName: z.string()
        .optional()
        .describe('Name of a heading within the target project to organize the to-do under (e.g., "Phase 1", "Research")'),
      completed: z.boolean()
        .optional()
        .default(false)
        .describe('Mark the to-do as completed immediately upon creation (default: false). Useful for logging already completed tasks'),
      canceled: z.boolean()
        .optional()
        .default(false)
        .describe('Mark the to-do as canceled immediately upon creation (default: false). Useful for recording tasks that are no longer needed'),
      creationDate: z.string()
        .regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
        .optional()
        .describe('Override the creation date with a specific ISO8601 datetime (YYYY-MM-DDTHH:MM:SS). Useful for importing historical data'),
      completionDate: z.string()
        .regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
        .optional()
        .describe('Set a specific completion date using ISO8601 datetime (YYYY-MM-DDTHH:MM:SS). Only used when completed is true')
    });
  • Registration function that calls server.tool() to register the 'add_todo' tool with the MCP server, providing the tool name, description, input schema, and handler function.
    export function registerAddTodoTool(server: McpServer): void {
      server.tool(
        'add_todo',
        'Create a new to-do item in Things.app. Add notes, tags, checklist items, and assign to projects or areas.',
        addTodoSchema.shape,
        async (params) => {
          try {
            logger.info('Adding new to-do', { title: params.title });
            
            const urlParams: Record<string, any> = {
              title: params.title
            };
    
            // Map schema parameters to Things URL scheme parameters
            if (params.notes) urlParams.notes = params.notes;
            if (params.when) urlParams.when = params.when;
            if (params.deadline) urlParams.deadline = params.deadline;
            if (params.tags) urlParams.tags = params.tags.join(',');
            if (params.checklistItems) urlParams['checklist-items'] = params.checklistItems.join(',');
            if (params.projectId) urlParams['list-id'] = params.projectId;
            if (params.projectName) urlParams.list = params.projectName;
            if (params.areaId) urlParams['area-id'] = params.areaId;
            if (params.areaName) urlParams.area = params.areaName;
            if (params.headingId) urlParams['heading-id'] = params.headingId;
            if (params.headingName) urlParams.heading = params.headingName;
            if (params.completed) urlParams.completed = params.completed;
            if (params.canceled) urlParams.canceled = params.canceled;
            if (params.creationDate) urlParams['creation-date'] = params.creationDate;
            if (params.completionDate) urlParams['completion-date'] = params.completionDate;
            
            const url = buildThingsUrl('add', urlParams);
            logger.debug('Generated URL', { url });
            
            await openThingsUrl(url);
            
            return {
              content: [{
                type: "text",
                text: `Successfully created to-do: ${params.title}`
              }]
            };
          } catch (error) {
            logger.error('Failed to add to-do', { error: error instanceof Error ? error.message : error });
            throw error;
          }
        }
      );
    }
  • src/index.ts:21-21 (registration)
    Main application entry point where registerAddTodoTool is invoked to register the tool with the MCP server instance.
    registerAddTodoTool(server);
  • TypeScript interface defining parameters for adding a todo item, matching the Things.app URL scheme keys used in URL construction.
    export interface AddTodoParams {
      title: string;
      notes?: string;
      when?: WhenValue;
      deadline?: string;
      tags?: string;
      'checklist-items'?: string;
      list?: string;
      heading?: string;
      completed?: boolean;
      canceled?: boolean;
    }

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/wbopan/things-mcp'

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