@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
126 lines (125 loc) • 6.11 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const logger_util_js_1 = require("../utils/logger.util.js");
const error_handler_util_js_1 = require("../utils/error-handler.util.js");
const atlassian_pages_formatter_js_1 = require("./atlassian.pages.formatter.js");
const vendor_atlassian_pages_service_js_1 = __importDefault(require("../services/vendor.atlassian.pages.service.js"));
const defaults_util_js_1 = require("../utils/defaults.util.js");
/**
* Controller for managing Confluence pages.
* Provides functionality for listing pages and retrieving page details.
*/
// Create a contextualized logger for this file
const controllerLogger = logger_util_js_1.Logger.forContext('controllers/atlassian.pages.controller.ts');
// Log controller initialization
controllerLogger.debug('Confluence pages controller initialized');
/**
* List pages from Confluence with filtering options
* @param options - Options for filtering pages
* @param options.spaceId - Filter by space ID(s)
* @param options.containerId - Alternative form of spaceId for consistency across services
* @param options.query - Filter by text in title, content or labels
* @param options.status - Filter by page status
* @param options.sort - Sort order for results
* @param options.limit - Maximum number of pages to return
* @param options.cursor - Pagination cursor for subsequent requests
* @returns Promise with formatted pages list content
* @throws Error if page listing fails
*/
async function list(options = {}) {
const methodLogger = logger_util_js_1.Logger.forContext('controllers/atlassian.pages.controller.ts', 'list');
methodLogger.debug('Listing Confluence pages with options:', options);
try {
// Create defaults object with proper typing
const defaults = {
limit: defaults_util_js_1.DEFAULT_PAGE_SIZE,
sort: '-modified-date',
status: ['current'],
};
// Apply defaults to ensure all standard properties are set
const mergedOptions = (0, defaults_util_js_1.applyDefaults)(options, defaults);
// Support containerId (standardized) or spaceId (Confluence-specific)
const spaceId = options.containerId || options.spaceId;
// Map controller options to service parameters
const params = {
...(spaceId && { spaceId }),
...(mergedOptions.query && { query: mergedOptions.query }),
...(mergedOptions.status && { status: mergedOptions.status }),
...(mergedOptions.sort && { sort: mergedOptions.sort }),
// Additional parameters with defaults
limit: mergedOptions.limit,
cursor: mergedOptions.cursor,
bodyFormat: 'storage',
};
methodLogger.debug('Using service params:', params);
// Get pages data from the API
const pagesData = await vendor_atlassian_pages_service_js_1.default.list(params);
// Log only summary information instead of the entire response
methodLogger.debug(`Retrieved ${pagesData.results.length} pages. Has more: ${pagesData._links?.next ? 'yes' : 'no'}`);
// The formatPagesList function expects a pagesData parameter with results
// Extract the nextCursor from the links
const nextCursor = pagesData._links?.next?.split('cursor=')[1] || '';
const formattedPages = (0, atlassian_pages_formatter_js_1.formatPagesList)(pagesData.results);
return {
content: formattedPages,
pagination: {
count: pagesData.results.length,
hasMore: !!pagesData._links?.next,
nextCursor: nextCursor,
},
};
}
catch (error) {
// Use the standardized error handler
return (0, error_handler_util_js_1.handleControllerError)(error, {
entityType: 'Pages',
operation: 'listing',
source: 'controllers/atlassian.pages.controller.ts@list',
});
}
}
/**
* Get details of a specific Confluence page
* @param args - Object containing the ID of the page to retrieve
* @param args.pageId - The ID of the page
* @returns Promise with formatted page details content
* @throws Error if page retrieval fails
*/
async function get(args) {
const { pageId } = args;
const methodLogger = logger_util_js_1.Logger.forContext('controllers/atlassian.pages.controller.ts', 'get');
methodLogger.debug(`Getting Confluence page with ID: ${pageId}...`);
try {
// Map controller options to service parameters
const params = {
bodyFormat: defaults_util_js_1.PAGE_DEFAULTS.BODY_FORMAT,
includeLabels: defaults_util_js_1.PAGE_DEFAULTS.INCLUDE_LABELS,
includeProperties: defaults_util_js_1.PAGE_DEFAULTS.INCLUDE_PROPERTIES,
includeWebresources: defaults_util_js_1.PAGE_DEFAULTS.INCLUDE_WEBRESOURCES,
includeCollaborators: defaults_util_js_1.PAGE_DEFAULTS.INCLUDE_COLLABORATORS,
includeVersion: defaults_util_js_1.PAGE_DEFAULTS.INCLUDE_VERSION,
};
methodLogger.debug('Using service params:', params);
// Get page data from the API
const pageData = await vendor_atlassian_pages_service_js_1.default.get(pageId, params);
// Log only key information instead of the entire response
methodLogger.debug(`Retrieved page: ${pageData.title} (${pageData.id})`);
// Format the page data for display
const formattedPage = (0, atlassian_pages_formatter_js_1.formatPageDetails)(pageData);
return {
content: formattedPage,
};
}
catch (error) {
return (0, error_handler_util_js_1.handleControllerError)(error, {
entityType: 'Page',
entityId: pageId,
operation: 'retrieving',
source: 'controllers/atlassian.pages.controller.ts@get',
});
}
}
exports.default = { list, get };