Skip to main content
Glama
atlassian.api.cli.ts6.34 kB
import { Command } from 'commander'; import { Logger } from '../utils/logger.util.js'; import { handleCliError } from '../utils/error.util.js'; import { handleGet, handlePost, handlePut, handlePatch, handleDelete, } from '../controllers/atlassian.api.controller.js'; /** * CLI module for generic Confluence API access. * Provides commands for making GET, POST, PUT, PATCH, and DELETE requests to any Confluence API endpoint. */ // Create a contextualized logger for this file const cliLogger = Logger.forContext('cli/atlassian.api.cli.ts'); // Log CLI initialization cliLogger.debug('Confluence API CLI module initialized'); /** * Parse JSON string with error handling and basic validation * @param jsonString - JSON string to parse * @param fieldName - Name of the field for error messages * @returns Parsed JSON object */ function parseJson<T extends Record<string, unknown>>( jsonString: string, fieldName: string, ): T { let parsed: unknown; try { parsed = JSON.parse(jsonString); } catch { throw new Error( `Invalid JSON in --${fieldName}. Please provide valid JSON.`, ); } // Validate that the parsed value is an object (not null, array, or primitive) if ( parsed === null || typeof parsed !== 'object' || Array.isArray(parsed) ) { throw new Error( `Invalid --${fieldName}: expected a JSON object, got ${parsed === null ? 'null' : Array.isArray(parsed) ? 'array' : typeof parsed}.`, ); } return parsed as T; } /** * Register a read command (GET/DELETE - no body) * @param program - Commander program instance * @param name - Command name * @param description - Command description * @param handler - Controller handler function */ function registerReadCommand( program: Command, name: string, description: string, handler: (options: { path: string; queryParams?: Record<string, string>; jq?: string; outputFormat?: 'toon' | 'json'; }) => Promise<{ content: string }>, ): void { program .command(name) .description(description) .requiredOption( '-p, --path <path>', 'API endpoint path (e.g., "/wiki/api/v2/spaces", "/wiki/api/v2/pages/{id}").', ) .option( '-q, --query-params <json>', 'Query parameters as JSON string (e.g., \'{"limit": "25"}\').', ) .option( '--jq <expression>', 'JMESPath expression to filter/transform the response.', ) .option( '-o, --output-format <format>', 'Output format: "toon" (default, token-efficient) or "json".', 'toon', ) .action(async (options) => { const actionLogger = cliLogger.forMethod(name); try { actionLogger.debug(`CLI ${name} called`, options); // Parse query params if provided let queryParams: Record<string, string> | undefined; if (options.queryParams) { queryParams = parseJson<Record<string, string>>( options.queryParams, 'query-params', ); } const result = await handler({ path: options.path, queryParams, jq: options.jq, outputFormat: options.outputFormat as 'toon' | 'json', }); console.log(result.content); } catch (error) { handleCliError(error); } }); } /** * Register a write command (POST/PUT/PATCH - with body) * @param program - Commander program instance * @param name - Command name * @param description - Command description * @param handler - Controller handler function */ function registerWriteCommand( program: Command, name: string, description: string, handler: (options: { path: string; body: Record<string, unknown>; queryParams?: Record<string, string>; jq?: string; outputFormat?: 'toon' | 'json'; }) => Promise<{ content: string }>, ): void { program .command(name) .description(description) .requiredOption( '-p, --path <path>', 'API endpoint path (e.g., "/wiki/api/v2/pages", "/wiki/api/v2/pages/{id}/labels").', ) .requiredOption('-b, --body <json>', 'Request body as JSON string.') .option('-q, --query-params <json>', 'Query parameters as JSON string.') .option( '--jq <expression>', 'JMESPath expression to filter/transform the response.', ) .option( '-o, --output-format <format>', 'Output format: "toon" (default, token-efficient) or "json".', 'toon', ) .action(async (options) => { const actionLogger = cliLogger.forMethod(name); try { actionLogger.debug(`CLI ${name} called`, options); // Parse body const body = parseJson<Record<string, unknown>>( options.body, 'body', ); // Parse query params if provided let queryParams: Record<string, string> | undefined; if (options.queryParams) { queryParams = parseJson<Record<string, string>>( options.queryParams, 'query-params', ); } const result = await handler({ path: options.path, body, queryParams, jq: options.jq, outputFormat: options.outputFormat as 'toon' | 'json', }); console.log(result.content); } catch (error) { handleCliError(error); } }); } /** * Register generic Confluence API CLI commands with the Commander program * * @param program - The Commander program instance to register commands with */ function register(program: Command): void { const methodLogger = Logger.forContext( 'cli/atlassian.api.cli.ts', 'register', ); methodLogger.debug('Registering Confluence API CLI commands...'); // Register GET command registerReadCommand( program, 'get', 'GET any Confluence endpoint. Returns JSON, optionally filtered with JMESPath.', handleGet, ); // Register POST command registerWriteCommand( program, 'post', 'POST to any Confluence endpoint. Returns JSON, optionally filtered with JMESPath.', handlePost, ); // Register PUT command registerWriteCommand( program, 'put', 'PUT to any Confluence endpoint. Returns JSON, optionally filtered with JMESPath.', handlePut, ); // Register PATCH command registerWriteCommand( program, 'patch', 'PATCH any Confluence endpoint. Returns JSON, optionally filtered with JMESPath.', handlePatch, ); // Register DELETE command registerReadCommand( program, 'delete', 'DELETE any Confluence endpoint. Returns JSON (if any), optionally filtered with JMESPath.', handleDelete, ); methodLogger.debug('CLI commands registered successfully'); } export default { register };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/aashari/mcp-server-atlassian-confluence'

If you have feedback or need assistance with the MCP directory API, please join our Discord server