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

84 lines (83 loc) 5.49 kB
"use strict"; 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_util_js_1 = require("../utils/error.util.js"); const atlassian_search_controller_js_1 = __importDefault(require("../controllers/atlassian.search.controller.js")); /** * CLI module for searching Confluence content. * Provides commands for searching Confluence content using Confluence Query Language (CQL). * All commands require valid Atlassian credentials. */ /** * Register Confluence Search 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) { const cliLogger = logger_util_js_1.Logger.forContext('cli/atlassian.search.cli.ts', 'register'); cliLogger.debug('Registering Confluence Search CLI commands...'); registerSearchCommand(program); cliLogger.debug('CLI commands registered successfully'); } /** * Register the command for searching Confluence content * @param program - The Commander program instance */ function registerSearchCommand(program) { program .command('search') .description('Search Confluence content using CQL (Confluence Query Language), with pagination.') .option('-l, --limit <number>', 'Maximum number of items to return (1-100). Use this to control the response size. Useful for pagination or when you only need a few results. The Confluence search API caps results at 100 items per request.', '25') .option('-c, --cursor <string>', 'Pagination cursor for retrieving the next set of results. Use this to navigate through large result sets. Obtain this opaque string from the pagination information included at the end of the previous response. Confluence uses cursor-based pagination rather than offset-based pagination.') .option('-q, --cql <cql>', 'Full CQL query for advanced filtering. If provided, this forms the base of the search and other filter options (--title, --space-key, etc.) will be ANDed with it. Example: `space = "DOCS" AND label = "release-notes"`.') .option('-t, --title <text>', 'Filter results to content where the title contains this text (case-insensitive search). If --cql is also provided, this will be ANDed with it. Otherwise, it will be used to build the CQL as `title ~ "YOUR_TITLE"`.') .option('-k, --space-key <key>', 'Filter results to content within a specific space key. If --cql is also provided, this will be ANDed with it. Otherwise, it will be used to build the CQL as `space = "YOUR_SPACE"`.') .option('--label <labels...>', 'Filter results to content tagged with ALL of these labels (repeatable option). If --cql is also provided, this will be ANDed with it. Otherwise, it will be used to build the CQL with multiple label conditions.') .option('--type <type>', 'Filter results by content type. Choose either "page" or "blogpost". If --cql is also provided, this will be ANDed with it. Otherwise, it will be used to build the CQL as `type = "YOUR_TYPE"`.', (value) => { if (!['page', 'blogpost'].includes(value)) { throw new Error('Type must be either "page" or "blogpost"'); } return value; }) .option('-s, --query <text>', 'Simple text search query. This will search for the given text within content body, title, and comments. Translates to CQL: `text ~ "YOUR_QUERY"`. If both --query and --cql are provided, they will be combined with AND.') .action(async (options) => { const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.search.cli.ts', 'search'); try { actionLogger.debug('Processing command options:', options); // 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 searchOptions = { ...(options.cql && { cql: options.cql }), ...(options.title && { title: options.title }), ...(options.spaceKey && { spaceKey: options.spaceKey }), ...(options.label && { labels: options.label }), ...(options.type && { contentType: options.type, }), ...(options.limit && { limit: parseInt(options.limit, 10), }), ...(options.cursor && { cursor: options.cursor }), ...(options.query && { query: options.query }), }; actionLogger.debug('Executing search with options:', searchOptions); const result = await atlassian_search_controller_js_1.default.search(searchOptions); actionLogger.debug('Successfully received search results'); // Print the main content (which now includes executed CQL and pagination information) console.log(result.content); } catch (error) { actionLogger.error('Operation failed:', error); (0, error_util_js_1.handleCliError)(error); } }); } exports.default = { register };