@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
78 lines (77 loc) • 2.85 kB
JavaScript
;
/**
* Markdown utility functions for converting HTML to Markdown
* Uses Turndown library for HTML to Markdown conversion
*
* @see https://github.com/mixmark-io/turndown
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.htmlToMarkdown = htmlToMarkdown;
const turndown_1 = __importDefault(require("turndown"));
const logger_util_js_1 = require("./logger.util.js");
// Create a singleton instance of TurndownService with default options
const turndownService = new turndown_1.default({
headingStyle: 'atx', // Use # style headings
bulletListMarker: '-', // Use - for bullet lists
codeBlockStyle: 'fenced', // Use ``` for code blocks
emDelimiter: '_', // Use _ for emphasis
strongDelimiter: '**', // Use ** for strong
linkStyle: 'inlined', // Use [text](url) for links
linkReferenceStyle: 'full', // Use [text][id] + [id]: url for reference links
});
// Add custom rule for strikethrough
turndownService.addRule('strikethrough', {
filter: (node) => {
return (node.nodeName.toLowerCase() === 'del' ||
node.nodeName.toLowerCase() === 's' ||
node.nodeName.toLowerCase() === 'strike');
},
replacement: (content) => `~~${content}~~`,
});
// Add custom rule for tables to improve table formatting
turndownService.addRule('tableCell', {
filter: ['th', 'td'],
replacement: (content, _node) => {
// Simplify content by consolidating whitespace
const simplifiedContent = content.replace(/\s+/g, ' ').trim();
return ` ${simplifiedContent} |`;
},
});
turndownService.addRule('tableRow', {
filter: 'tr',
replacement: (content, node) => {
let output = `|${content}\n`;
// If this is the first row in a table head, add the header separator row
if (node.parentNode &&
'tagName' in node.parentNode &&
node.parentNode.tagName === 'THEAD') {
const cellCount = node.childNodes.length;
output += '|' + ' --- |'.repeat(cellCount) + '\n';
}
return output;
},
});
/**
* Convert HTML content to Markdown
*
* @param html - The HTML content to convert
* @returns The converted Markdown content
*/
function htmlToMarkdown(html) {
if (!html || html.trim() === '') {
return '';
}
try {
const markdown = turndownService.turndown(html);
return markdown;
}
catch (error) {
const conversionLogger = logger_util_js_1.Logger.forContext('utils/markdown.util.ts', 'htmlToMarkdown');
conversionLogger.error('Error converting HTML to Markdown:', error);
// Return the original HTML if conversion fails
return html;
}
}