UNPKG

businessmap-mcp

Version:

MCP server for Businessmap Kanbanize, exposing tools for managing business entities like boards, cards, and columns, facilitating LLM interaction.

155 lines (154 loc) 7.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CardCommentsToolsController = void 0; const zod_1 = require("zod"); const ApiService_1 = require("../../services/ApiService"); const apiResponseHandler_1 = require("../../utils/apiResponseHandler"); const env_1 = require("../../utils/env"); class CardCommentsToolsController { server; constructor(server) { this.server = server; this.registerTools(); } registerTools() { this.registerGetCardCommentsToolhandler(); this.registerGetCardCommentToolhandler(); if (!env_1.env.BUSINESSMAP_READ_ONLY) { this.registerAddCardCommentToolhandler(); this.registerAddFormattedCardCommentToolhandler(); this.registerUpdateCardCommentToolhandler(); this.registerDeleteCardCommentToolhandler(); } } registerGetCardCommentsToolhandler() { this.server.tool("get-card-comments", "Get a card's comments", { cardId: zod_1.z.string().describe("A card id"), }, async ({ cardId }) => { const response = await ApiService_1.apiServices.getCardComments(cardId); return (0, apiResponseHandler_1.handleApiResponse)(response); }); } registerAddCardCommentToolhandler() { this.server.tool("add-card-comment", "Add a comment to a card", { cardId: zod_1.z.string().describe("A card id"), comment: zod_1.z.string().describe("Comment to be added"), }, async ({ cardId, comment }) => { const response = await ApiService_1.apiServices.addCardComment(cardId, comment); return (0, apiResponseHandler_1.handleApiResponse)(response); }); } registerGetCardCommentToolhandler() { this.server.tool("get-card-comment", "Get the details of a comment for a card", { cardId: zod_1.z.string().describe("A card id"), commentId: zod_1.z.string().describe("A comment id"), }, async ({ cardId, commentId }) => { const response = await ApiService_1.apiServices.getCardComment(cardId, commentId); return (0, apiResponseHandler_1.handleApiResponse)(response); }); } registerUpdateCardCommentToolhandler() { this.server.tool("update-card-comment", "Update the details of a comment for a card", { cardId: zod_1.z.string().describe("A card id"), commentId: zod_1.z.string().describe("A comment id"), comment: zod_1.z.string().describe("A comment a updated"), }, async ({ cardId, commentId, comment }) => { const response = await ApiService_1.apiServices.updateCardComment(cardId, commentId, comment); return (0, apiResponseHandler_1.handleApiResponse)(response); }); } registerDeleteCardCommentToolhandler() { this.server.tool("delete-card-comment", "Delete a comment for a card", { cardId: zod_1.z.string().describe("A card id"), commentId: zod_1.z.string().describe("A comment id"), }, async ({ cardId, commentId }) => { const response = await ApiService_1.apiServices.deleteCardComment(cardId, commentId); return (0, apiResponseHandler_1.handleApiResponse)(response); }); } /** * IMPORTANT - API Limitation: * The comment creation API (addCardComment) only accepts plain text (type: plain), * it does not accept HTML. The update API (updateCardComment) accepts complete HTML with inline styles. * * This tool accepts HTML directly and internally: * 1. Extracts plain text from HTML to create the comment * 2. Waits for the returned comment_id * 3. Immediately updates with the original HTML * * For the user, it appears as a single HTML creation operation. */ registerAddFormattedCardCommentToolhandler() { this.server.tool("add-formatted-card-comment", "Add a formatted comment to a card with HTML rich formatting. Accepts HTML content directly. Internally creates a plain text comment first, then immediately updates it with the provided HTML formatting.", { cardId: zod_1.z.string().describe("A card id"), htmlContent: zod_1.z.string().describe("Comment content in HTML format (e.g., <h3>Title</h3><p>Paragraph</p>)"), }, async ({ cardId, htmlContent }) => { // Step 1: Extract plain text from HTML for creation // Remove HTML tags to get plain text, preserving text content const plainText = htmlContent .replace(/<[^>]*>/g, '') // Remove HTML tags .replace(/&nbsp;/g, ' ') // Replace &nbsp; with space .replace(/&amp;/g, '&') // Replace &amp; with & .replace(/&lt;/g, '<') // Replace &lt; with < .replace(/&gt;/g, '>') // Replace &gt; with > .replace(/&quot;/g, '"') // Replace &quot; with " .replace(/&#39;/g, "'") // Replace &#39; with ' .replace(/\s+/g, ' ') // Normalize whitespace .trim(); // If plain text is empty after extraction, use a placeholder const textForCreation = plainText || 'Comment'; // Step 2: Create comment with plain text (API limitation) // This is done internally, user doesn't need to know const createResponse = await ApiService_1.apiServices.addCardComment(cardId, textForCreation); if (createResponse.error) { return (0, apiResponseHandler_1.handleApiResponse)(createResponse); } if (!createResponse.data) { return (0, apiResponseHandler_1.handleApiResponse)({ error: { code: "NO_DATA", message: "Failed to create comment - no data returned", reference: "Check API response" } }); } // Step 3: Extract comment_id from response // The response structure is: { data: CardCommentResponsePost } // CardCommentResponsePost has: { data: DataResponsePost } // DataResponsePost has: { comment_id: number } let commentId; // Try primary path: createResponse.data.data.comment_id if (createResponse.data?.data?.comment_id) { commentId = createResponse.data.data.comment_id.toString(); } // Try alternative path in case API structure is different else if (createResponse.data?.comment_id) { commentId = createResponse.data.comment_id.toString(); } if (!commentId) { return (0, apiResponseHandler_1.handleApiResponse)({ error: { code: "NO_COMMENT_ID", message: "Failed to get comment_id from creation response", reference: `Check API response structure. Response: ${JSON.stringify(createResponse.data)}` } }); } // Step 4: Update comment immediately with HTML formatting // This happens internally, user sees it as a single operation const updateResponse = await ApiService_1.apiServices.updateCardComment(cardId, commentId, htmlContent); if (updateResponse.error) { return (0, apiResponseHandler_1.handleApiResponse)(updateResponse); } // Return success as if it was a single operation // User doesn't need to know about the two-step process return (0, apiResponseHandler_1.handleApiResponse)({ data: { comment_id: commentId, ...updateResponse.data } }); }); } } exports.CardCommentsToolsController = CardCommentsToolsController;