Skip to main content
Glama

update_card

Modify card properties, update descriptions, or move cards between columns in Focalboard using human-readable property names.

Instructions

Update a card's properties, including moving it to different columns. Accepts human-readable property and column names.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
cardIdYesThe ID of the card to update
boardIdYesThe ID of the board the card belongs to
titleNoNew title for the card (optional)
propertiesNoProperty values to update (e.g., {"Status": "In Progress", "Priority": "High"}). Use property names, not IDs.
descriptionNoUpdate or set the description/content for the card in markdown format (optional)

Implementation Reference

  • MCP tool handler for 'update_card'. Validates inputs (requires cardId and boardId), conditionally updates title via updateCard, properties via updateCardProperties, description via setCardDescription, then fetches and returns the updated card JSON.
    case 'update_card': {
      const cardId = args?.cardId as string;
      const boardId = args?.boardId as string;
      const title = args?.title as string;
      const properties = (args?.properties as Record<string, string>) || {};
      const description = args?.description as string | undefined;
    
      if (!cardId || !boardId) {
        throw new Error('cardId and boardId are required');
      }
    
      if (!title && Object.keys(properties).length === 0 && !description) {
        throw new Error('Either title, properties, or description must be provided');
      }
    
      let card;
    
      // Update title if provided
      if (title) {
        card = await focalboard.updateCard(boardId, cardId, { title });
      }
    
      // Update properties if provided
      if (Object.keys(properties).length > 0) {
        card = await focalboard.updateCardProperties(cardId, boardId, properties);
      }
    
      // Update description if provided
      if (description) {
        await focalboard.setCardDescription(boardId, cardId, description);
      }
    
      // Fetch the updated card
      card = await focalboard.getCard(cardId);
    
      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify(card, null, 2)
          }
        ]
      };
    }
  • Tool definition including name, description, and input schema for 'update_card'. Specifies required parameters (cardId, boardId) and optional (title, properties as object of strings, description).
    {
      name: 'update_card',
      description: 'Update a card\'s properties, including moving it to different columns. Accepts human-readable property and column names.',
      inputSchema: {
        type: 'object',
        properties: {
          cardId: {
            type: 'string',
            description: 'The ID of the card to update'
          },
          boardId: {
            type: 'string',
            description: 'The ID of the board the card belongs to'
          },
          title: {
            type: 'string',
            description: 'New title for the card (optional)'
          },
          properties: {
            type: 'object',
            description: 'Property values to update (e.g., {"Status": "In Progress", "Priority": "High"}). Use property names, not IDs.',
            additionalProperties: {
              type: 'string'
            }
          },
          description: {
            type: 'string',
            description: 'Update or set the description/content for the card in markdown format (optional)'
          }
        },
        required: ['cardId', 'boardId']
      }
    },
  • Helper function updateCardProperties that resolves human-readable property names and values to internal IDs by fetching the board, then applies the patch via updateCard. Used in the tool handler for properties updates.
    async updateCardProperties(
      cardId: string,
      boardId: string,
      properties: Record<string, string>
    ): Promise<Card> {
      const board = await this.getBoard(boardId);
      const propertyUpdates: Record<string, string> = {};
    
      for (const [propName, value] of Object.entries(properties)) {
        const property = this.findPropertyByName(board, propName);
        if (!property) {
          throw new Error(`Property '${propName}' not found on board`);
        }
    
        // For select/multiSelect types, resolve option ID
        if (property.type === 'select' || property.type === 'multiSelect') {
          const optionId = this.findPropertyOption(property, value);
          if (!optionId) {
            throw new Error(`Option '${value}' not found in property '${propName}'`);
          }
          propertyUpdates[property.id] = optionId;
        } else {
          // For other types, use the value directly
          propertyUpdates[property.id] = value;
        }
      }
    
      const patch: CardPatch = {
        updatedFields: {
          properties: propertyUpdates
        }
      };
    
      return this.updateCard(boardId, cardId, patch);
    }
  • Core helper method to PATCH update a card via the Focalboard API endpoint, then refetches the card since the API returns no body. Used for title updates and by updateCardProperties.
    async updateCard(boardId: string, cardId: string, patch: CardPatch): Promise<Card> {
      await this.makeRequest<void>(
        `/boards/${boardId}/blocks/${cardId}`,
        'PATCH',
        patch
      );
    
      // Fetch and return the updated card since PATCH returns empty
      return this.getCard(cardId);
    }
  • Helper to set or update card description by managing text blocks: updates existing or creates new via createTextBlock. Used in tool handler for description updates.
    async setCardDescription(boardId: string, cardId: string, description: string): Promise<Block> {
      // Get existing content blocks
      const contentBlocks = await this.getCardContent(cardId);
      const textBlocks = contentBlocks.filter(block => block.type === 'text');
    
      if (textBlocks.length > 0) {
        // Update the first text block directly
        const textBlock = textBlocks[0];
        await this.makeRequest<void>(
          `/boards/${boardId}/blocks/${textBlock.id}`,
          'PATCH',
          { title: description }
        );
    
        // Fetch and return the updated block
        const updatedBlocks = await this.makeRequest<Block[]>(
          `/boards/${boardId}/blocks`,
          'GET',
          undefined,
          { block_id: textBlock.id }
        );
        return updatedBlocks[0];
      } else {
        // Create a new text block
        return this.createTextBlock(boardId, cardId, description);
      }
    }
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. While it mentions updating properties and moving columns, it doesn't address important behavioral aspects like whether this requires specific permissions, if changes are reversible, what happens to unspecified properties, or potential rate limits. The description is insufficient for a mutation tool with zero annotation coverage.

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 appropriately concise with just two sentences. The first sentence states the core functionality, and the second adds important implementation detail about human-readable names. No wasted words, though it could be slightly more structured.

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?

For a mutation tool with 5 parameters, no annotations, and no output schema, the description is inadequate. It doesn't explain what happens on success/failure, what values are returned, error conditions, or behavioral constraints. The agent lacks crucial information to use this tool effectively.

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 5 parameters thoroughly. The description adds minimal value beyond the schema by mentioning 'human-readable property and column names' and 'including moving it to different columns', but doesn't provide additional syntax, format details, or constraints beyond what the schema provides.

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 verb ('Update') and resource ('a card's properties'), and specifies that it includes moving cards between columns. However, it doesn't explicitly differentiate from sibling tools like 'create_card' or 'delete_card' beyond the update action.

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 'create_card' or 'delete_card'. It mentions human-readable property and column names but doesn't explain when this tool is appropriate versus other card-related operations.

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/gmjuhasz/focalboard-mcp-server'

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