@edicarlos.lds/businessmap-mcp
Version:
Model Context Protocol server for BusinessMap (Kanbanize) integration
672 lines • 30.2 kB
JavaScript
import { addCardParentSchema, addPredecessorSchema, addStickerToCardSchema, addTagToCardSchema, blockCardSchema, cardSizeSchema, createCardSchema, createCardSubtaskSchema, createCommentSchema, createTagSchema, deleteCardSchema, deleteCommentSchema, getCardChildrenSchema, getCardCommentSchema, getCardHistorySchema, getCardLinkedCardsSchema, getCardOutcomesSchema, getCardParentGraphSchema, getCardParentSchema, getCardParentsSchema, getCardSchema, getCardSubtaskSchema, getCardSubtasksSchema, getCardTypesSchema, listCardsSchema, moveCardSchema, removeCardParentSchema, removePredecessorSchema, removeStickerFromCardSchema, removeTagFromCardSchema, unblockCardSchema, updateCardSchema, updateCommentSchema, } from '../../schemas/index.js';
import { createErrorResponse, createSuccessResponse } from './base-tool.js';
export class CardToolHandler {
registerTools(server, client, readOnlyMode) {
this.registerListCards(server, client);
this.registerGetCard(server, client);
this.registerGetCardSize(server, client);
this.registerGetCardComments(server, client);
this.registerGetCardComment(server, client);
this.registerGetCardCustomFields(server, client);
this.registerGetCardTypes(server, client);
this.registerGetCardHistory(server, client);
this.registerGetCardOutcomes(server, client);
this.registerGetCardLinkedCards(server, client);
this.registerGetCardSubtasks(server, client);
this.registerGetCardSubtask(server, client);
this.registerGetCardParents(server, client);
this.registerGetCardParent(server, client);
this.registerGetCardParentGraph(server, client);
this.registerGetCardChildren(server, client);
if (!readOnlyMode) {
this.registerCreateCard(server, client);
this.registerMoveCard(server, client);
this.registerUpdateCard(server, client);
this.registerSetCardSize(server, client);
this.registerDeleteCard(server, client);
this.registerCreateCardSubtask(server, client);
this.registerAddCardParent(server, client);
this.registerRemoveCardParent(server, client);
// Block / Unblock
this.registerBlockCard(server, client);
this.registerUnblockCard(server, client);
// Comments
this.registerCreateComment(server, client);
this.registerUpdateComment(server, client);
this.registerDeleteComment(server, client);
// Tags
this.registerCreateTag(server, client);
this.registerAddTagToCard(server, client);
this.registerRemoveTagFromCard(server, client);
// Stickers
this.registerAddStickerToCard(server, client);
this.registerRemoveStickerFromCard(server, client);
// Predecessors
this.registerAddPredecessor(server, client);
this.registerRemovePredecessor(server, client);
}
}
registerListCards(server, client) {
server.registerTool('list_cards', {
title: 'List Cards',
description: 'Get a list of cards from a board with optional filters',
inputSchema: listCardsSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async (params) => {
try {
const { board_id, ...filters } = params;
const cards = await client.getCards(board_id, filters);
return createSuccessResponse(cards);
}
catch (error) {
return createErrorResponse(error, 'fetching cards');
}
});
}
registerGetCard(server, client) {
server.registerTool('get_card', {
title: 'Get Card',
description: 'Get details of a specific card',
inputSchema: getCardSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async ({ card_id }) => {
try {
const card = await client.getCard(card_id);
return createSuccessResponse(card);
}
catch (error) {
return createErrorResponse(error, 'fetching card');
}
});
}
registerGetCardSize(server, client) {
server.registerTool('get_card_size', {
title: 'Get Card Size',
description: 'Get the size/points of a specific card',
inputSchema: getCardSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async ({ card_id }) => {
try {
const card = await client.getCard(card_id);
const size = card.size || 0;
return {
content: [
{
type: 'text',
text: `Card "${card.title}" (ID: ${card_id}) has size: ${size} points`,
},
],
};
}
catch (error) {
return createErrorResponse(error, 'fetching card size');
}
});
}
registerCreateCard(server, client) {
server.registerTool('create_card', {
title: 'Create Card',
description: 'Create a new card in a board',
inputSchema: createCardSchema.shape,
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
}, async (params) => {
try {
const card = await client.createCard(params);
return createSuccessResponse(card, 'Card created successfully:');
}
catch (error) {
return createErrorResponse(error, 'creating card');
}
});
}
registerMoveCard(server, client) {
server.registerTool('move_card', {
title: 'Move Card',
description: 'Move a card to a different column or lane',
inputSchema: moveCardSchema.shape,
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
}, async ({ card_id, column_id, lane_id, position }) => {
try {
const card = await client.moveCard(card_id, column_id, lane_id, position);
return createSuccessResponse(card, 'Card moved successfully:');
}
catch (error) {
return createErrorResponse(error, 'moving card');
}
});
}
registerUpdateCard(server, client) {
server.registerTool('update_card', {
title: 'Update Card',
description: "Update a card's properties",
inputSchema: updateCardSchema.shape,
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
}, async (params) => {
try {
const card = await client.updateCard(params);
return createSuccessResponse(card, 'Card updated successfully:');
}
catch (error) {
return createErrorResponse(error, 'updating card');
}
});
}
registerSetCardSize(server, client) {
server.registerTool('set_card_size', {
title: 'Set Card Size',
description: 'Set the size/points of a specific card',
inputSchema: cardSizeSchema.shape,
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
}, async ({ card_id, size }) => {
try {
const card = await client.updateCard({ card_id, size });
return {
content: [
{
type: 'text',
text: `Card "${card.title}" (ID: ${card_id}) size updated to: ${size} points`,
},
],
};
}
catch (error) {
return createErrorResponse(error, 'setting card size');
}
});
}
registerGetCardComments(server, client) {
server.registerTool('get_card_comments', {
title: 'Get Card Comments',
description: 'Get all comments for a specific card',
inputSchema: getCardSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async ({ card_id }) => {
try {
const comments = await client.getCardComments(card_id);
return createSuccessResponse({
comments,
count: comments.length,
});
}
catch (error) {
return createErrorResponse(error, 'getting card comments');
}
});
}
registerGetCardComment(server, client) {
server.registerTool('get_card_comment', {
title: 'Get Card Comment',
description: 'Get details of a specific comment from a card',
inputSchema: getCardCommentSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async ({ card_id, comment_id }) => {
try {
const comment = await client.getCardComment(card_id, comment_id);
return createSuccessResponse(comment);
}
catch (error) {
return createErrorResponse(error, 'getting card comment');
}
});
}
registerGetCardCustomFields(server, client) {
server.registerTool('get_card_custom_fields', {
title: 'Get Card Custom Fields',
description: 'Get all custom fields for a specific card',
inputSchema: getCardSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async ({ card_id }) => {
try {
const customFields = await client.getCardCustomFields(card_id);
return createSuccessResponse({
customFields,
count: customFields.length,
});
}
catch (error) {
return createErrorResponse(error, 'getting card custom fields');
}
});
}
registerGetCardTypes(server, client) {
server.registerTool('get_card_types', {
title: 'Get Card Types',
description: 'Get all available card types',
inputSchema: getCardTypesSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async () => {
try {
const cardTypes = await client.getCardTypes();
return createSuccessResponse({
cardTypes,
count: cardTypes.length,
});
}
catch (error) {
return createErrorResponse(error, 'getting card types');
}
});
}
registerGetCardHistory(server, client) {
server.registerTool('get_card_history', {
title: 'Get Card History',
description: 'Get the history of a specific card outcome',
inputSchema: getCardHistorySchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async ({ card_id, outcome_id }) => {
try {
const history = await client.getCardHistory(card_id, outcome_id);
return createSuccessResponse({
history,
count: history.length,
});
}
catch (error) {
return createErrorResponse(error, 'getting card history');
}
});
}
registerGetCardOutcomes(server, client) {
server.registerTool('get_card_outcomes', {
title: 'Get Card Outcomes',
description: 'Get all outcomes for a specific card',
inputSchema: getCardOutcomesSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async ({ card_id }) => {
try {
const outcomes = await client.getCardOutcomes(card_id);
return createSuccessResponse({
outcomes,
count: outcomes.length,
});
}
catch (error) {
return createErrorResponse(error, 'getting card outcomes');
}
});
}
registerGetCardLinkedCards(server, client) {
server.registerTool('get_card_linked_cards', {
title: 'Get Card Linked Cards',
description: 'Get all linked cards for a specific card',
inputSchema: getCardLinkedCardsSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async ({ card_id }) => {
try {
const linkedCards = await client.getCardLinkedCards(card_id);
return createSuccessResponse({
linkedCards,
count: linkedCards.length,
});
}
catch (error) {
return createErrorResponse(error, 'getting card linked cards');
}
});
}
registerGetCardSubtasks(server, client) {
server.registerTool('get_card_subtasks', {
title: 'Get Card Subtasks',
description: 'Get all subtasks for a specific card',
inputSchema: getCardSubtasksSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async ({ card_id }) => {
try {
const subtasks = await client.getCardSubtasks(card_id);
return createSuccessResponse({
subtasks,
count: subtasks.length,
});
}
catch (error) {
return createErrorResponse(error, 'getting card subtasks');
}
});
}
registerGetCardSubtask(server, client) {
server.registerTool('get_card_subtask', {
title: 'Get Card Subtask',
description: 'Get details of a specific subtask from a card',
inputSchema: getCardSubtaskSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async ({ card_id, subtask_id }) => {
try {
const subtask = await client.getCardSubtask(card_id, subtask_id);
return createSuccessResponse(subtask);
}
catch (error) {
return createErrorResponse(error, 'getting card subtask');
}
});
}
registerCreateCardSubtask(server, client) {
server.registerTool('create_card_subtask', {
title: 'Create Card Subtask',
description: 'Create a new subtask for a card',
inputSchema: createCardSubtaskSchema.shape,
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
}, async (params) => {
try {
const { card_id, ...subtaskData } = params;
const subtask = await client.createCardSubtask(card_id, subtaskData);
return createSuccessResponse(subtask, 'Subtask created successfully:');
}
catch (error) {
return createErrorResponse(error, 'creating card subtask');
}
});
}
registerGetCardParents(server, client) {
server.registerTool('get_card_parents', {
title: 'Get Card Parents',
description: 'Get a list of parent cards for a specific card',
inputSchema: getCardParentsSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async ({ card_id }) => {
try {
const parents = await client.getCardParents(card_id);
return createSuccessResponse({
parents,
count: parents.length,
});
}
catch (error) {
return createErrorResponse(error, 'getting card parents');
}
});
}
registerGetCardParent(server, client) {
server.registerTool('get_card_parent', {
title: 'Get Card Parent',
description: 'Check if a card is a parent of a given card',
inputSchema: getCardParentSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async ({ card_id, parent_card_id }) => {
try {
const parent = await client.getCardParent(card_id, parent_card_id);
return createSuccessResponse(parent);
}
catch (error) {
return createErrorResponse(error, 'getting card parent');
}
});
}
registerAddCardParent(server, client) {
server.registerTool('add_card_parent', {
title: 'Add Card Parent',
description: 'Make a card a parent of a given card',
inputSchema: addCardParentSchema.shape,
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
}, async ({ card_id, parent_card_id }) => {
try {
const result = await client.addCardParent(card_id, parent_card_id);
return createSuccessResponse(result, 'Card parent added successfully:');
}
catch (error) {
return createErrorResponse(error, 'adding card parent');
}
});
}
registerRemoveCardParent(server, client) {
server.registerTool('remove_card_parent', {
title: 'Remove Card Parent',
description: 'Remove the link between a child card and a parent card',
inputSchema: removeCardParentSchema.shape,
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false },
}, async ({ card_id, parent_card_id }) => {
try {
await client.removeCardParent(card_id, parent_card_id);
return createSuccessResponse({ card_id, parent_card_id }, 'Card parent removed successfully:');
}
catch (error) {
return createErrorResponse(error, 'removing card parent');
}
});
}
registerGetCardParentGraph(server, client) {
server.registerTool('get_card_parent_graph', {
title: 'Get Card Parent Graph',
description: 'Get a list of parent cards including their parent cards too',
inputSchema: getCardParentGraphSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async ({ card_id }) => {
try {
const parentGraph = await client.getCardParentGraph(card_id);
return createSuccessResponse({
parentGraph,
count: parentGraph.length,
});
}
catch (error) {
return createErrorResponse(error, 'getting card parent graph');
}
});
}
registerGetCardChildren(server, client) {
server.registerTool('get_card_children', {
title: 'Get Card Children',
description: 'Get a list of child cards of a specified parent card',
inputSchema: getCardChildrenSchema.shape,
annotations: { readOnlyHint: true, idempotentHint: true },
}, async ({ card_id }) => {
try {
const children = await client.getCardChildren(card_id);
return createSuccessResponse({
children,
count: children.length,
});
}
catch (error) {
return createErrorResponse(error, 'getting card children');
}
});
}
// ─── Block / Unblock ────────────────────────────────────────────────────────
registerBlockCard(server, client) {
server.registerTool('block_card', {
title: 'Block Card',
description: 'Block a card and set a reason/comment explaining why it is blocked',
inputSchema: blockCardSchema.shape,
}, async ({ card_id, reason }) => {
try {
await client.blockCard(card_id, reason);
return createSuccessResponse({ card_id, reason }, 'Card blocked successfully:');
}
catch (error) {
return createErrorResponse(error, 'blocking card');
}
});
}
registerUnblockCard(server, client) {
server.registerTool('unblock_card', {
title: 'Unblock Card',
description: 'Unblock a card by removing its block reason',
inputSchema: unblockCardSchema.shape,
}, async ({ card_id }) => {
try {
await client.unblockCard(card_id);
return createSuccessResponse({ card_id }, 'Card unblocked successfully:');
}
catch (error) {
return createErrorResponse(error, 'unblocking card');
}
});
}
// ─── Comments ───────────────────────────────────────────────────────────────
registerCreateComment(server, client) {
server.registerTool('create_comment', {
title: 'Create Comment',
description: 'Add a new comment to a card',
inputSchema: createCommentSchema.shape,
}, async ({ card_id, text }) => {
try {
const comment = await client.createCardComment(card_id, { text });
return createSuccessResponse(comment, 'Comment created successfully:');
}
catch (error) {
return createErrorResponse(error, 'creating comment');
}
});
}
registerUpdateComment(server, client) {
server.registerTool('update_comment', {
title: 'Update Comment',
description: 'Update the text of an existing comment on a card',
inputSchema: updateCommentSchema.shape,
}, async ({ card_id, comment_id, text }) => {
try {
const comment = await client.updateCardComment(card_id, comment_id, { text });
return createSuccessResponse(comment, 'Comment updated successfully:');
}
catch (error) {
return createErrorResponse(error, 'updating comment');
}
});
}
registerDeleteComment(server, client) {
server.registerTool('delete_comment', {
title: 'Delete Comment',
description: 'Delete a comment from a card',
inputSchema: deleteCommentSchema.shape,
}, async ({ card_id, comment_id }) => {
try {
await client.deleteCardComment(card_id, comment_id);
return createSuccessResponse({ card_id, comment_id }, 'Comment deleted successfully:');
}
catch (error) {
return createErrorResponse(error, 'deleting comment');
}
});
}
// ─── Tags ────────────────────────────────────────────────────────────────────
registerCreateTag(server, client) {
server.registerTool('create_tag', {
title: 'Create Tag',
description: 'Create a new tag in the workspace',
inputSchema: createTagSchema.shape,
}, async ({ label, color }) => {
try {
const tag = await client.createTag({ label, color });
return createSuccessResponse(tag, 'Tag created successfully:');
}
catch (error) {
return createErrorResponse(error, 'creating tag');
}
});
}
registerAddTagToCard(server, client) {
server.registerTool('add_tag_to_card', {
title: 'Add Tag to Card',
description: 'Add an existing tag to a card',
inputSchema: addTagToCardSchema.shape,
}, async ({ card_id, tag_id }) => {
try {
await client.addTagToCard(card_id, tag_id);
return createSuccessResponse({ card_id, tag_id }, 'Tag added to card successfully:');
}
catch (error) {
return createErrorResponse(error, 'adding tag to card');
}
});
}
registerRemoveTagFromCard(server, client) {
server.registerTool('remove_tag_from_card', {
title: 'Remove Tag from Card',
description: 'Remove a tag from a card',
inputSchema: removeTagFromCardSchema.shape,
}, async ({ card_id, tag_id }) => {
try {
await client.removeTagFromCard(card_id, tag_id);
return createSuccessResponse({ card_id, tag_id }, 'Tag removed from card successfully:');
}
catch (error) {
return createErrorResponse(error, 'removing tag from card');
}
});
}
// ─── Stickers ───────────────────────────────────────────────────────────────
registerAddStickerToCard(server, client) {
server.registerTool('add_sticker_to_card', {
title: 'Add Sticker to Card',
description: 'Add a sticker to a card',
inputSchema: addStickerToCardSchema.shape,
}, async ({ card_id, sticker_id }) => {
try {
const result = await client.addStickerToCard(card_id, sticker_id);
return createSuccessResponse(result, 'Sticker added to card successfully:');
}
catch (error) {
return createErrorResponse(error, 'adding sticker to card');
}
});
}
registerRemoveStickerFromCard(server, client) {
server.registerTool('remove_sticker_from_card', {
title: 'Remove Sticker from Card',
description: 'Remove a sticker from a card using the sticker-card association ID ' +
'(the "id" field returned when listing or adding stickers to a card)',
inputSchema: removeStickerFromCardSchema.shape,
}, async ({ card_id, sticker_card_id }) => {
try {
await client.removeStickerFromCard(card_id, sticker_card_id);
return createSuccessResponse({ card_id, sticker_card_id }, 'Sticker removed from card successfully:');
}
catch (error) {
return createErrorResponse(error, 'removing sticker from card');
}
});
}
// ─── Delete Card ─────────────────────────────────────────────────────────────
registerDeleteCard(server, client) {
server.registerTool('delete_card', {
title: 'Delete Card',
description: 'Permanently delete a card. This action cannot be undone and the card cannot be recovered.',
inputSchema: deleteCardSchema.shape,
}, async ({ card_id }) => {
try {
await client.deleteCard(card_id);
return createSuccessResponse({ card_id }, 'Card deleted successfully:');
}
catch (error) {
return createErrorResponse(error, 'deleting card');
}
});
}
// ─── Predecessors ─────────────────────────────────────────────────────────────
registerAddPredecessor(server, client) {
server.registerTool('add_predecessor', {
title: 'Add Predecessor',
description: 'Establish or update a predecessor-successor relationship between two cards. The predecessor_card_id becomes a prerequisite that must be completed before the card.',
inputSchema: addPredecessorSchema.shape,
}, async ({ card_id, predecessor_card_id, linked_card_position, card_position }) => {
try {
const params = {};
if (linked_card_position !== undefined)
params['linked_card_position'] = linked_card_position;
if (card_position !== undefined)
params['card_position'] = card_position;
await client.addPredecessor(card_id, predecessor_card_id, params);
return createSuccessResponse({ card_id, predecessor_card_id }, 'Predecessor added successfully:');
}
catch (error) {
return createErrorResponse(error, 'adding predecessor');
}
});
}
registerRemovePredecessor(server, client) {
server.registerTool('remove_predecessor', {
title: 'Remove Predecessor',
description: 'Remove the predecessor-successor relationship between two cards.',
inputSchema: removePredecessorSchema.shape,
}, async ({ card_id, predecessor_card_id }) => {
try {
await client.removePredecessor(card_id, predecessor_card_id);
return createSuccessResponse({ card_id, predecessor_card_id }, 'Predecessor removed successfully:');
}
catch (error) {
return createErrorResponse(error, 'removing predecessor');
}
});
}
}
//# sourceMappingURL=card-tools.js.map