Atlassian Confluence MCP Server

by aashari
Verified
import { Command } from 'commander'; import { Logger } from '../utils/logger.util.js'; import { handleCliError } from '../utils/error.util.js'; import atlassianSpacesController from '../controllers/atlassian.spaces.controller.js'; import { ListSpacesOptions } from '../controllers/atlassian.spaces.types.js'; import { formatHeading, formatPagination } from '../utils/formatter.util.js'; /** * CLI module for managing Confluence spaces. * Provides commands for listing spaces and retrieving space details. * All commands require valid Atlassian credentials. */ /** * Register Confluence Spaces CLI commands with the Commander program * @param program - The Commander program instance to register commands with * @throws Error if command registration fails */ function register(program: Command): void { const cliLogger = Logger.forContext( 'cli/atlassian.spaces.cli.ts', 'register', ); cliLogger.debug('Registering Confluence Spaces CLI commands...'); registerListSpacesCommand(program); registerGetSpaceCommand(program); cliLogger.debug('CLI commands registered successfully'); } /** * Register the command for listing Confluence spaces * @param program - The Commander program instance */ function registerListSpacesCommand(program: Command): void { program .command('list-spaces') .description( `List Confluence spaces accessible to the authenticated user. PURPOSE: Discover available spaces, find their keys for use in other commands (like searching or listing pages), and get a high-level overview of space metadata. Use Case: Useful when you don't know the exact key of a space, or when exploring available spaces. Allows filtering by type (global/personal) and status (current/archived). Output: Formatted list including space name, key, ID, type, status, description snippet, and URL. Supports filtering and pagination. Sorting: By default, spaces are sorted by name in descending order. Examples: $ mcp-atlassian-confluence list-spaces --type global --status current $ mcp-atlassian-confluence list-spaces --limit 50 $ mcp-atlassian-confluence list-spaces --query "Documentation"`, ) .option( '-l, --limit <number>', 'Maximum number of items to return (1-100)', '25', ) .option( '-c, --cursor <string>', 'Pagination cursor for retrieving the next set of results', ) .option( '-q, --query <text>', 'Filter spaces by name, key, or description (simple text search, not query language)', ) .option( '-t, --type <type>', 'Filter by space type: global, personal', 'global', ) .option( '-s, --status <status>', 'Filter by space status: current, archived', 'current', ) .action(async (options) => { const actionLogger = Logger.forContext( 'cli/atlassian.spaces.cli.ts', 'list-spaces', ); try { actionLogger.debug('Processing command options:', options); // Validate type if provided if ( options.type && !['global', 'personal'].includes(options.type) ) { throw new Error( 'Type must be either "global" or "personal"', ); } // Validate status if provided if ( options.status && !['current', 'archived'].includes(options.status) ) { throw new Error( 'Status must be either "current" or "archived"', ); } // Validate limit if provided if (options.limit) { const limit = parseInt(options.limit, 10); if (isNaN(limit) || limit <= 0) { throw new Error( 'Invalid --limit value: Must be a positive integer.', ); } } const filterOptions: ListSpacesOptions = { ...(options.type && { type: options.type }), ...(options.status && { status: options.status }), ...(options.limit && { limit: parseInt(options.limit, 10), }), ...(options.cursor && { cursor: options.cursor }), ...(options.query && { query: options.query }), }; actionLogger.debug( 'Fetching spaces with filters:', filterOptions, ); const result = await atlassianSpacesController.list(filterOptions); actionLogger.debug('Successfully retrieved spaces'); // Print the main content console.log(formatHeading('Spaces', 2)); console.log(result.content); // Print pagination information if available if (result.pagination) { console.log( '\n' + formatPagination( result.pagination.count ?? 0, result.pagination.hasMore, result.pagination.nextCursor, ), ); } } catch (error) { actionLogger.error('Operation failed:', error); handleCliError(error); } }); } /** * Register the command for retrieving a specific Confluence space * @param program - The Commander program instance */ function registerGetSpaceCommand(program: Command): void { program .command('get-space') .description( `Get detailed information about a specific Confluence space. PURPOSE: Retrieve comprehensive metadata for a known space, including its full description, permissions, and homepage details.`, ) .requiredOption( '-k, --space-key <key>', 'Key of the space to retrieve (e.g., DEV, MARKETING)', ) .action(async (options) => { const actionLogger = Logger.forContext( 'cli/atlassian.spaces.cli.ts', 'get-space', ); try { actionLogger.debug('Processing command options:', options); // Validate space key format (typically uppercase alphanumeric) if (!options.spaceKey.match(/^[A-Za-z0-9_]+$/)) { throw new Error( 'Space key must contain only letters, numbers, and underscores.', ); } actionLogger.debug(`Fetching space: ${options.spaceKey}`); const result = await atlassianSpacesController.get({ spaceKey: options.spaceKey, }); console.log(result.content); } catch (error) { handleCliError(error); } }); } export default { register };