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

158 lines (157 loc) 5.63 kB
"use strict"; /** * Standardized formatting utilities for consistent output across all CLI and Tool interfaces. * These functions should be used by all formatters to ensure consistent formatting. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.formatDate = formatDate; exports.formatHeading = formatHeading; exports.formatPagination = formatPagination; exports.formatUrl = formatUrl; exports.formatSeparator = formatSeparator; exports.formatBulletList = formatBulletList; exports.formatNumberedList = formatNumberedList; const logger_util_js_1 = require("./logger.util.js"); /** * Format a date in a standardized way: YYYY-MM-DD HH:MM:SS UTC * @param dateString - ISO date string or Date object * @returns Formatted date string */ function formatDate(dateString) { if (!dateString) { return 'Not available'; } try { const date = typeof dateString === 'string' ? new Date(dateString) : dateString; // Format: YYYY-MM-DD HH:MM:SS UTC return date .toISOString() .replace('T', ' ') .replace(/\.\d+Z$/, ' UTC'); } catch { return 'Invalid date'; } } /** * Format a heading with the specified level (markdown) * @param text - The heading text * @param level - The heading level (1-6, defaults to 1) * @returns Formatted heading */ function formatHeading(text, level = 1) { const hashes = '#'.repeat(Math.max(1, Math.min(6, level))); return `${hashes} ${text}`; } /** * Format pagination information in a standardized way for CLI output. * Includes separator, item counts, availability message, next page instructions, and timestamp. * @param pagination - The ResponsePagination object containing pagination details. * @returns Formatted pagination footer string for CLI. */ function formatPagination(pagination) { const methodLogger = logger_util_js_1.Logger.forContext('utils/formatter.util.ts', 'formatPagination'); const parts = [formatSeparator()]; // Start with separator const { count = 0, hasMore, nextCursor, total } = pagination; // Showing count and potentially total if (total !== undefined && total >= 0) { parts.push(`*Showing ${count} of ${total} total items.*`); } else if (count >= 0) { parts.push(`*Showing ${count} item${count !== 1 ? 's' : ''}.*`); } // More results availability if (hasMore) { parts.push('More results are available.'); } // Prompt for the next action (using cursor string for Confluence) if (hasMore && nextCursor) { parts.push(`*Use --cursor "${nextCursor}" to view more.*`); } // Add standard timestamp parts.push(`*Information retrieved at: ${formatDate(new Date())}*`); const result = parts.join('\n').trim(); // Join with newline methodLogger.debug(`Formatted pagination footer: ${result}`); return result; } /** * Format a URL as a markdown link * @param url - The URL to format * @param title - Optional title for the link * @returns Formatted URL as a markdown link */ function formatUrl(url, title) { return `[${title || url}](${url})`; } /** * Format a separator line * @returns Formatted separator line */ function formatSeparator() { return '---'; } /** * Format a bullet list from an object * @param items - The object to format as a bullet list * @param formatter - Optional function to format keys * @returns Formatted bullet list */ function formatBulletList(items, formatter = (key) => key) { const lines = []; for (const [key, value] of Object.entries(items)) { if (value === undefined || value === null) { continue; } const formattedKey = formatter(key); if (typeof value === 'object' && value !== null && 'url' in value) { const urlObj = value; // Handle URL objects with title const urlTitle = urlObj.title || urlObj.url; lines.push(`- **${formattedKey}**: ${formatUrl(String(urlObj.url), String(urlTitle))}`); } else if (typeof value === 'string' && (value.startsWith('http://') || value.startsWith('https://'))) { // Handle URL strings lines.push(`- **${formattedKey}**: ${formatUrl(value)}`); } else if (value instanceof Date) { // Handle dates lines.push(`- **${formattedKey}**: ${formatDate(value)}`); } else if (Array.isArray(value)) { // Handle arrays lines.push(`- **${formattedKey}**: ${value.join(', ')}`); } else { // Handle all other types lines.push(`- **${formattedKey}**: ${String(value)}`); } } return lines.join('\n'); } /** * Format a numbered list from an array * @param items - The array of items to format * @param formatter - Function to format each item * @returns Formatted numbered list */ function formatNumberedList(items, formatter) { return items .map((item, index) => { const formattedItem = formatter(item, index); return `${index + 1}. ${formattedItem}`; }) .join('\n\n'); } /** * Format text as a Markdown code block * @param text Text content * @param language Optional language identifier * @returns Formatted code block string */ // Unused function - commented out // export function formatCodeBlock(text: string, language: string = ''): string { // // Trim trailing newline if present to avoid extra line in block // const trimmedText = text.replace(/$\n/, ''); // return `\`\`\`${language}\n${trimmedText}\n\`\`\``; // }