Skip to main content
Glama
cesarvarela

PostgreSQL MCP Server

by cesarvarela

update-data

Modify existing records in PostgreSQL tables using WHERE conditions to target specific data, with options to return updated records for verification.

Instructions

Update existing records in a table. Requires WHERE conditions for safety. Supports complex WHERE clauses and returns updated records.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
tableYes
dataYes
whereYes
returningNo

Implementation Reference

  • Core handler function for the 'update-data' tool. Parses input with Zod schema, validates connection and parameters, sanitizes table/columns, builds parameterized SQL UPDATE query supporting SET clauses, WHERE with =, IS NULL, IN, LIKE, executes modification, returns updated count and rows (if RETURNING specified).
    export async function updateData(
      rawParams: any
    ): McpToolResponse {
      try {
        // Validate and parse parameters
        const params = updateDataSchema.parse(rawParams);
        // Check database connection status
        const connectionStatus = getConnectionStatus();
        if (connectionStatus.status !== 'connected') {
          return createDatabaseUnavailableResponse("update data");
        }
        
        const { table, data, where, returning } = params;
    
        // Validate table name
        const sanitizedTable = sanitizeIdentifier(table);
    
        // Validate that we have data to update
        if (!data || Object.keys(data).length === 0) {
          throw new Error("No data provided for update");
        }
    
        // Validate that we have WHERE conditions (safety check)
        if (!where || Object.keys(where).length === 0) {
          throw new Error("WHERE clause is required for UPDATE operations for safety");
        }
    
        // Build SET clause
        const setClauses: string[] = [];
        const queryParams: any[] = [];
        let paramIndex = 1;
    
        for (const [column, value] of Object.entries(data)) {
          const sanitizedColumn = sanitizeIdentifier(column);
          setClauses.push(`${sanitizedColumn} = $${paramIndex}`);
          queryParams.push(value);
          paramIndex++;
        }
    
        // Build WHERE clause
        const whereConditions: string[] = [];
        
        for (const [column, value] of Object.entries(where)) {
          const sanitizedColumn = sanitizeIdentifier(column);
          
          if (value === null) {
            whereConditions.push(`${sanitizedColumn} IS NULL`);
          } else if (Array.isArray(value)) {
            // Handle IN operator for arrays
            const placeholders = value.map(() => `$${paramIndex++}`).join(", ");
            whereConditions.push(`${sanitizedColumn} IN (${placeholders})`);
            queryParams.push(...value);
          } else if (typeof value === 'string' && value.includes('%')) {
            // Handle LIKE operator for strings with wildcards
            whereConditions.push(`${sanitizedColumn} LIKE $${paramIndex}`);
            queryParams.push(value);
            paramIndex++;
          } else {
            // Handle equality
            whereConditions.push(`${sanitizedColumn} = $${paramIndex}`);
            queryParams.push(value);
            paramIndex++;
          }
        }
    
        // Build UPDATE query
        let updateQuery = `
          UPDATE ${sanitizedTable}
          SET ${setClauses.join(", ")}
          WHERE ${whereConditions.join(" AND ")}
        `;
    
        // Add RETURNING clause
        let hasEmptyReturning = false;
        if (returning.length > 0) {
          const sanitizedReturning = returning.map((col: string) => 
            col === "*" ? "*" : sanitizeIdentifier(col)
          );
          updateQuery += ` RETURNING ${sanitizedReturning.join(", ")}`;
        } else {
          hasEmptyReturning = true;
        }
    
        debug("Executing update query");
        const result = await executePostgresModification(updateQuery, queryParams);
    
        const response = {
          table: sanitizedTable,
          updated_count: result.affectedCount,
          data: hasEmptyReturning 
            ? Array(result.affectedCount).fill({}) 
            : result.rows,
          updated_at: new Date().toISOString(),
        };
    
        return createMcpSuccessResponse(response);
    
      } catch (error) {
        return createMcpErrorResponse("update data", error);
      }
    }
  • Zod schema definition for 'update-data' tool parameters: table (string), data (record to set), where (record for conditions), returning (array of columns, default ['*']).
    export const updateDataShape: ZodRawShape = {
      table: z.string().min(1, "Table name is required"),
      data: z.record(z.any()),
      where: z.record(z.any()),
      returning: z.array(z.string()).optional().default(["*"]),
    };
    
    export const updateDataSchema = z.object(updateDataShape);
  • index.ts:55-60 (registration)
    Registers the 'update-data' tool on the MCP server, linking name, description, input schema (updateDataShape), and handler function (updateData).
    server.tool(
      "update-data",
      "Update existing records in a table. Requires WHERE conditions for safety. Supports complex WHERE clauses and returns updated records.",
      updateDataShape,
      updateData
    );
Behavior2/5

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

With no annotations provided, the description carries full burden but offers limited behavioral insight. It mentions safety requirements (WHERE conditions) and return behavior (returns updated records), but doesn't cover critical aspects like permissions needed, whether updates are reversible, rate limits, error handling, or transaction implications. For a mutation tool with zero annotation coverage, this leaves significant gaps in understanding its behavior.

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 efficiently structured in two sentences that get straight to the point: first states core functionality and safety requirement, second adds capabilities and return behavior. There's no wasted text, though it could be slightly more front-loaded by mentioning the return behavior earlier.

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 this is a mutation tool with 4 parameters (including complex nested objects), 0% schema coverage, no annotations, and no output schema, the description is insufficiently complete. It doesn't explain what 'data' should contain, how 'where' clauses are structured, what 'returning' controls, or provide examples. The agent would struggle to use this tool correctly without significant additional context.

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?

With 0% schema description coverage, the description must compensate but only partially does so. It mentions 'WHERE conditions' (mapping to 'where' parameter) and 'returns updated records' (hinting at 'returning'), but doesn't explain 'table' or 'data' parameters at all. The description adds some meaning but doesn't fully address the four parameters, especially given the complex nested object structure indicated in context signals.

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

Purpose4/5

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

The description clearly states the action ('Update existing records') and resource ('in a table'), making the purpose immediately understandable. It distinguishes from siblings like 'insert-data' (creates new) and 'delete-data' (removes), but doesn't explicitly contrast with 'query-table' or 'execute-query' which might also modify data.

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 provides some guidance by stating 'Requires WHERE conditions for safety' and mentioning support for 'complex WHERE clauses', which implies when to use it (for updates with conditions). However, it doesn't explicitly say when NOT to use it or name alternatives like 'insert-data' for new records or 'execute-query' for other operations, leaving usage context somewhat implied.

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/cesarvarela/postgres-mcp'

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