Skip to main content
Glama

tasks_add

Add new tasks to the MCP Tasks server with specified status and optional positioning. Supports batch operations for efficient task creation.

Instructions

Add new tasks with a specific status. It's faster and cheaper if you use this in batch. User can add atomically while AI works using the CLI add tool

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
source_idNoSource ID from task_setup() response - Defaults to most recent in the workspace if not provided - Try to always provide it! - If you don't have it, ask the user for a file path and call task_setup()
textsYesEach text becomes a task
statusYesYou might need to infer it from the context: - "To Do" for tasks coming up next (e.g. "Do X next") - "In Progress" for what you'll do now (e.g. "First do X") - "Reminders" instructions for you (the AI) to be constantly reminded of - "Notes" to collect non-actionable notes
indexNo0-based index to place the tasks. e.g.: - 0 for "Do this next" - Omit to place at the end ("Do this later")

Implementation Reference

  • Core handler logic for tasks_add (internally 'add' tool). Loads metadata, removes duplicates, handles special statuses, applies auto-WIP rules, inserts tasks at index, saves state, and returns updated summary.
    handler: (args, context) => {
      let meta = metadata.load(args.source_id)
      const { source, state } = meta
      const { texts, status } = args
      // Remove existing tasks with same text from all groups (duplicate handling)
      for (const groupName of meta.statuses) {
        if (state.groups[groupName]) {
          state.groups[groupName] = state.groups[groupName].filter(text => !texts.includes(text))
        }
      }
      let group = state.groups[status]
      // Special handling for Deleted and other unknown statuses
      if (!group) {
        storage.save(source.path, state)
        return getSummary(source.id)
      }
      const wip = state.groups[env.STATUS_WIP]
      const todos = state.groups[env.STATUS_TODO]
      if (env.AUTO_WIP && args.status === env.STATUS_WIP) {
        // Move all WIP but the first to ToDo
        todos.unshift(...wip)
        wip.length = 0
      }
    
      // Add new tasks at the specified index
      const index = util.clamp(args.index ?? group.length, 0, group.length)
      group.splice(index, 0, ...texts)
      const isUpdate = !!context?.update
      if (env.AUTO_WIP && !wip.length && todos[0] && (todos[0] !== texts[0] || isUpdate)) {
        // Move first ToDo to WIP (but not for updates)
        wip.push(todos.shift()!)
      }
      storage.save(source.path, state)
      // Re-load metadata after state changes
      meta = metadata.load(source.id)
      const affected = _.compact(texts.map(t => meta.tasksByIdOrText[t]))
      return getSummary(source.id, { [isUpdate ? 'updated' : 'added']: affected })
    },
  • Input schema for tasks_add tool using Zod: requires source_id, texts (array of strings), status, optional index.
    schema: z.object({
      source_id: schemas.sourceId,
      texts: z.array(z.string().min(1)).describe('Each text becomes a task'),
      status: schemas.status,
      index: schemas.index,
    }),
  • src/server.ts:16-42 (registration)
    Generic registration loop that adds the tasks_add tool (and others) to the FastMCP server via server.addTool, using the tool's name (tasks_add), description, schema, and cli.runTool for execution.
    for (const tool of Object.values(tools)) {
      if (!tool.isEnabled) {
        continue
      }
      if (tool.isResource) {
        // Register as resource
        server.addResource({
          uri: `resource://${tool.name}`,
          name: tool.description,
          mimeType: 'text/plain',
          load: () => cli.runTool(tool, []).then(text => ({ text })),
        })
      } else {
        // Register as tool with enhanced logging
        server.addTool({
          annotations: {
            openWorldHint: false, // This tool doesn't interact with external systems
            readOnlyHint: tool.isReadOnly,
            title: tool.name,
          },
          name: tool.name,
          description: tool.description,
          parameters: tool.schema,
          execute: (args) => cli.runTool(tool, args),
        })
      }
    }
  • src/tools.ts:68-115 (registration)
    Tool definition for 'add', which is renamed to 'tasks_add' by defineTool due to PREFIX_TOOLS=true, and added to the exported tools object.
    add: defineTool('add', {
      schema: z.object({
        source_id: schemas.sourceId,
        texts: z.array(z.string().min(1)).describe('Each text becomes a task'),
        status: schemas.status,
        index: schemas.index,
      }),
      fromArgs: ([text, status = env.STATUS_TODO, index]) => ({ texts: [text], status, index: index ? Number(index) : undefined }),
      description: 'Add new tasks with a specific status. It\'s faster and cheaper if you use this in batch. User can add atomically while AI works using the CLI add tool',
      handler: (args, context) => {
        let meta = metadata.load(args.source_id)
        const { source, state } = meta
        const { texts, status } = args
        // Remove existing tasks with same text from all groups (duplicate handling)
        for (const groupName of meta.statuses) {
          if (state.groups[groupName]) {
            state.groups[groupName] = state.groups[groupName].filter(text => !texts.includes(text))
          }
        }
        let group = state.groups[status]
        // Special handling for Deleted and other unknown statuses
        if (!group) {
          storage.save(source.path, state)
          return getSummary(source.id)
        }
        const wip = state.groups[env.STATUS_WIP]
        const todos = state.groups[env.STATUS_TODO]
        if (env.AUTO_WIP && args.status === env.STATUS_WIP) {
          // Move all WIP but the first to ToDo
          todos.unshift(...wip)
          wip.length = 0
        }
    
        // Add new tasks at the specified index
        const index = util.clamp(args.index ?? group.length, 0, group.length)
        group.splice(index, 0, ...texts)
        const isUpdate = !!context?.update
        if (env.AUTO_WIP && !wip.length && todos[0] && (todos[0] !== texts[0] || isUpdate)) {
          // Move first ToDo to WIP (but not for updates)
          wip.push(todos.shift()!)
        }
        storage.save(source.path, state)
        // Re-load metadata after state changes
        meta = metadata.load(source.id)
        const affected = _.compact(texts.map(t => meta.tasksByIdOrText[t]))
        return getSummary(source.id, { [isUpdate ? 'updated' : 'added']: affected })
      },
    }),
  • defineTool helper that prefixes tool names with 'tasks_' (e.g., 'add' -> 'tasks_add') if PREFIX_TOOLS is true, and sets other properties.
    function defineTool<S extends ZodSchema>(name: string, tool: {
      schema: S
      description: string
      isResource?: boolean
      isReadOnly?: boolean
      isEnabled?: boolean
      handler: (args: z.infer<S>, context?: any) => any
      fromArgs: (args: string[]) => z.infer<S>
    }) {
      const toolName = env.PREFIX_TOOLS ? `tasks_${name}` : name
      return {
        ...tool,
        name: toolName,
        isResource: tool.isResource ?? false,
        isReadOnly: tool.isReadOnly ?? false,
        isEnabled: tool.isEnabled ?? true,
      }
    }

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/flesler/mcp-tasks'

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