@aashari/mcp-server-atlassian-jira
Version:
Node.js/TypeScript MCP server for Atlassian Jira. Equips AI systems (LLMs) with tools to list/get projects, search/get issues (using JQL/ID), and view dev info (commits, PRs). Connects AI capabilities directly into Jira project management and issue tracki
135 lines (134 loc) • 6.36 kB
JavaScript
;
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_api_controller_js_1 = require("../controllers/atlassian.api.controller.js");
/**
* CLI module for generic Jira API access.
* Provides commands for making GET, POST, PUT, PATCH, and DELETE requests to any Jira API endpoint.
*/
// Create a contextualized logger for this file
const cliLogger = logger_util_js_1.Logger.forContext('cli/atlassian.api.cli.ts');
// Log CLI initialization
cliLogger.debug('Jira 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(jsonString, fieldName) {
let parsed;
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;
}
/**
* 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, name, description, handler) {
program
.command(name)
.description(description)
.requiredOption('-p, --path <path>', 'API endpoint path (e.g., "/rest/api/3/project", "/rest/api/3/issue/{issueKey}").')
.option('-q, --query-params <json>', 'Query parameters as JSON string (e.g., \'{"maxResults": "50"}\').')
.option('--jq <expression>', 'JMESPath expression to filter/transform the response.')
.option('--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;
if (options.queryParams) {
queryParams = parseJson(options.queryParams, 'query-params');
}
const result = await handler({
path: options.path,
queryParams,
jq: options.jq,
outputFormat: options.outputFormat,
});
console.log(result.content);
}
catch (error) {
(0, error_util_js_1.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, name, description, handler) {
program
.command(name)
.description(description)
.requiredOption('-p, --path <path>', 'API endpoint path (e.g., "/rest/api/3/issue", "/rest/api/3/issue/{issueKey}/comment").')
.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('--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(options.body, 'body');
// Parse query params if provided
let queryParams;
if (options.queryParams) {
queryParams = parseJson(options.queryParams, 'query-params');
}
const result = await handler({
path: options.path,
body,
queryParams,
jq: options.jq,
outputFormat: options.outputFormat,
});
console.log(result.content);
}
catch (error) {
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register generic Jira API CLI commands with the Commander program
*
* @param program - The Commander program instance to register commands with
*/
function register(program) {
const methodLogger = logger_util_js_1.Logger.forContext('cli/atlassian.api.cli.ts', 'register');
methodLogger.debug('Registering Jira API CLI commands...');
// Register GET command
registerReadCommand(program, 'get', 'GET any Jira endpoint. Returns TOON by default (or JSON with --output-format json), optionally filtered with JMESPath.', atlassian_api_controller_js_1.handleGet);
// Register POST command
registerWriteCommand(program, 'post', 'POST to any Jira endpoint. Returns TOON by default (or JSON with --output-format json), optionally filtered with JMESPath.', atlassian_api_controller_js_1.handlePost);
// Register PUT command
registerWriteCommand(program, 'put', 'PUT to any Jira endpoint. Returns TOON by default (or JSON with --output-format json), optionally filtered with JMESPath.', atlassian_api_controller_js_1.handlePut);
// Register PATCH command
registerWriteCommand(program, 'patch', 'PATCH any Jira endpoint. Returns TOON by default (or JSON with --output-format json), optionally filtered with JMESPath.', atlassian_api_controller_js_1.handlePatch);
// Register DELETE command
registerReadCommand(program, 'delete', 'DELETE any Jira endpoint. Returns TOON by default (or JSON with --output-format json, if any), optionally filtered with JMESPath.', atlassian_api_controller_js_1.handleDelete);
methodLogger.debug('CLI commands registered successfully');
}
exports.default = { register };