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;
    }
Behavior2/5

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

With no annotations provided, the description carries full burden for behavioral disclosure. While it implies a write operation ('Create'), it doesn't address critical behavioral aspects: required permissions, whether creation is idempotent, rate limits, error conditions, or what happens on success (e.g., returns an ID). For a mutation tool with 16 parameters, this is insufficient.

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 a single, efficient sentence that front-loads the core action. It wastes no words but could be slightly more structured by separating capabilities from assignment options. Every word earns its place, though it's brief given the tool's 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 (16 parameters, mutation operation) and lack of annotations and output schema, the description is incomplete. It doesn't explain what happens after creation (e.g., returns a todo ID), error handling, or important behavioral constraints. For a create tool with many options, more context is needed to guide effective use.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents all 16 parameters thoroughly. The description adds minimal value beyond the schema by mentioning notes, tags, checklist items, projects, and areas, but doesn't provide additional syntax, constraints, or usage examples that aren't already in the parameter descriptions.

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

Purpose5/5

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

The description clearly states the verb ('Create') and resource ('new to-do item in Things.app'), and distinguishes from siblings by specifying what can be added (notes, tags, checklist items) and where it can be assigned (projects or areas). This is specific and differentiates from tools like 'add_project' or 'update_todo'.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives like 'update_todo' or 'add_project'. It lists capabilities but doesn't specify prerequisites, constraints, or when-not-to-use scenarios. For example, it doesn't clarify if this is for initial creation only versus modifying existing todos.

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

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