@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
JavaScript
;
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');
}