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
| Name | Required | Description | Default |
|---|---|---|---|
| cardId | Yes | The ID of the card to update | |
| boardId | Yes | The ID of the board the card belongs to | |
| title | No | New title for the card (optional) | |
| properties | No | Property values to update (e.g., {"Status": "In Progress", "Priority": "High"}). Use property names, not IDs. | |
| description | No | Update or set the description/content for the card in markdown format (optional) |
Implementation Reference
- src/index.ts:392-435 (handler)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) } ] }; }
- src/index.ts:146-178 (schema)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'] } },
- src/focalboard-client.ts:318-352 (helper)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); }
- src/focalboard-client.ts:256-265 (helper)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); }
- src/focalboard-client.ts:419-445 (helper)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); } }