UNPKG

@aashari/mcp-server-atlassian-confluence

Version:

Node.js/TypeScript MCP server for Atlassian Confluence. Provides tools enabling AI systems (LLMs) to list/get spaces & pages (content formatted as Markdown) and search via CQL. Connects AI seamlessly to Confluence knowledge bases using the standard MCP in

139 lines (138 loc) 6.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.formatPagesList = formatPagesList; exports.formatPageDetails = formatPageDetails; const formatter_util_js_1 = require("../utils/formatter.util.js"); /** * Format a list of pages for display * @param pagesData - Raw pages data from the API * @param baseUrl - Base URL for constructing page links * @returns Formatted string with pages information in markdown format */ function formatPagesList(pagesData, baseUrl = '') { if (!pagesData || pagesData.length === 0) { return ('No Confluence pages found matching your criteria.' + '\n\n' + (0, formatter_util_js_1.formatSeparator)() + '\n' + `*Information retrieved at: ${(0, formatter_util_js_1.formatDate)(new Date())}*`); } const lines = [(0, formatter_util_js_1.formatHeading)('Confluence Pages', 1), '']; // Format each page with its details const formattedList = (0, formatter_util_js_1.formatNumberedList)(pagesData, (page, _index) => { const itemLines = []; // Basic information itemLines.push((0, formatter_util_js_1.formatHeading)(page.title, 2)); // Create an object with all the properties to display const pageUrl = `${baseUrl}/pages/viewpage.action?pageId=${page.id}`; const properties = { ID: page.id, Status: page.status, 'Space ID': page.spaceId || 'N/A', Title: page.title, Created: page.createdAt ? (0, formatter_util_js_1.formatDate)(page.createdAt) : 'N/A', Author: page.authorId || 'Unknown', Version: page.version?.number || 'N/A', URL: (0, formatter_util_js_1.formatUrl)(pageUrl, page.title), }; // Format as a bullet list itemLines.push((0, formatter_util_js_1.formatBulletList)(properties, (key) => key)); return itemLines.join('\n'); }); lines.push(formattedList); // Add standard footer with timestamp lines.push('\n\n' + (0, formatter_util_js_1.formatSeparator)()); lines.push(`*Information retrieved at: ${(0, formatter_util_js_1.formatDate)(new Date())}*`); return lines.join('\n'); } /** * Format detailed page information for display * @param pageData - Raw page details from the API * @param markdownBody - Pre-converted markdown content for the page body * @param commentsSummary - Optional comments data to include a summary of recent comments * @returns Formatted string with page details in markdown format */ function formatPageDetails(pageData, markdownBody = '*No content available*', commentsSummary) { // Create URL const baseUrl = pageData._links.base || ''; const pageUrl = pageData._links.webui || ''; const fullUrl = pageUrl.startsWith('http') ? pageUrl : `${baseUrl}${pageUrl}`; const lines = [ (0, formatter_util_js_1.formatHeading)(`Confluence Page: ${pageData.title}`, 1), '', `> A ${pageData.status} page in space \`${pageData.spaceId}\` created on ${(0, formatter_util_js_1.formatDate)(pageData.createdAt)}.`, '', (0, formatter_util_js_1.formatHeading)('Basic Information', 2), ]; // Format basic information as a bullet list const basicProperties = { ID: pageData.id, Title: pageData.title, 'Space ID': pageData.spaceId, Status: pageData.status, 'Created At': (0, formatter_util_js_1.formatDate)(pageData.createdAt), 'Author ID': pageData.authorId, 'Parent ID': pageData.parentId || 'None', }; lines.push((0, formatter_util_js_1.formatBulletList)(basicProperties, (key) => key)); // Content section lines.push(''); lines.push((0, formatter_util_js_1.formatHeading)('Content', 2)); // Use the pre-converted markdown body passed by the controller lines.push(markdownBody); // Comments section if available if (commentsSummary && commentsSummary.content) { lines.push(''); lines.push((0, formatter_util_js_1.formatHeading)('Recent Comments', 2)); // Check if there's comment content to display if (commentsSummary.content.includes('No comments found')) { lines.push('*No comments found for this page*'); } else { // Extract a shorter version of the comments that doesn't include the original heading // and footer to integrate better with our page details format let commentsContent = commentsSummary.content; // Remove the original "Page Comments" heading if it exists commentsContent = commentsContent.replace(/# Page Comments\n\n/, ''); // Remove the footer timestamp if it exists commentsContent = commentsContent.replace(/\n\n---+\n\*Information retrieved at:.*\*/, ''); // Add the extracted comments content lines.push(commentsContent); // Add a link to view all comments if there are more - check in the content string if (commentsSummary.content.includes('More results are available')) { lines.push(''); // Link to view all comments for this page const allCommentsUrl = `${baseUrl}/pages/viewpage.action?pageId=${pageData.id}&showComments=true`; lines.push(`*${(0, formatter_util_js_1.formatUrl)(allCommentsUrl, 'View all comments on this page')}*`); } } } // Labels section lines.push(''); lines.push((0, formatter_util_js_1.formatHeading)('Labels', 2)); if (pageData.labels?.results && pageData.labels.results.length > 0) { const labelLines = []; pageData.labels.results.forEach((label) => { labelLines.push(`- **${label.name}** (ID: ${label.id})`); }); lines.push(labelLines.join('\n')); } else { lines.push('*No labels assigned to this page*'); } // Links section lines.push(''); lines.push((0, formatter_util_js_1.formatHeading)('Links', 2)); lines.push(`- **Web UI**: ${fullUrl}`); lines.push(`- ${(0, formatter_util_js_1.formatUrl)(fullUrl, 'Open in Confluence')}`); // Add standard footer with timestamp lines.push('\n\n' + (0, formatter_util_js_1.formatSeparator)()); lines.push(`*Information retrieved at: ${(0, formatter_util_js_1.formatDate)(new Date())}*`); // Optionally keep the direct link if (fullUrl) { lines.push(`*View this page in Confluence: ${fullUrl}*`); } return lines.join('\n'); }