Skip to main content
Glama

project_update

Idempotent

Update any project by submitting only the fields to change. Use status 'archived' to soft-delete a project.

Instructions

Update a project. Pass only the fields you want to change. Set status to "archived" to soft-delete.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
idYesProject ID
nameNo
descriptionNo
statusNo
tagsNo

Implementation Reference

  • The handler function for project_update tool. Fetches existing project by ID, builds an UPDATE SQL via buildUpdate helper (allowing only name/description/status/tags), executes it with RETURNING *, logs field-level changes, and returns the updated row.
    function handleProjectUpdate(args: Record<string, unknown>) {
      const db = getDb();
      const id = args.id as number;
    
      const oldRow = db.prepare('SELECT * FROM projects WHERE id = ?').get(id) as Record<string, unknown> | undefined;
      if (!oldRow) throw new Error(`Project ${id} not found`);
    
      const update = buildUpdate('projects', id, args, ['name', 'description', 'status', 'tags']);
      if (!update) throw new Error('No fields to update');
    
      const newRow = db.prepare(update.sql).get(...update.params) as Record<string, unknown>;
      logEntityUpdate(db, 'project', id, newRow.name as string, oldRow, newRow, ['name', 'status']);
    
      return newRow;
    }
  • The tool definition / input schema for project_update. Requires 'id' (integer) and accepts optional 'name', 'description', 'status' (enum), and 'tags' (string array). Annotated as non-destructive and idempotent.
    {
      name: 'project_update',
      description:
        'Update a project. Pass only the fields you want to change. Set status to "archived" to soft-delete.',
      annotations: { title: 'Update Project', readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'integer', description: 'Project ID' },
          name: { type: 'string' },
          description: { type: 'string' },
          status: { type: 'string', enum: ['active', 'on_hold', 'completed', 'archived'] },
          tags: { type: 'array', items: { type: 'string' } },
        },
        required: ['id'],
      },
    },
  • Registration of the project_update handler (handleProjectUpdate) in the handlers map exported from projects.ts. This map is consumed in src/index.ts where ALL_HANDLERS spreads it and dispatches incoming tool calls.
    export const handlers: Record<string, ToolHandler> = {
      project_create: handleProjectCreate,
      project_list: handleProjectList,
      project_update: handleProjectUpdate,
    };
  • The buildUpdate helper used by handleProjectUpdate. Dynamically constructs an UPDATE SQL with RETURNING * for only the allowedColumns that are present in the fields. For JSON columns (including 'tags'), the value is JSON-stringified. Also sets updated_at to current datetime. Returns null if no fields to update.
    export function buildUpdate(
      table: string,
      id: number,
      fields: Record<string, unknown>,
      allowedColumns: string[]
    ): { sql: string; params: unknown[] } | null {
      const updates: string[] = [];
      const params: unknown[] = [];
    
      for (const col of allowedColumns) {
        if (fields[col] !== undefined) {
          updates.push(`${col} = ?`);
          params.push(JSON_COLUMNS.has(col) ? JSON.stringify(fields[col]) : fields[col]);
        }
      }
    
      if (updates.length === 0) return null;
    
      updates.push("updated_at = datetime('now')");
      params.push(id);
    
      return {
        sql: `UPDATE ${table} SET ${updates.join(', ')} WHERE id = ? RETURNING *`,
        params,
      };
    }
  • The logEntityUpdate helper called by handleProjectUpdate to log field-level changes. Tracks 'name' and 'status' fields, creating activity_log entries with action 'status_changed' for status changes or 'updated' for other field changes.
    export function logEntityUpdate(
      db: Database.Database,
      entityType: string,
      entityId: number,
      entityName: string,
      oldRow: Record<string, unknown>,
      newRow: Record<string, unknown>,
      trackedFields: string[]
    ): void {
      for (const field of trackedFields) {
        const oldVal = String(oldRow[field] ?? '');
        const newVal = String(newRow[field] ?? '');
        if (oldVal !== newVal) {
          const action = field === 'status' ? 'status_changed' : 'updated';
          logActivity(
            db, entityType, entityId, action, field, oldVal, newVal,
            `${entityType} '${entityName}' ${field}: ${oldVal} -> ${newVal}`
          );
        }
      }
    }
Behavior4/5

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

Annotations already indicate the tool is not read-only and not destructive, with idempotency. The description adds value by disclosing the soft-delete behavior (setting status to 'archived') and the partial update semantics, which go beyond what annotations provide. No contradictions with annotations.

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

Conciseness5/5

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

The description is comprised of two concise and front-loaded sentences, delivering key information without extraneous content. Every sentence adds value: the first states the primary action and partial update, the second explains the soft-delete use of the 'status' parameter.

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

Completeness4/5

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

Given the tool's moderate complexity (5 parameters, partial update, soft-delete) and the absence of an output schema, the description covers the essential behavioral aspects. It is missing details about response format, error handling, or authentication, but the provided information is sufficient for basic correct usage.

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 low (20%), with only 'id' described. The description provides high-level guidance on partial updates and the effect of the 'status' parameter (soft-delete), but it does not elaborate on other parameters like 'name', 'description', or 'tags'. This partially compensates but insufficiently addresses the low coverage.

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 'Update a project' as the primary action, distinguishing it from creation or listing tools. It also specifies the partial update behavior and the special effect of setting status to 'archived' for soft-deletion, leaving no ambiguity about the tool's purpose.

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 advises to 'Pass only the fields you want to change,' implying partial updates, and explains soft-delete via status. However, it lacks explicit guidance on when to use this tool versus alternatives like project_create (for new projects) or other sibling tools, and does not mention prerequisites or restrictions.

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

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