Skip to main content
Glama

task_update

Modify task details in Saga MCP's project tracker by updating specific fields like status, priority, or due date, with automatic activity logging for status changes.

Instructions

Update a task. Pass only fields to change. Status transitions are automatically logged in the activity log.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
idYesTask ID
titleNo
descriptionNo
statusNo
priorityNo
assigned_toNo
estimated_hoursNo
actual_hoursNo
due_dateNo
source_refNoLink to source code location
depends_onNoTask IDs this task depends on (replaces existing)
sort_orderNo
tagsNo

Implementation Reference

  • The function 'handleTaskUpdate' implements the logic for the 'task_update' tool. It updates database records, handles dependencies, and logs activity.
    function handleTaskUpdate(args: Record<string, unknown>) {
      const db = getDb();
      const id = args.id as number;
    
      const oldRow = db.prepare('SELECT * FROM tasks WHERE id = ?').get(id) as Record<string, unknown> | undefined;
      if (!oldRow) throw new Error(`Task ${id} not found`);
    
      const update = buildUpdate('tasks', id, args, [
        'title', 'description', 'status', 'priority', 'assigned_to',
        'estimated_hours', 'actual_hours', 'due_date', 'source_ref', 'sort_order', 'tags',
      ]);
    
      let newRow: Record<string, unknown>;
    
      if (update) {
        newRow = db.prepare(update.sql).get(...update.params) as Record<string, unknown>;
        logEntityUpdate(db, 'task', id, newRow.title as string, oldRow, newRow, [
          'status', 'priority', 'assigned_to', 'title',
        ]);
      } else if (args.depends_on !== undefined) {
        // Only depends_on changed, no column updates
        newRow = oldRow;
      } else {
        throw new Error('No fields to update');
      }
    
      // Handle dependency updates
      if (args.depends_on !== undefined) {
        const dependsOn = args.depends_on as number[];
        setDependencies(db, id, dependsOn);
        logActivity(db, 'task', id, 'updated', 'depends_on', null,
          dependsOn.length > 0 ? dependsOn.join(',') : '(none)',
          `Task '${newRow.title}' dependencies updated: [${dependsOn.join(', ')}]`);
        evaluateAndUpdateDependencies(db, id);
        // Re-fetch in case status changed
        newRow = db.prepare('SELECT * FROM tasks WHERE id = ?').get(id) as Record<string, unknown>;
      }
    
      // Auto time tracking: when status changes to done and actual_hours wasn't manually set
      const statusChanged = args.status && oldRow.status !== args.status;
      if (statusChanged && args.status === 'done' && !args.actual_hours && !newRow.actual_hours) {
        const startEntry = db.prepare(
          `SELECT created_at FROM activity_log
           WHERE entity_type = 'task' AND entity_id = ? AND action = 'status_changed'
             AND field_name = 'status' AND new_value = 'in_progress'
           ORDER BY created_at DESC LIMIT 1`
        ).get(id) as { created_at: string } | undefined;
    
        if (startEntry) {
          const startMs = new Date(startEntry.created_at + 'Z').getTime();
          const nowMs = Date.now();
          const hours = Math.round(((nowMs - startMs) / 3_600_000) * 10) / 10; // 1 decimal
          if (hours > 0) {
            db.prepare('UPDATE tasks SET actual_hours = ? WHERE id = ?').run(hours, id);
            (newRow as Record<string, unknown>).actual_hours = hours;
            logActivity(db, 'task', id, 'updated', 'actual_hours', null, String(hours),
              `Task '${newRow.title}' auto-tracked: ${hours}h`);
          }
        }
      }
    
      // Re-evaluate downstream tasks when this task is marked done
      if (statusChanged && args.status === 'done') {
        reevaluateDownstream(db, id);
      }
  • The schema definition for the 'task_update' tool, specifying its input properties.
    name: 'task_update',
    description:
      'Update a task. Pass only fields to change. Status transitions are automatically logged in the activity log.',
    annotations: { title: 'Update Task', readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
    inputSchema: {
      type: 'object',
      properties: {
        id: { type: 'integer', description: 'Task ID' },
        title: { type: 'string' },
        description: { type: 'string' },
        status: { type: 'string', enum: ['todo', 'in_progress', 'review', 'done', 'blocked'] },
        priority: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] },
        assigned_to: { type: 'string' },
        estimated_hours: { type: 'number' },
        actual_hours: { type: 'number' },
        due_date: { type: 'string' },
        source_ref: {
          type: 'object',
          description: 'Link to source code location',
          properties: {
            file: { type: 'string', description: 'File path' },
            line_start: { type: 'integer', description: 'Start line number' },
            line_end: { type: 'integer', description: 'End line number' },
            repo: { type: 'string', description: 'Repository URL or name' },
            commit: { type: 'string', description: 'Commit hash' },
          },
          required: ['file'],
        },
        depends_on: { type: 'array', items: { type: 'integer' }, description: 'Task IDs this task depends on (replaces existing)' },
        sort_order: { type: 'integer' },
  • Registration of 'task_update' handler in the tools list.
    task_update: handleTaskUpdate,

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/spranab/saga-mcp'

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