mcp-jira-stdio 1.9.0 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +480 -675
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
-
import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
5
4
|
import axios from 'axios';
|
|
6
5
|
import { z } from 'zod';
|
|
7
6
|
import FormData from 'form-data';
|
|
@@ -441,7 +440,7 @@ var require_package2 = __commonJS({
|
|
|
441
440
|
"package.json"(exports$1, module) {
|
|
442
441
|
module.exports = {
|
|
443
442
|
name: "mcp-jira-stdio",
|
|
444
|
-
version: "1.
|
|
443
|
+
version: "1.10.1",
|
|
445
444
|
description: "Model Context Protocol (MCP) server for Jira API integration",
|
|
446
445
|
author: "graslt",
|
|
447
446
|
license: "MIT",
|
|
@@ -490,7 +489,7 @@ var require_package2 = __commonJS({
|
|
|
490
489
|
node: ">=20.0.0"
|
|
491
490
|
},
|
|
492
491
|
dependencies: {
|
|
493
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
492
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
494
493
|
axios: "^1.7.0",
|
|
495
494
|
"form-data": "^4.0.5",
|
|
496
495
|
"md-to-adf": "^0.5.0",
|
|
@@ -579,7 +578,8 @@ var TOOL_NAMES = {
|
|
|
579
578
|
GET_ATTACHMENTS: "jira_get_attachments",
|
|
580
579
|
DELETE_ATTACHMENT: "jira_delete_attachment",
|
|
581
580
|
GET_TRANSITIONS: "jira_get_transitions",
|
|
582
|
-
TRANSITION_ISSUE: "jira_transition_issue"
|
|
581
|
+
TRANSITION_ISSUE: "jira_transition_issue",
|
|
582
|
+
GET_ISSUE_GRAPH: "jira_get_issue_graph"
|
|
583
583
|
};
|
|
584
584
|
|
|
585
585
|
// src/utils/logger.ts
|
|
@@ -1011,6 +1011,16 @@ var TransitionIssueInputSchema = z.object({
|
|
|
1011
1011
|
}).refine((data) => data.transitionId || data.transitionName, {
|
|
1012
1012
|
message: "Either transitionId or transitionName must be provided"
|
|
1013
1013
|
});
|
|
1014
|
+
var GetIssueGraphInputSchema = z.object({
|
|
1015
|
+
issueKey: z.string().min(1).describe("Seed issue key to start graph traversal from (e.g., PROJECT-123)").refine((v) => isValidIssueKey(v), "Invalid issue key format"),
|
|
1016
|
+
maxDepth: z.number().min(1).max(5).default(2).describe("Maximum BFS traversal depth from seed issue (default: 2, max: 5)"),
|
|
1017
|
+
maxNodes: z.number().min(1).max(200).default(50).describe("Maximum number of nodes to include in the graph (default: 50, max: 200)"),
|
|
1018
|
+
includeHierarchy: z.boolean().default(true).describe("Include parent/child/subtask edges (default: true)"),
|
|
1019
|
+
linkTypes: z.array(z.string()).optional().describe(
|
|
1020
|
+
'Filter to specific link types (e.g., ["Blocks", "Relates"]). If omitted, includes all link types.'
|
|
1021
|
+
),
|
|
1022
|
+
direction: z.enum(["all", "inward", "outward"]).default("all").describe('Which link directions to follow: "all", "inward", or "outward" (default: "all")')
|
|
1023
|
+
});
|
|
1014
1024
|
function ensureAdfDescription(desc, format = "markdown") {
|
|
1015
1025
|
if (!desc) return desc;
|
|
1016
1026
|
if (typeof desc === "object") return desc;
|
|
@@ -2209,27 +2219,7 @@ function handleError(error) {
|
|
|
2209
2219
|
// src/tools/get-visible-projects.ts
|
|
2210
2220
|
var log3 = createLogger("tool:get-visible-projects");
|
|
2211
2221
|
var getVisibleProjectsTool = {
|
|
2212
|
-
|
|
2213
|
-
description: "Retrieves all projects accessible to the authenticated user. Returns project keys, names, descriptions, and basic metadata.",
|
|
2214
|
-
inputSchema: {
|
|
2215
|
-
type: "object",
|
|
2216
|
-
properties: {
|
|
2217
|
-
expand: {
|
|
2218
|
-
type: "array",
|
|
2219
|
-
items: { type: "string" },
|
|
2220
|
-
description: 'Additional project details to include (e.g., ["description", "lead", "issueTypes"])',
|
|
2221
|
-
default: []
|
|
2222
|
-
},
|
|
2223
|
-
recent: {
|
|
2224
|
-
type: "number",
|
|
2225
|
-
description: "Limit results to recently accessed projects (max number)",
|
|
2226
|
-
minimum: 1,
|
|
2227
|
-
maximum: 100
|
|
2228
|
-
}
|
|
2229
|
-
},
|
|
2230
|
-
required: []
|
|
2231
|
-
}
|
|
2232
|
-
};
|
|
2222
|
+
description: "Retrieves all projects accessible to the authenticated user. Returns project keys, names, descriptions, and basic metadata."};
|
|
2233
2223
|
async function handleGetVisibleProjects(input) {
|
|
2234
2224
|
try {
|
|
2235
2225
|
const validated = validateInput(GetVisibleProjectsInputSchema, input);
|
|
@@ -2249,30 +2239,7 @@ async function handleGetVisibleProjects(input) {
|
|
|
2249
2239
|
// src/tools/get-issue.ts
|
|
2250
2240
|
var log4 = createLogger("tool:get-issue");
|
|
2251
2241
|
var getIssueTool = {
|
|
2252
|
-
|
|
2253
|
-
description: 'Retrieve details for a specific Jira issue by key or URL. Use this when the user mentions an issue like "PAYWALL-943" or pastes a Jira link (e.g., https://your.atlassian.net/browse/PAYWALL-943). Returns status, assignee, priority, project, type, labels, components, timestamps, and description.',
|
|
2254
|
-
inputSchema: {
|
|
2255
|
-
type: "object",
|
|
2256
|
-
properties: {
|
|
2257
|
-
issueKey: {
|
|
2258
|
-
type: "string",
|
|
2259
|
-
description: "Issue key or full Jira URL (e.g., PROJECT-123 or https://your.atlassian.net/browse/PROJECT-123)"
|
|
2260
|
-
},
|
|
2261
|
-
expand: {
|
|
2262
|
-
type: "array",
|
|
2263
|
-
items: { type: "string" },
|
|
2264
|
-
description: 'Additional issue details to include (e.g., ["comments", "attachments", "changelog"])',
|
|
2265
|
-
default: []
|
|
2266
|
-
},
|
|
2267
|
-
fields: {
|
|
2268
|
-
type: "array",
|
|
2269
|
-
items: { type: "string" },
|
|
2270
|
-
description: 'Specific fields to retrieve (e.g., ["summary", "status", "assignee"])'
|
|
2271
|
-
}
|
|
2272
|
-
},
|
|
2273
|
-
required: ["issueKey"]
|
|
2274
|
-
}
|
|
2275
|
-
};
|
|
2242
|
+
description: 'Retrieve details for a specific Jira issue by key or URL. Use this when the user mentions an issue like "PAYWALL-943" or pastes a Jira link (e.g., https://your.atlassian.net/browse/PAYWALL-943). Returns status, assignee, priority, project, type, labels, components, timestamps, and description.'};
|
|
2276
2243
|
async function handleGetIssue(input) {
|
|
2277
2244
|
try {
|
|
2278
2245
|
const validated = validateInput(GetIssueInputSchema, input);
|
|
@@ -2294,41 +2261,7 @@ async function handleGetIssue(input) {
|
|
|
2294
2261
|
// src/tools/search-issues.ts
|
|
2295
2262
|
var log5 = createLogger("tool:search-issues");
|
|
2296
2263
|
var searchIssuesTool = {
|
|
2297
|
-
|
|
2298
|
-
description: 'Search for Jira issues using JQL. Supports complex queries with pagination and field selection. Examples: "project = PROJECT AND status = Open", "assignee = currentUser()". For pagination, use nextPageToken from previous response.',
|
|
2299
|
-
inputSchema: {
|
|
2300
|
-
type: "object",
|
|
2301
|
-
properties: {
|
|
2302
|
-
jql: {
|
|
2303
|
-
type: "string",
|
|
2304
|
-
description: 'JQL query string (e.g., "project = PROJECT AND status = Open")'
|
|
2305
|
-
},
|
|
2306
|
-
nextPageToken: {
|
|
2307
|
-
type: "string",
|
|
2308
|
-
description: "Token for pagination. Omit for first page, use value from previous response for next page."
|
|
2309
|
-
},
|
|
2310
|
-
maxResults: {
|
|
2311
|
-
type: "number",
|
|
2312
|
-
description: "Maximum number of results to return per page",
|
|
2313
|
-
minimum: 1,
|
|
2314
|
-
maximum: 100,
|
|
2315
|
-
default: 50
|
|
2316
|
-
},
|
|
2317
|
-
fields: {
|
|
2318
|
-
type: "array",
|
|
2319
|
-
items: { type: "string" },
|
|
2320
|
-
description: "Specific fields to retrieve for each issue"
|
|
2321
|
-
},
|
|
2322
|
-
expand: {
|
|
2323
|
-
type: "array",
|
|
2324
|
-
items: { type: "string" },
|
|
2325
|
-
description: "Additional details to include for each issue",
|
|
2326
|
-
default: []
|
|
2327
|
-
}
|
|
2328
|
-
},
|
|
2329
|
-
required: ["jql"]
|
|
2330
|
-
}
|
|
2331
|
-
};
|
|
2264
|
+
description: 'Search for Jira issues using JQL. Supports complex queries with pagination and field selection. Examples: "project = PROJECT AND status = Open", "assignee = currentUser()". For pagination, use nextPageToken from previous response.'};
|
|
2332
2265
|
async function handleSearchIssues(input) {
|
|
2333
2266
|
try {
|
|
2334
2267
|
const validated = validateInput(SearchIssuesInputSchema, input);
|
|
@@ -2352,37 +2285,7 @@ async function handleSearchIssues(input) {
|
|
|
2352
2285
|
// src/tools/get-my-issues.ts
|
|
2353
2286
|
var log6 = createLogger("tool:get-my-issues");
|
|
2354
2287
|
var getMyIssuesTool = {
|
|
2355
|
-
|
|
2356
|
-
description: "Retrieves issues assigned to current user, sorted by most recently updated first. Supports pagination and field selection. For pagination, use nextPageToken from previous response.",
|
|
2357
|
-
inputSchema: {
|
|
2358
|
-
type: "object",
|
|
2359
|
-
properties: {
|
|
2360
|
-
nextPageToken: {
|
|
2361
|
-
type: "string",
|
|
2362
|
-
description: "Token for pagination. Omit for first page, use value from previous response for next page."
|
|
2363
|
-
},
|
|
2364
|
-
maxResults: {
|
|
2365
|
-
type: "number",
|
|
2366
|
-
description: "Maximum number of results to return per page",
|
|
2367
|
-
minimum: 1,
|
|
2368
|
-
maximum: 100,
|
|
2369
|
-
default: 50
|
|
2370
|
-
},
|
|
2371
|
-
fields: {
|
|
2372
|
-
type: "array",
|
|
2373
|
-
items: { type: "string" },
|
|
2374
|
-
description: "Specific fields to retrieve for each issue"
|
|
2375
|
-
},
|
|
2376
|
-
expand: {
|
|
2377
|
-
type: "array",
|
|
2378
|
-
items: { type: "string" },
|
|
2379
|
-
description: "Additional details to include for each issue",
|
|
2380
|
-
default: []
|
|
2381
|
-
}
|
|
2382
|
-
},
|
|
2383
|
-
required: []
|
|
2384
|
-
}
|
|
2385
|
-
};
|
|
2288
|
+
description: "Retrieves issues assigned to current user, sorted by most recently updated first. Supports pagination and field selection. For pagination, use nextPageToken from previous response."};
|
|
2386
2289
|
async function handleGetMyIssues(input) {
|
|
2387
2290
|
try {
|
|
2388
2291
|
const validated = validateInput(GetMyIssuesInputSchema, input);
|
|
@@ -2406,19 +2309,7 @@ async function handleGetMyIssues(input) {
|
|
|
2406
2309
|
// src/tools/get-issue-types.ts
|
|
2407
2310
|
var log7 = createLogger("tool:get-issue-types");
|
|
2408
2311
|
var getIssueTypesTool = {
|
|
2409
|
-
|
|
2410
|
-
description: "Retrieves available issue types. Can get global issue types or project-specific issue types including regular issues and subtasks (Bug, Story, Task, Epic, etc.).",
|
|
2411
|
-
inputSchema: {
|
|
2412
|
-
type: "object",
|
|
2413
|
-
properties: {
|
|
2414
|
-
projectKey: {
|
|
2415
|
-
type: "string",
|
|
2416
|
-
description: "Project key to get issue types for specific project (optional - if not provided, returns global issue types)"
|
|
2417
|
-
}
|
|
2418
|
-
},
|
|
2419
|
-
required: []
|
|
2420
|
-
}
|
|
2421
|
-
};
|
|
2312
|
+
description: "Retrieves available issue types. Can get global issue types or project-specific issue types including regular issues and subtasks (Bug, Story, Task, Epic, etc.)."};
|
|
2422
2313
|
async function handleGetIssueTypes(input) {
|
|
2423
2314
|
try {
|
|
2424
2315
|
const validated = validateInput(GetIssueTypesInputSchema, input);
|
|
@@ -2439,40 +2330,7 @@ async function handleGetIssueTypes(input) {
|
|
|
2439
2330
|
// src/tools/get-users.ts
|
|
2440
2331
|
var log8 = createLogger("tool:get-users");
|
|
2441
2332
|
var getUsersTool = {
|
|
2442
|
-
|
|
2443
|
-
description: "Search for users by name, email, username, or account ID. Returns display name, email, account status, and account type. Supports pagination.",
|
|
2444
|
-
inputSchema: {
|
|
2445
|
-
type: "object",
|
|
2446
|
-
properties: {
|
|
2447
|
-
query: {
|
|
2448
|
-
type: "string",
|
|
2449
|
-
description: "Search query for user name or email (partial matches supported)"
|
|
2450
|
-
},
|
|
2451
|
-
username: {
|
|
2452
|
-
type: "string",
|
|
2453
|
-
description: "Specific username to search for"
|
|
2454
|
-
},
|
|
2455
|
-
accountId: {
|
|
2456
|
-
type: "string",
|
|
2457
|
-
description: "Specific account ID to search for"
|
|
2458
|
-
},
|
|
2459
|
-
startAt: {
|
|
2460
|
-
type: "number",
|
|
2461
|
-
description: "Index of first result to return (for pagination)",
|
|
2462
|
-
minimum: 0,
|
|
2463
|
-
default: 0
|
|
2464
|
-
},
|
|
2465
|
-
maxResults: {
|
|
2466
|
-
type: "number",
|
|
2467
|
-
description: "Maximum number of results to return",
|
|
2468
|
-
minimum: 1,
|
|
2469
|
-
maximum: 50,
|
|
2470
|
-
default: 50
|
|
2471
|
-
}
|
|
2472
|
-
},
|
|
2473
|
-
required: []
|
|
2474
|
-
}
|
|
2475
|
-
};
|
|
2333
|
+
description: "Search for users by name, email, username, or account ID. Returns display name, email, account status, and account type. Supports pagination."};
|
|
2476
2334
|
async function handleGetUsers(input) {
|
|
2477
2335
|
try {
|
|
2478
2336
|
const validated = validateInput(GetUsersInputSchema, input);
|
|
@@ -2503,14 +2361,7 @@ async function handleGetUsers(input) {
|
|
|
2503
2361
|
// src/tools/get-priorities.ts
|
|
2504
2362
|
var log9 = createLogger("tool:get-priorities");
|
|
2505
2363
|
var getPrioritiesTool = {
|
|
2506
|
-
|
|
2507
|
-
description: "Retrieves available priorities (e.g., Highest, High, Medium, Low, Lowest). Returns IDs, names, and descriptions.",
|
|
2508
|
-
inputSchema: {
|
|
2509
|
-
type: "object",
|
|
2510
|
-
properties: {},
|
|
2511
|
-
required: []
|
|
2512
|
-
}
|
|
2513
|
-
};
|
|
2364
|
+
description: "Retrieves available priorities (e.g., Highest, High, Medium, Low, Lowest). Returns IDs, names, and descriptions."};
|
|
2514
2365
|
async function handleGetPriorities(input) {
|
|
2515
2366
|
try {
|
|
2516
2367
|
validateInput(GetPrioritiesInputSchema, input);
|
|
@@ -2527,23 +2378,7 @@ async function handleGetPriorities(input) {
|
|
|
2527
2378
|
// src/tools/get-statuses.ts
|
|
2528
2379
|
var log10 = createLogger("tool:get-statuses");
|
|
2529
2380
|
var getStatusesTool = {
|
|
2530
|
-
|
|
2531
|
-
description: "Retrieves available statuses (global or project-specific, e.g., To Do, In Progress, Done). Returns status categories and workflow information.",
|
|
2532
|
-
inputSchema: {
|
|
2533
|
-
type: "object",
|
|
2534
|
-
properties: {
|
|
2535
|
-
projectKey: {
|
|
2536
|
-
type: "string",
|
|
2537
|
-
description: "Project key to get statuses for specific project (optional)"
|
|
2538
|
-
},
|
|
2539
|
-
issueTypeId: {
|
|
2540
|
-
type: "string",
|
|
2541
|
-
description: "Issue type ID to get statuses for specific issue type (requires projectKey)"
|
|
2542
|
-
}
|
|
2543
|
-
},
|
|
2544
|
-
required: []
|
|
2545
|
-
}
|
|
2546
|
-
};
|
|
2381
|
+
description: "Retrieves available statuses (global or project-specific, e.g., To Do, In Progress, Done). Returns status categories and workflow information."};
|
|
2547
2382
|
async function handleGetStatuses(input) {
|
|
2548
2383
|
try {
|
|
2549
2384
|
const validated = validateInput(GetStatusesInputSchema, input);
|
|
@@ -2571,68 +2406,7 @@ async function handleGetStatuses(input) {
|
|
|
2571
2406
|
// src/tools/create-issue.ts
|
|
2572
2407
|
var log11 = createLogger("tool:create-issue");
|
|
2573
2408
|
var createIssueTool = {
|
|
2574
|
-
|
|
2575
|
-
description: 'Creates a new Jira issue in the specified project. Supports setting issue type, priority, assignee, labels, components, and custom fields. Description format is controlled by the "format" parameter (default: markdown). For required custom fields, supply them via customFields (e.g., { "customfield_12345": { id: "..." } }). Returns the created issue with all details.',
|
|
2576
|
-
inputSchema: {
|
|
2577
|
-
type: "object",
|
|
2578
|
-
properties: {
|
|
2579
|
-
projectKey: {
|
|
2580
|
-
type: "string",
|
|
2581
|
-
description: "Project key where the issue will be created"
|
|
2582
|
-
},
|
|
2583
|
-
summary: {
|
|
2584
|
-
type: "string",
|
|
2585
|
-
description: "Issue summary/title",
|
|
2586
|
-
minLength: 1
|
|
2587
|
-
},
|
|
2588
|
-
description: {
|
|
2589
|
-
anyOf: [{ type: "string" }, { type: "object" }],
|
|
2590
|
-
description: 'Detailed issue description (optional). Format depends on the "format" parameter.'
|
|
2591
|
-
},
|
|
2592
|
-
issueType: {
|
|
2593
|
-
type: "string",
|
|
2594
|
-
description: "Issue type name (e.g., Bug, Story, Task, Epic)"
|
|
2595
|
-
},
|
|
2596
|
-
priority: {
|
|
2597
|
-
type: "string",
|
|
2598
|
-
description: "Issue priority name (e.g., High, Medium, Low) - optional"
|
|
2599
|
-
},
|
|
2600
|
-
assignee: {
|
|
2601
|
-
type: "string",
|
|
2602
|
-
description: "Assignee account ID (optional)"
|
|
2603
|
-
},
|
|
2604
|
-
labels: {
|
|
2605
|
-
type: "array",
|
|
2606
|
-
items: { type: "string" },
|
|
2607
|
-
description: "Issue labels (optional)",
|
|
2608
|
-
default: []
|
|
2609
|
-
},
|
|
2610
|
-
components: {
|
|
2611
|
-
type: "array",
|
|
2612
|
-
items: { type: "string" },
|
|
2613
|
-
description: "Component names (optional)",
|
|
2614
|
-
default: []
|
|
2615
|
-
},
|
|
2616
|
-
customFields: {
|
|
2617
|
-
type: "object",
|
|
2618
|
-
additionalProperties: true,
|
|
2619
|
-
description: 'Additional Jira fields, e.g. { "customfield_10071": value }. Use this to set required custom fields.'
|
|
2620
|
-
},
|
|
2621
|
-
returnIssue: {
|
|
2622
|
-
type: "boolean",
|
|
2623
|
-
description: "If false, returns only the issue key without fetching full details",
|
|
2624
|
-
default: true
|
|
2625
|
-
},
|
|
2626
|
-
format: {
|
|
2627
|
-
type: "string",
|
|
2628
|
-
enum: ["markdown", "adf", "plain"],
|
|
2629
|
-
description: 'Description format: "markdown" (converts Markdown to ADF, default), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting)',
|
|
2630
|
-
default: "markdown"
|
|
2631
|
-
}
|
|
2632
|
-
},
|
|
2633
|
-
required: ["projectKey", "summary", "issueType"]
|
|
2634
|
-
}
|
|
2635
|
-
};
|
|
2409
|
+
description: 'Creates a new Jira issue in the specified project. Supports setting issue type, priority, assignee, labels, components, and custom fields. Description format is controlled by the "format" parameter (default: markdown). For required custom fields, supply them via customFields (e.g., { "customfield_12345": { id: "..." } }). Returns the created issue with all details.'};
|
|
2636
2410
|
async function handleCreateIssue(input) {
|
|
2637
2411
|
try {
|
|
2638
2412
|
const validated = validateInput(CreateIssueInputSchema, input);
|
|
@@ -2672,60 +2446,7 @@ async function handleCreateIssue(input) {
|
|
|
2672
2446
|
// src/tools/update-issue.ts
|
|
2673
2447
|
var log12 = createLogger("tool:update-issue");
|
|
2674
2448
|
var updateIssueTool = {
|
|
2675
|
-
|
|
2676
|
-
description: 'Updates an existing Jira issue by its key. Supports updating summary, description, priority, assignee, labels, and components. Description format is controlled by the "format" parameter (default: markdown). Only specified fields will be updated.',
|
|
2677
|
-
inputSchema: {
|
|
2678
|
-
type: "object",
|
|
2679
|
-
properties: {
|
|
2680
|
-
issueKey: {
|
|
2681
|
-
type: "string",
|
|
2682
|
-
description: "Issue key to update (e.g., PROJECT-123)"
|
|
2683
|
-
},
|
|
2684
|
-
summary: {
|
|
2685
|
-
type: "string",
|
|
2686
|
-
description: "New issue summary/title (optional)"
|
|
2687
|
-
},
|
|
2688
|
-
description: {
|
|
2689
|
-
anyOf: [{ type: "string" }, { type: "object" }],
|
|
2690
|
-
description: 'New issue description (optional). Format depends on the "format" parameter.'
|
|
2691
|
-
},
|
|
2692
|
-
priority: {
|
|
2693
|
-
type: "string",
|
|
2694
|
-
description: "New priority name (e.g., High, Medium, Low) - optional"
|
|
2695
|
-
},
|
|
2696
|
-
assignee: {
|
|
2697
|
-
type: "string",
|
|
2698
|
-
description: "New assignee account ID (optional, use null string to unassign)"
|
|
2699
|
-
},
|
|
2700
|
-
labels: {
|
|
2701
|
-
type: "array",
|
|
2702
|
-
items: { type: "string" },
|
|
2703
|
-
description: "New labels array (replaces existing labels) - optional"
|
|
2704
|
-
},
|
|
2705
|
-
components: {
|
|
2706
|
-
type: "array",
|
|
2707
|
-
items: { type: "string" },
|
|
2708
|
-
description: "New components array (replaces existing components) - optional"
|
|
2709
|
-
},
|
|
2710
|
-
parent: {
|
|
2711
|
-
type: "string",
|
|
2712
|
-
description: "New parent issue key (e.g., PROJECT-100). Set to empty string to remove the parent."
|
|
2713
|
-
},
|
|
2714
|
-
returnIssue: {
|
|
2715
|
-
type: "boolean",
|
|
2716
|
-
description: "If false, returns a success message without fetching the updated issue",
|
|
2717
|
-
default: true
|
|
2718
|
-
},
|
|
2719
|
-
format: {
|
|
2720
|
-
type: "string",
|
|
2721
|
-
enum: ["markdown", "adf", "plain"],
|
|
2722
|
-
description: 'Description format: "markdown" (converts Markdown to ADF, default), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting)',
|
|
2723
|
-
default: "markdown"
|
|
2724
|
-
}
|
|
2725
|
-
},
|
|
2726
|
-
required: ["issueKey"]
|
|
2727
|
-
}
|
|
2728
|
-
};
|
|
2449
|
+
description: 'Updates an existing Jira issue by its key. Supports updating summary, description, priority, assignee, labels, and components. Description format is controlled by the "format" parameter (default: markdown). Only specified fields will be updated.'};
|
|
2729
2450
|
async function handleUpdateIssue(input) {
|
|
2730
2451
|
try {
|
|
2731
2452
|
const validated = validateInput(UpdateIssueInputSchema, input);
|
|
@@ -2756,46 +2477,7 @@ async function handleUpdateIssue(input) {
|
|
|
2756
2477
|
// src/tools/add-comment.ts
|
|
2757
2478
|
var log13 = createLogger("tool:add-comment");
|
|
2758
2479
|
var addCommentTool = {
|
|
2759
|
-
|
|
2760
|
-
description: 'Adds a comment to an issue. Supports visibility restrictions for groups or roles. Comment format is controlled by the "format" parameter (default: markdown). Returns the created comment with author details and timestamp.',
|
|
2761
|
-
inputSchema: {
|
|
2762
|
-
type: "object",
|
|
2763
|
-
properties: {
|
|
2764
|
-
issueKey: {
|
|
2765
|
-
type: "string",
|
|
2766
|
-
description: "Issue key to add comment to (e.g., PROJECT-123)"
|
|
2767
|
-
},
|
|
2768
|
-
body: {
|
|
2769
|
-
type: "string",
|
|
2770
|
-
description: 'Comment body text. Format depends on the "format" parameter.',
|
|
2771
|
-
minLength: 1
|
|
2772
|
-
},
|
|
2773
|
-
visibility: {
|
|
2774
|
-
type: "object",
|
|
2775
|
-
description: "Comment visibility restrictions (optional)",
|
|
2776
|
-
properties: {
|
|
2777
|
-
type: {
|
|
2778
|
-
type: "string",
|
|
2779
|
-
enum: ["group", "role"],
|
|
2780
|
-
description: 'Visibility type - either "group" or "role"'
|
|
2781
|
-
},
|
|
2782
|
-
value: {
|
|
2783
|
-
type: "string",
|
|
2784
|
-
description: "Group name or role name for visibility restriction"
|
|
2785
|
-
}
|
|
2786
|
-
},
|
|
2787
|
-
required: ["type", "value"]
|
|
2788
|
-
},
|
|
2789
|
-
format: {
|
|
2790
|
-
type: "string",
|
|
2791
|
-
enum: ["markdown", "adf", "plain"],
|
|
2792
|
-
description: 'Comment format: "markdown" (converts Markdown to ADF, default), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting)',
|
|
2793
|
-
default: "markdown"
|
|
2794
|
-
}
|
|
2795
|
-
},
|
|
2796
|
-
required: ["issueKey", "body"]
|
|
2797
|
-
}
|
|
2798
|
-
};
|
|
2480
|
+
description: 'Adds a comment to an issue. Supports visibility restrictions for groups or roles. Comment format is controlled by the "format" parameter (default: markdown). Returns the created comment with author details and timestamp.'};
|
|
2799
2481
|
async function handleAddComment(input) {
|
|
2800
2482
|
try {
|
|
2801
2483
|
const validated = validateInput(AddCommentInputSchema, input);
|
|
@@ -2817,25 +2499,7 @@ async function handleAddComment(input) {
|
|
|
2817
2499
|
// src/tools/get-project-info.ts
|
|
2818
2500
|
var log14 = createLogger("tool:get-project-info");
|
|
2819
2501
|
var getProjectInfoTool = {
|
|
2820
|
-
|
|
2821
|
-
description: "Retrieves detailed information about a project (components, versions, issue types, roles, insights). More comprehensive than the basic project list.",
|
|
2822
|
-
inputSchema: {
|
|
2823
|
-
type: "object",
|
|
2824
|
-
properties: {
|
|
2825
|
-
projectKey: {
|
|
2826
|
-
type: "string",
|
|
2827
|
-
description: "Project key to get detailed information for"
|
|
2828
|
-
},
|
|
2829
|
-
expand: {
|
|
2830
|
-
type: "array",
|
|
2831
|
-
items: { type: "string" },
|
|
2832
|
-
description: 'Additional project details to include (e.g., ["description", "lead", "issueTypes", "versions"])',
|
|
2833
|
-
default: []
|
|
2834
|
-
}
|
|
2835
|
-
},
|
|
2836
|
-
required: ["projectKey"]
|
|
2837
|
-
}
|
|
2838
|
-
};
|
|
2502
|
+
description: "Retrieves detailed information about a project (components, versions, issue types, roles, insights). More comprehensive than the basic project list."};
|
|
2839
2503
|
async function handleGetProjectInfo(input) {
|
|
2840
2504
|
try {
|
|
2841
2505
|
const validated = validateInput(GetProjectInfoInputSchema, input);
|
|
@@ -2852,54 +2516,7 @@ async function handleGetProjectInfo(input) {
|
|
|
2852
2516
|
// src/tools/create-subtask.ts
|
|
2853
2517
|
var log15 = createLogger("tool:create-subtask");
|
|
2854
2518
|
var createSubtaskTool = {
|
|
2855
|
-
|
|
2856
|
-
description: 'Creates a subtask under an existing parent issue. Automatically determines the correct project and subtask issue type. Supports setting priority, assignee, labels, and components. Description format is controlled by the "format" parameter (default: markdown).',
|
|
2857
|
-
inputSchema: {
|
|
2858
|
-
type: "object",
|
|
2859
|
-
properties: {
|
|
2860
|
-
parentIssueKey: {
|
|
2861
|
-
type: "string",
|
|
2862
|
-
description: "Parent issue key (e.g., PROJECT-123)"
|
|
2863
|
-
},
|
|
2864
|
-
summary: {
|
|
2865
|
-
type: "string",
|
|
2866
|
-
description: "Subtask summary/title",
|
|
2867
|
-
minLength: 1
|
|
2868
|
-
},
|
|
2869
|
-
description: {
|
|
2870
|
-
type: "string",
|
|
2871
|
-
description: 'Detailed subtask description (optional). Format depends on the "format" parameter.'
|
|
2872
|
-
},
|
|
2873
|
-
priority: {
|
|
2874
|
-
type: "string",
|
|
2875
|
-
description: "Subtask priority name (e.g., High, Medium, Low) - optional"
|
|
2876
|
-
},
|
|
2877
|
-
assignee: {
|
|
2878
|
-
type: "string",
|
|
2879
|
-
description: "Assignee account ID (optional)"
|
|
2880
|
-
},
|
|
2881
|
-
labels: {
|
|
2882
|
-
type: "array",
|
|
2883
|
-
items: { type: "string" },
|
|
2884
|
-
description: "Subtask labels (optional)",
|
|
2885
|
-
default: []
|
|
2886
|
-
},
|
|
2887
|
-
components: {
|
|
2888
|
-
type: "array",
|
|
2889
|
-
items: { type: "string" },
|
|
2890
|
-
description: "Component names (optional)",
|
|
2891
|
-
default: []
|
|
2892
|
-
},
|
|
2893
|
-
format: {
|
|
2894
|
-
type: "string",
|
|
2895
|
-
enum: ["markdown", "adf", "plain"],
|
|
2896
|
-
description: 'Description format: "markdown" (converts Markdown to ADF, default), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting)',
|
|
2897
|
-
default: "markdown"
|
|
2898
|
-
}
|
|
2899
|
-
},
|
|
2900
|
-
required: ["parentIssueKey", "summary"]
|
|
2901
|
-
}
|
|
2902
|
-
};
|
|
2519
|
+
description: 'Creates a subtask under an existing parent issue. Automatically determines the correct project and subtask issue type. Supports setting priority, assignee, labels, and components. Description format is controlled by the "format" parameter (default: markdown).'};
|
|
2903
2520
|
async function handleCreateSubtask(input) {
|
|
2904
2521
|
try {
|
|
2905
2522
|
const validated = validateInput(CreateSubtaskInputSchema, input);
|
|
@@ -2925,23 +2542,7 @@ async function handleCreateSubtask(input) {
|
|
|
2925
2542
|
// src/tools/get-create-meta.ts
|
|
2926
2543
|
var log16 = createLogger("tool:get-create-meta");
|
|
2927
2544
|
var getCreateMetaTool = {
|
|
2928
|
-
|
|
2929
|
-
description: "Retrieves create metadata for a project, showing all available fields (including custom fields) for creating issues. Shows required vs optional fields, field types, and allowed values. Use this before creating issues to discover what fields are needed.",
|
|
2930
|
-
inputSchema: {
|
|
2931
|
-
type: "object",
|
|
2932
|
-
properties: {
|
|
2933
|
-
projectKey: {
|
|
2934
|
-
type: "string",
|
|
2935
|
-
description: "Project key to get create metadata for (e.g., PROJECT)"
|
|
2936
|
-
},
|
|
2937
|
-
issueTypeName: {
|
|
2938
|
-
type: "string",
|
|
2939
|
-
description: "Specific issue type name to get metadata for (optional)"
|
|
2940
|
-
}
|
|
2941
|
-
},
|
|
2942
|
-
required: ["projectKey"]
|
|
2943
|
-
}
|
|
2944
|
-
};
|
|
2545
|
+
description: "Retrieves create metadata for a project, showing all available fields (including custom fields) for creating issues. Shows required vs optional fields, field types, and allowed values. Use this before creating issues to discover what fields are needed."};
|
|
2945
2546
|
async function handleGetCreateMeta(input) {
|
|
2946
2547
|
try {
|
|
2947
2548
|
const validated = validateInput(GetCreateMetaInputSchema, input);
|
|
@@ -2965,19 +2566,7 @@ async function handleGetCreateMeta(input) {
|
|
|
2965
2566
|
// src/tools/get-custom-fields.ts
|
|
2966
2567
|
var log17 = createLogger("tool:get-custom-fields");
|
|
2967
2568
|
var getCustomFieldsTool = {
|
|
2968
|
-
|
|
2969
|
-
description: "Retrieves all custom fields available in Jira. Shows custom field names, IDs (e.g., customfield_10071), and types. Useful for discovering what custom fields exist and their identifiers.",
|
|
2970
|
-
inputSchema: {
|
|
2971
|
-
type: "object",
|
|
2972
|
-
properties: {
|
|
2973
|
-
projectKey: {
|
|
2974
|
-
type: "string",
|
|
2975
|
-
description: "Project key to filter custom fields (optional)"
|
|
2976
|
-
}
|
|
2977
|
-
},
|
|
2978
|
-
required: []
|
|
2979
|
-
}
|
|
2980
|
-
};
|
|
2569
|
+
description: "Retrieves all custom fields available in Jira. Shows custom field names, IDs (e.g., customfield_10071), and types. Useful for discovering what custom fields exist and their identifiers."};
|
|
2981
2570
|
async function handleGetCustomFields(input) {
|
|
2982
2571
|
try {
|
|
2983
2572
|
const validated = validateInput(GetCustomFieldsInputSchema, input);
|
|
@@ -2995,27 +2584,7 @@ async function handleGetCustomFields(input) {
|
|
|
2995
2584
|
// src/tools/create-issue-link.ts
|
|
2996
2585
|
var log18 = createLogger("tool:create-issue-link");
|
|
2997
2586
|
var createIssueLinkTool = {
|
|
2998
|
-
|
|
2999
|
-
description: 'Creates a link between two Jira issues. Supports common link types like "blocks", "relates", "duplicates", and "clones". Use this to establish relationships between issues.',
|
|
3000
|
-
inputSchema: {
|
|
3001
|
-
type: "object",
|
|
3002
|
-
properties: {
|
|
3003
|
-
fromIssue: {
|
|
3004
|
-
type: "string",
|
|
3005
|
-
description: "Source issue key (e.g., PROJECT-123)"
|
|
3006
|
-
},
|
|
3007
|
-
toIssue: {
|
|
3008
|
-
type: "string",
|
|
3009
|
-
description: "Target issue key (e.g., PROJECT-456)"
|
|
3010
|
-
},
|
|
3011
|
-
linkType: {
|
|
3012
|
-
type: "string",
|
|
3013
|
-
description: 'Link type: "blocks" (fromIssue blocks toIssue), "is blocked by", "relates", "duplicates", "clones", or custom link type name'
|
|
3014
|
-
}
|
|
3015
|
-
},
|
|
3016
|
-
required: ["fromIssue", "toIssue", "linkType"]
|
|
3017
|
-
}
|
|
3018
|
-
};
|
|
2587
|
+
description: 'Creates a link between two Jira issues. Supports common link types like "blocks", "relates", "duplicates", and "clones". Use this to establish relationships between issues.'};
|
|
3019
2588
|
async function handleCreateIssueLink(input) {
|
|
3020
2589
|
try {
|
|
3021
2590
|
const validated = validateInput(CreateIssueLinkInputSchema, input);
|
|
@@ -3036,35 +2605,7 @@ async function handleCreateIssueLink(input) {
|
|
|
3036
2605
|
// src/tools/get-comments.ts
|
|
3037
2606
|
var log19 = createLogger("tool:get-comments");
|
|
3038
2607
|
var getCommentsTool = {
|
|
3039
|
-
|
|
3040
|
-
description: "Retrieves all comments for a Jira issue. Returns comment author, content, timestamps, and visibility settings. Supports pagination for issues with many comments.",
|
|
3041
|
-
inputSchema: {
|
|
3042
|
-
type: "object",
|
|
3043
|
-
properties: {
|
|
3044
|
-
issueKey: {
|
|
3045
|
-
type: "string",
|
|
3046
|
-
description: "Issue key to get comments for (e.g., PROJECT-123)"
|
|
3047
|
-
},
|
|
3048
|
-
maxResults: {
|
|
3049
|
-
type: "number",
|
|
3050
|
-
description: "Maximum number of comments to return (default: 50, max: 100)",
|
|
3051
|
-
minimum: 1,
|
|
3052
|
-
maximum: 100
|
|
3053
|
-
},
|
|
3054
|
-
orderBy: {
|
|
3055
|
-
type: "string",
|
|
3056
|
-
enum: ["created", "-created", "+created"],
|
|
3057
|
-
description: 'Sort order for comments: "created" or "+created" (oldest first), "-created" (newest first)'
|
|
3058
|
-
},
|
|
3059
|
-
startAt: {
|
|
3060
|
-
type: "number",
|
|
3061
|
-
description: "Index of first comment to return (for pagination, default: 0)",
|
|
3062
|
-
minimum: 0
|
|
3063
|
-
}
|
|
3064
|
-
},
|
|
3065
|
-
required: ["issueKey"]
|
|
3066
|
-
}
|
|
3067
|
-
};
|
|
2608
|
+
description: "Retrieves all comments for a Jira issue. Returns comment author, content, timestamps, and visibility settings. Supports pagination for issues with many comments."};
|
|
3068
2609
|
async function handleGetComments(input) {
|
|
3069
2610
|
try {
|
|
3070
2611
|
const validated = validateInput(GetCommentsInputSchema, input);
|
|
@@ -3091,7 +2632,6 @@ async function handleGetComments(input) {
|
|
|
3091
2632
|
// src/tools/add-attachment.ts
|
|
3092
2633
|
var log20 = createLogger("tool:add-attachment");
|
|
3093
2634
|
var addAttachmentTool = {
|
|
3094
|
-
name: TOOL_NAMES.ADD_ATTACHMENT,
|
|
3095
2635
|
description: `Uploads an attachment (image, document, etc.) to a Jira issue.
|
|
3096
2636
|
|
|
3097
2637
|
**EFFICIENT METHOD (recommended for large files):**
|
|
@@ -3102,37 +2642,7 @@ var addAttachmentTool = {
|
|
|
3102
2642
|
- content: Base64 encoded content - WARNING: HIGH token cost (~330,000 tokens for 1MB file)
|
|
3103
2643
|
Only suitable for small files (< 500 KB)
|
|
3104
2644
|
|
|
3105
|
-
Returns attachment metadata including ID and download URL. To reference the image in a comment or description, use wiki markup: !filename.png! or !filename.png|thumbnail
|
|
3106
|
-
inputSchema: {
|
|
3107
|
-
type: "object",
|
|
3108
|
-
properties: {
|
|
3109
|
-
issueKey: {
|
|
3110
|
-
type: "string",
|
|
3111
|
-
description: "Issue key to add attachment to (e.g., PROJECT-123)"
|
|
3112
|
-
},
|
|
3113
|
-
filename: {
|
|
3114
|
-
type: "string",
|
|
3115
|
-
description: "Name of the file to attach (e.g., screenshot.png, document.pdf)",
|
|
3116
|
-
minLength: 1
|
|
3117
|
-
},
|
|
3118
|
-
fileUrl: {
|
|
3119
|
-
type: "string",
|
|
3120
|
-
description: "URL to download file from (efficient for remote files, ~60 tokens). Upload large files to Dropbox/S3/imgur first, then use URL.",
|
|
3121
|
-
format: "uri"
|
|
3122
|
-
},
|
|
3123
|
-
content: {
|
|
3124
|
-
type: "string",
|
|
3125
|
-
description: "Base64-encoded or plain text content. WARNING: HIGH token cost (~330k tokens for 1MB file). Use fileUrl for large files or upload to cloud storage first."
|
|
3126
|
-
},
|
|
3127
|
-
isBase64: {
|
|
3128
|
-
type: "boolean",
|
|
3129
|
-
description: "Whether content is base64-encoded (default: true). Set to false for plain text files.",
|
|
3130
|
-
default: true
|
|
3131
|
-
}
|
|
3132
|
-
},
|
|
3133
|
-
required: ["issueKey", "filename"]
|
|
3134
|
-
}
|
|
3135
|
-
};
|
|
2645
|
+
Returns attachment metadata including ID and download URL. To reference the image in a comment or description, use wiki markup: !filename.png! or !filename.png|thumbnail!`};
|
|
3136
2646
|
async function handleAddAttachment(input) {
|
|
3137
2647
|
try {
|
|
3138
2648
|
const validated = validateInput(AddAttachmentInputSchema, input);
|
|
@@ -3167,19 +2677,7 @@ async function handleAddAttachment(input) {
|
|
|
3167
2677
|
// src/tools/get-attachments.ts
|
|
3168
2678
|
var log21 = createLogger("tool:get-attachments");
|
|
3169
2679
|
var getAttachmentsTool = {
|
|
3170
|
-
|
|
3171
|
-
description: "Lists all attachments on a Jira issue. Returns attachment metadata including filename, size, MIME type, author, and download URL.",
|
|
3172
|
-
inputSchema: {
|
|
3173
|
-
type: "object",
|
|
3174
|
-
properties: {
|
|
3175
|
-
issueKey: {
|
|
3176
|
-
type: "string",
|
|
3177
|
-
description: "Issue key to get attachments for (e.g., PROJECT-123)"
|
|
3178
|
-
}
|
|
3179
|
-
},
|
|
3180
|
-
required: ["issueKey"]
|
|
3181
|
-
}
|
|
3182
|
-
};
|
|
2680
|
+
description: "Lists all attachments on a Jira issue. Returns attachment metadata including filename, size, MIME type, author, and download URL."};
|
|
3183
2681
|
async function handleGetAttachments(input) {
|
|
3184
2682
|
try {
|
|
3185
2683
|
const validated = validateInput(GetAttachmentsInputSchema, input);
|
|
@@ -3196,20 +2694,7 @@ async function handleGetAttachments(input) {
|
|
|
3196
2694
|
// src/tools/delete-attachment.ts
|
|
3197
2695
|
var log22 = createLogger("tool:delete-attachment");
|
|
3198
2696
|
var deleteAttachmentTool = {
|
|
3199
|
-
|
|
3200
|
-
description: "Deletes an attachment from Jira by its attachment ID. Use jira_get_attachments to find attachment IDs.",
|
|
3201
|
-
inputSchema: {
|
|
3202
|
-
type: "object",
|
|
3203
|
-
properties: {
|
|
3204
|
-
attachmentId: {
|
|
3205
|
-
type: "string",
|
|
3206
|
-
description: "ID of the attachment to delete (can be found using jira_get_attachments)",
|
|
3207
|
-
minLength: 1
|
|
3208
|
-
}
|
|
3209
|
-
},
|
|
3210
|
-
required: ["attachmentId"]
|
|
3211
|
-
}
|
|
3212
|
-
};
|
|
2697
|
+
description: "Deletes an attachment from Jira by its attachment ID. Use jira_get_attachments to find attachment IDs."};
|
|
3213
2698
|
async function handleDeleteAttachment(input) {
|
|
3214
2699
|
try {
|
|
3215
2700
|
const validated = validateInput(DeleteAttachmentInputSchema, input);
|
|
@@ -3233,19 +2718,7 @@ async function handleDeleteAttachment(input) {
|
|
|
3233
2718
|
// src/tools/get-transitions.ts
|
|
3234
2719
|
var log23 = createLogger("tool:get-transitions");
|
|
3235
2720
|
var getTransitionsTool = {
|
|
3236
|
-
|
|
3237
|
-
description: "Retrieves all available workflow transitions for a Jira issue. Use this to discover which status changes are possible for an issue before calling jira_transition_issue.",
|
|
3238
|
-
inputSchema: {
|
|
3239
|
-
type: "object",
|
|
3240
|
-
properties: {
|
|
3241
|
-
issueKey: {
|
|
3242
|
-
type: "string",
|
|
3243
|
-
description: "Issue key to get available transitions for (e.g., PROJECT-123)"
|
|
3244
|
-
}
|
|
3245
|
-
},
|
|
3246
|
-
required: ["issueKey"]
|
|
3247
|
-
}
|
|
3248
|
-
};
|
|
2721
|
+
description: "Retrieves all available workflow transitions for a Jira issue. Use this to discover which status changes are possible for an issue before calling jira_transition_issue."};
|
|
3249
2722
|
async function handleGetTransitions(input) {
|
|
3250
2723
|
try {
|
|
3251
2724
|
const validated = validateInput(GetTransitionsInputSchema, input);
|
|
@@ -3262,41 +2735,7 @@ async function handleGetTransitions(input) {
|
|
|
3262
2735
|
// src/tools/transition-issue.ts
|
|
3263
2736
|
var log24 = createLogger("tool:transition-issue");
|
|
3264
2737
|
var transitionIssueTool = {
|
|
3265
|
-
|
|
3266
|
-
description: 'Transitions a Jira issue to a new workflow status (e.g., "To Do" -> "In Progress" -> "Done"). Use jira_get_transitions first to discover available transitions. Supports adding a comment and setting resolution during the transition.',
|
|
3267
|
-
inputSchema: {
|
|
3268
|
-
type: "object",
|
|
3269
|
-
properties: {
|
|
3270
|
-
issueKey: {
|
|
3271
|
-
type: "string",
|
|
3272
|
-
description: "Issue key to transition (e.g., PROJECT-123)"
|
|
3273
|
-
},
|
|
3274
|
-
transitionId: {
|
|
3275
|
-
type: "string",
|
|
3276
|
-
description: "ID of the transition to perform. Use jira_get_transitions to find available transition IDs."
|
|
3277
|
-
},
|
|
3278
|
-
transitionName: {
|
|
3279
|
-
type: "string",
|
|
3280
|
-
description: 'Name of the transition to perform (e.g., "In Progress", "Done"). Case-insensitive. Alternative to transitionId.'
|
|
3281
|
-
},
|
|
3282
|
-
comment: {
|
|
3283
|
-
type: "string",
|
|
3284
|
-
description: "Optional comment to add when transitioning the issue"
|
|
3285
|
-
},
|
|
3286
|
-
resolution: {
|
|
3287
|
-
type: "string",
|
|
3288
|
-
description: 'Resolution name when transitioning to a resolved/done status (e.g., "Done", "Fixed")'
|
|
3289
|
-
},
|
|
3290
|
-
format: {
|
|
3291
|
-
type: "string",
|
|
3292
|
-
enum: ["markdown", "adf", "plain"],
|
|
3293
|
-
description: 'Comment format: "markdown" (converts Markdown to ADF), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting). Default: "markdown"',
|
|
3294
|
-
default: "markdown"
|
|
3295
|
-
}
|
|
3296
|
-
},
|
|
3297
|
-
required: ["issueKey"]
|
|
3298
|
-
}
|
|
3299
|
-
};
|
|
2738
|
+
description: 'Transitions a Jira issue to a new workflow status (e.g., "To Do" -> "In Progress" -> "Done"). Use jira_get_transitions first to discover available transitions. Supports adding a comment and setting resolution during the transition.'};
|
|
3300
2739
|
async function handleTransitionIssue(input) {
|
|
3301
2740
|
try {
|
|
3302
2741
|
const validated = validateInput(TransitionIssueInputSchema, input);
|
|
@@ -3339,6 +2778,259 @@ Available transitions: ${available || "none"}`
|
|
|
3339
2778
|
}
|
|
3340
2779
|
}
|
|
3341
2780
|
|
|
2781
|
+
// src/tools/get-issue-graph.ts
|
|
2782
|
+
var log25 = createLogger("tool:get-issue-graph");
|
|
2783
|
+
var GRAPH_FIELDS = [
|
|
2784
|
+
"summary",
|
|
2785
|
+
"status",
|
|
2786
|
+
"issuetype",
|
|
2787
|
+
"priority",
|
|
2788
|
+
"parent",
|
|
2789
|
+
"subtasks",
|
|
2790
|
+
"issuelinks"
|
|
2791
|
+
];
|
|
2792
|
+
var getIssueGraphTool = {
|
|
2793
|
+
description: "Build a dependency/relationship graph starting from a seed issue. Returns a map of connected issues (parent/child hierarchy, blocks, relates to, duplicates, etc.) with nodes and edges, plus a Mermaid diagram for visualization. Use this to understand how issues are connected across epics, stories, and subtasks."};
|
|
2794
|
+
function extractIssueData(issue) {
|
|
2795
|
+
const fields = issue.fields;
|
|
2796
|
+
return {
|
|
2797
|
+
key: issue.key,
|
|
2798
|
+
summary: fields?.summary || "No summary",
|
|
2799
|
+
status: fields?.status?.name || "Unknown",
|
|
2800
|
+
statusCategory: fields?.status?.statusCategory?.name || "Unknown",
|
|
2801
|
+
issueType: fields?.issuetype?.name || "Unknown",
|
|
2802
|
+
priority: fields?.priority?.name || "None",
|
|
2803
|
+
issuelinks: fields?.issuelinks || [],
|
|
2804
|
+
parent: fields?.parent ? {
|
|
2805
|
+
key: fields.parent.key,
|
|
2806
|
+
summary: fields.parent.fields?.summary,
|
|
2807
|
+
status: fields.parent.fields?.status?.name,
|
|
2808
|
+
issueType: fields.parent.fields?.issuetype?.name
|
|
2809
|
+
} : void 0,
|
|
2810
|
+
subtasks: fields?.subtasks || []
|
|
2811
|
+
};
|
|
2812
|
+
}
|
|
2813
|
+
function buildGraph(issueDataMap, rootKey, options) {
|
|
2814
|
+
const nodes = [];
|
|
2815
|
+
const edges = [];
|
|
2816
|
+
const edgeSet = /* @__PURE__ */ new Set();
|
|
2817
|
+
const addEdge = (edge) => {
|
|
2818
|
+
const edgeId = `${edge.from}->${edge.to}:${edge.type}:${edge.category}`;
|
|
2819
|
+
if (!edgeSet.has(edgeId)) {
|
|
2820
|
+
edgeSet.add(edgeId);
|
|
2821
|
+
edges.push(edge);
|
|
2822
|
+
}
|
|
2823
|
+
};
|
|
2824
|
+
for (const [, data] of issueDataMap) {
|
|
2825
|
+
nodes.push({
|
|
2826
|
+
key: data.key,
|
|
2827
|
+
summary: data.summary,
|
|
2828
|
+
status: data.status,
|
|
2829
|
+
statusCategory: data.statusCategory,
|
|
2830
|
+
issueType: data.issueType,
|
|
2831
|
+
priority: data.priority
|
|
2832
|
+
});
|
|
2833
|
+
if (options.includeHierarchy) {
|
|
2834
|
+
if (data.parent && issueDataMap.has(data.parent.key)) {
|
|
2835
|
+
addEdge({
|
|
2836
|
+
from: data.parent.key,
|
|
2837
|
+
to: data.key,
|
|
2838
|
+
type: "parent of",
|
|
2839
|
+
label: "parent of",
|
|
2840
|
+
category: "hierarchy"
|
|
2841
|
+
});
|
|
2842
|
+
}
|
|
2843
|
+
for (const sub of data.subtasks) {
|
|
2844
|
+
if (issueDataMap.has(sub.key)) {
|
|
2845
|
+
addEdge({
|
|
2846
|
+
from: data.key,
|
|
2847
|
+
to: sub.key,
|
|
2848
|
+
type: "parent of",
|
|
2849
|
+
label: "parent of",
|
|
2850
|
+
category: "hierarchy"
|
|
2851
|
+
});
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
}
|
|
2855
|
+
for (const link of data.issuelinks) {
|
|
2856
|
+
const typeName = link.type?.name || "Unknown";
|
|
2857
|
+
if (options.linkTypes && options.linkTypes.length > 0) {
|
|
2858
|
+
if (!options.linkTypes.some((lt) => lt.toLowerCase() === typeName.toLowerCase())) {
|
|
2859
|
+
continue;
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
if (link.outwardIssue && (options.direction === "all" || options.direction === "outward")) {
|
|
2863
|
+
if (issueDataMap.has(link.outwardIssue.key)) {
|
|
2864
|
+
addEdge({
|
|
2865
|
+
from: data.key,
|
|
2866
|
+
to: link.outwardIssue.key,
|
|
2867
|
+
type: typeName,
|
|
2868
|
+
label: link.type?.outward || typeName,
|
|
2869
|
+
category: "link"
|
|
2870
|
+
});
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
if (link.inwardIssue && (options.direction === "all" || options.direction === "inward")) {
|
|
2874
|
+
if (issueDataMap.has(link.inwardIssue.key)) {
|
|
2875
|
+
addEdge({
|
|
2876
|
+
from: link.inwardIssue.key,
|
|
2877
|
+
to: data.key,
|
|
2878
|
+
type: typeName,
|
|
2879
|
+
label: link.type?.outward || typeName,
|
|
2880
|
+
category: "link"
|
|
2881
|
+
});
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
return {
|
|
2887
|
+
rootIssue: rootKey,
|
|
2888
|
+
nodes,
|
|
2889
|
+
edges,
|
|
2890
|
+
metadata: {
|
|
2891
|
+
totalNodes: nodes.length,
|
|
2892
|
+
totalEdges: edges.length,
|
|
2893
|
+
maxDepthReached: false,
|
|
2894
|
+
// set by caller
|
|
2895
|
+
traversalDepth: 0
|
|
2896
|
+
// set by caller
|
|
2897
|
+
}
|
|
2898
|
+
};
|
|
2899
|
+
}
|
|
2900
|
+
function formatGraphResponse(graph) {
|
|
2901
|
+
const { nodes, edges, metadata, rootIssue } = graph;
|
|
2902
|
+
const nodesTable = nodes.map((n) => `| ${n.key} | ${n.summary} | ${n.status} | ${n.issueType} | ${n.priority} |`).join("\n");
|
|
2903
|
+
const edgesTable = edges.map((e) => `| ${e.from} | ${e.label} | ${e.to} | ${e.category} |`).join("\n");
|
|
2904
|
+
const mermaidNodes = nodes.map((n) => {
|
|
2905
|
+
const shape = n.statusCategory === "Done" ? `${n.key}[/"${n.issueType}: ${escapeMermaid(n.summary)}"/]` : n.statusCategory === "In Progress" ? `${n.key}[["${n.issueType}: ${escapeMermaid(n.summary)}"]]` : `${n.key}["${n.issueType}: ${escapeMermaid(n.summary)}"]`;
|
|
2906
|
+
return ` ${shape}`;
|
|
2907
|
+
}).join("\n");
|
|
2908
|
+
const mermaidEdges = edges.map((e) => {
|
|
2909
|
+
if (e.category === "hierarchy") {
|
|
2910
|
+
return ` ${e.from} --> ${e.to}`;
|
|
2911
|
+
}
|
|
2912
|
+
return ` ${e.from} -->|${escapeMermaid(e.label)}| ${e.to}`;
|
|
2913
|
+
}).join("\n");
|
|
2914
|
+
const doneNodes = nodes.filter((n) => n.statusCategory === "Done").map((n) => n.key);
|
|
2915
|
+
const inProgressNodes = nodes.filter((n) => n.statusCategory === "In Progress").map((n) => n.key);
|
|
2916
|
+
const todoNodes = nodes.filter((n) => n.statusCategory !== "Done" && n.statusCategory !== "In Progress").map((n) => n.key);
|
|
2917
|
+
let mermaidStyles = "";
|
|
2918
|
+
if (doneNodes.length > 0) mermaidStyles += `
|
|
2919
|
+
classDef done fill:#d4edda,stroke:#28a745`;
|
|
2920
|
+
if (inProgressNodes.length > 0)
|
|
2921
|
+
mermaidStyles += `
|
|
2922
|
+
classDef inprogress fill:#fff3cd,stroke:#ffc107`;
|
|
2923
|
+
if (todoNodes.length > 0) mermaidStyles += `
|
|
2924
|
+
classDef todo fill:#f8d7da,stroke:#dc3545`;
|
|
2925
|
+
if (doneNodes.length > 0) mermaidStyles += `
|
|
2926
|
+
class ${doneNodes.join(",")} done`;
|
|
2927
|
+
if (inProgressNodes.length > 0)
|
|
2928
|
+
mermaidStyles += `
|
|
2929
|
+
class ${inProgressNodes.join(",")} inprogress`;
|
|
2930
|
+
if (todoNodes.length > 0) mermaidStyles += `
|
|
2931
|
+
class ${todoNodes.join(",")} todo`;
|
|
2932
|
+
const depthNote = metadata.maxDepthReached ? " (max depth reached, graph may be incomplete)" : "";
|
|
2933
|
+
const text = `## Issue Graph: ${rootIssue} (depth: ${metadata.traversalDepth}, ${metadata.totalNodes} nodes, ${metadata.totalEdges} edges)${depthNote}
|
|
2934
|
+
|
|
2935
|
+
### Nodes
|
|
2936
|
+
| Key | Summary | Status | Type | Priority |
|
|
2937
|
+
|-----|---------|--------|------|----------|
|
|
2938
|
+
${nodesTable}
|
|
2939
|
+
|
|
2940
|
+
### Edges
|
|
2941
|
+
| From | Relationship | To | Category |
|
|
2942
|
+
|------|-------------|-----|----------|
|
|
2943
|
+
${edgesTable}
|
|
2944
|
+
|
|
2945
|
+
### Mermaid Diagram
|
|
2946
|
+
\`\`\`mermaid
|
|
2947
|
+
graph TD
|
|
2948
|
+
${mermaidNodes}
|
|
2949
|
+
${mermaidEdges}${mermaidStyles}
|
|
2950
|
+
\`\`\``;
|
|
2951
|
+
return { content: [{ type: "text", text }] };
|
|
2952
|
+
}
|
|
2953
|
+
function escapeMermaid(text) {
|
|
2954
|
+
return text.replace(/"/g, "'").replace(/[[\]{}()#]/g, "").substring(0, 60);
|
|
2955
|
+
}
|
|
2956
|
+
async function handleGetIssueGraph(input) {
|
|
2957
|
+
try {
|
|
2958
|
+
const validated = validateInput(GetIssueGraphInputSchema, input);
|
|
2959
|
+
const {
|
|
2960
|
+
issueKey,
|
|
2961
|
+
maxDepth = 2,
|
|
2962
|
+
maxNodes = 50,
|
|
2963
|
+
includeHierarchy = true,
|
|
2964
|
+
linkTypes,
|
|
2965
|
+
direction = "all"
|
|
2966
|
+
} = validated;
|
|
2967
|
+
log25.info(`Building issue graph from ${issueKey} (depth: ${maxDepth}, maxNodes: ${maxNodes})`);
|
|
2968
|
+
const issueDataMap = /* @__PURE__ */ new Map();
|
|
2969
|
+
const queue = [{ key: issueKey, depth: 0 }];
|
|
2970
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2971
|
+
let maxDepthReached = false;
|
|
2972
|
+
let actualDepth = 0;
|
|
2973
|
+
while (queue.length > 0 && issueDataMap.size < maxNodes) {
|
|
2974
|
+
const current = queue.shift();
|
|
2975
|
+
if (visited.has(current.key)) continue;
|
|
2976
|
+
visited.add(current.key);
|
|
2977
|
+
if (current.depth > maxDepth) {
|
|
2978
|
+
maxDepthReached = true;
|
|
2979
|
+
continue;
|
|
2980
|
+
}
|
|
2981
|
+
actualDepth = Math.max(actualDepth, current.depth);
|
|
2982
|
+
let issue;
|
|
2983
|
+
try {
|
|
2984
|
+
issue = await getIssue(current.key, { fields: GRAPH_FIELDS });
|
|
2985
|
+
} catch (err) {
|
|
2986
|
+
log25.warn(`Skipping issue ${current.key}: ${err.message}`);
|
|
2987
|
+
continue;
|
|
2988
|
+
}
|
|
2989
|
+
const data = extractIssueData(issue);
|
|
2990
|
+
issueDataMap.set(current.key, data);
|
|
2991
|
+
if (current.depth >= maxDepth) continue;
|
|
2992
|
+
const nextDepth = current.depth + 1;
|
|
2993
|
+
if (includeHierarchy && data.parent && !visited.has(data.parent.key)) {
|
|
2994
|
+
queue.push({ key: data.parent.key, depth: nextDepth });
|
|
2995
|
+
}
|
|
2996
|
+
if (includeHierarchy) {
|
|
2997
|
+
for (const sub of data.subtasks) {
|
|
2998
|
+
if (!visited.has(sub.key)) {
|
|
2999
|
+
queue.push({ key: sub.key, depth: nextDepth });
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
for (const link of data.issuelinks) {
|
|
3004
|
+
if (linkTypes && linkTypes.length > 0) {
|
|
3005
|
+
const typeName = link.type?.name || "";
|
|
3006
|
+
if (!linkTypes.some((lt) => lt.toLowerCase() === typeName.toLowerCase())) continue;
|
|
3007
|
+
}
|
|
3008
|
+
if (link.outwardIssue && !visited.has(link.outwardIssue.key) && (direction === "all" || direction === "outward")) {
|
|
3009
|
+
queue.push({ key: link.outwardIssue.key, depth: nextDepth });
|
|
3010
|
+
}
|
|
3011
|
+
if (link.inwardIssue && !visited.has(link.inwardIssue.key) && (direction === "all" || direction === "inward")) {
|
|
3012
|
+
queue.push({ key: link.inwardIssue.key, depth: nextDepth });
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
if (queue.length > 0) {
|
|
3017
|
+
maxDepthReached = true;
|
|
3018
|
+
}
|
|
3019
|
+
log25.info(`Graph built: ${issueDataMap.size} nodes discovered`);
|
|
3020
|
+
const graph = buildGraph(issueDataMap, issueKey, {
|
|
3021
|
+
includeHierarchy,
|
|
3022
|
+
linkTypes,
|
|
3023
|
+
direction
|
|
3024
|
+
});
|
|
3025
|
+
graph.metadata.maxDepthReached = maxDepthReached;
|
|
3026
|
+
graph.metadata.traversalDepth = actualDepth;
|
|
3027
|
+
return formatGraphResponse(graph);
|
|
3028
|
+
} catch (error) {
|
|
3029
|
+
log25.error("Error in handleGetIssueGraph:", error);
|
|
3030
|
+
return handleError(error);
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
|
|
3342
3034
|
// src/index.ts
|
|
3343
3035
|
if (process.env.NODE_ENV !== "production") {
|
|
3344
3036
|
try {
|
|
@@ -3347,54 +3039,172 @@ if (process.env.NODE_ENV !== "production") {
|
|
|
3347
3039
|
} catch {
|
|
3348
3040
|
}
|
|
3349
3041
|
}
|
|
3350
|
-
var
|
|
3351
|
-
var
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3042
|
+
var log26 = createLogger("server");
|
|
3043
|
+
var toolRegistry = [
|
|
3044
|
+
// === Read-only tools ===
|
|
3045
|
+
{
|
|
3046
|
+
name: TOOL_NAMES.GET_VISIBLE_PROJECTS,
|
|
3047
|
+
description: getVisibleProjectsTool.description,
|
|
3048
|
+
inputSchema: GetVisibleProjectsInputSchema,
|
|
3049
|
+
handler: handleGetVisibleProjects,
|
|
3050
|
+
annotations: { readOnlyHint: true }
|
|
3051
|
+
},
|
|
3052
|
+
{
|
|
3053
|
+
name: TOOL_NAMES.GET_ISSUE,
|
|
3054
|
+
description: getIssueTool.description,
|
|
3055
|
+
inputSchema: GetIssueInputSchema,
|
|
3056
|
+
handler: handleGetIssue,
|
|
3057
|
+
annotations: { readOnlyHint: true }
|
|
3058
|
+
},
|
|
3059
|
+
{
|
|
3060
|
+
name: TOOL_NAMES.SEARCH_ISSUES,
|
|
3061
|
+
description: searchIssuesTool.description,
|
|
3062
|
+
inputSchema: SearchIssuesInputSchema,
|
|
3063
|
+
handler: handleSearchIssues,
|
|
3064
|
+
annotations: { readOnlyHint: true }
|
|
3065
|
+
},
|
|
3066
|
+
{
|
|
3067
|
+
name: TOOL_NAMES.GET_MY_ISSUES,
|
|
3068
|
+
description: getMyIssuesTool.description,
|
|
3069
|
+
inputSchema: GetMyIssuesInputSchema,
|
|
3070
|
+
handler: handleGetMyIssues,
|
|
3071
|
+
annotations: { readOnlyHint: true }
|
|
3072
|
+
},
|
|
3073
|
+
{
|
|
3074
|
+
name: TOOL_NAMES.GET_ISSUE_TYPES,
|
|
3075
|
+
description: getIssueTypesTool.description,
|
|
3076
|
+
inputSchema: GetIssueTypesInputSchema,
|
|
3077
|
+
handler: handleGetIssueTypes,
|
|
3078
|
+
annotations: { readOnlyHint: true }
|
|
3079
|
+
},
|
|
3080
|
+
{
|
|
3081
|
+
name: TOOL_NAMES.GET_USERS,
|
|
3082
|
+
description: getUsersTool.description,
|
|
3083
|
+
inputSchema: GetUsersInputSchema,
|
|
3084
|
+
handler: handleGetUsers,
|
|
3085
|
+
annotations: { readOnlyHint: true }
|
|
3086
|
+
},
|
|
3087
|
+
{
|
|
3088
|
+
name: TOOL_NAMES.GET_PRIORITIES,
|
|
3089
|
+
description: getPrioritiesTool.description,
|
|
3090
|
+
inputSchema: GetPrioritiesInputSchema,
|
|
3091
|
+
handler: handleGetPriorities,
|
|
3092
|
+
annotations: { readOnlyHint: true }
|
|
3093
|
+
},
|
|
3094
|
+
{
|
|
3095
|
+
name: TOOL_NAMES.GET_STATUSES,
|
|
3096
|
+
description: getStatusesTool.description,
|
|
3097
|
+
inputSchema: GetStatusesInputSchema,
|
|
3098
|
+
handler: handleGetStatuses,
|
|
3099
|
+
annotations: { readOnlyHint: true }
|
|
3100
|
+
},
|
|
3101
|
+
{
|
|
3102
|
+
name: TOOL_NAMES.GET_PROJECT_INFO,
|
|
3103
|
+
description: getProjectInfoTool.description,
|
|
3104
|
+
inputSchema: GetProjectInfoInputSchema,
|
|
3105
|
+
handler: handleGetProjectInfo,
|
|
3106
|
+
annotations: { readOnlyHint: true }
|
|
3107
|
+
},
|
|
3108
|
+
{
|
|
3109
|
+
name: TOOL_NAMES.GET_CREATE_META,
|
|
3110
|
+
description: getCreateMetaTool.description,
|
|
3111
|
+
inputSchema: GetCreateMetaInputSchema,
|
|
3112
|
+
handler: handleGetCreateMeta,
|
|
3113
|
+
annotations: { readOnlyHint: true }
|
|
3114
|
+
},
|
|
3115
|
+
{
|
|
3116
|
+
name: TOOL_NAMES.GET_CUSTOM_FIELDS,
|
|
3117
|
+
description: getCustomFieldsTool.description,
|
|
3118
|
+
inputSchema: GetCustomFieldsInputSchema,
|
|
3119
|
+
handler: handleGetCustomFields,
|
|
3120
|
+
annotations: { readOnlyHint: true }
|
|
3121
|
+
},
|
|
3122
|
+
{
|
|
3123
|
+
name: TOOL_NAMES.GET_COMMENTS,
|
|
3124
|
+
description: getCommentsTool.description,
|
|
3125
|
+
inputSchema: GetCommentsInputSchema,
|
|
3126
|
+
handler: handleGetComments,
|
|
3127
|
+
annotations: { readOnlyHint: true }
|
|
3128
|
+
},
|
|
3129
|
+
{
|
|
3130
|
+
name: TOOL_NAMES.GET_ATTACHMENTS,
|
|
3131
|
+
description: getAttachmentsTool.description,
|
|
3132
|
+
inputSchema: GetAttachmentsInputSchema,
|
|
3133
|
+
handler: handleGetAttachments,
|
|
3134
|
+
annotations: { readOnlyHint: true }
|
|
3135
|
+
},
|
|
3136
|
+
{
|
|
3137
|
+
name: TOOL_NAMES.GET_TRANSITIONS,
|
|
3138
|
+
description: getTransitionsTool.description,
|
|
3139
|
+
inputSchema: GetTransitionsInputSchema,
|
|
3140
|
+
handler: handleGetTransitions,
|
|
3141
|
+
annotations: { readOnlyHint: true }
|
|
3142
|
+
},
|
|
3143
|
+
// === Mutating tools ===
|
|
3144
|
+
{
|
|
3145
|
+
name: TOOL_NAMES.CREATE_ISSUE,
|
|
3146
|
+
description: createIssueTool.description,
|
|
3147
|
+
inputSchema: CreateIssueInputSchema,
|
|
3148
|
+
handler: handleCreateIssue,
|
|
3149
|
+
annotations: { readOnlyHint: false }
|
|
3150
|
+
},
|
|
3151
|
+
{
|
|
3152
|
+
name: TOOL_NAMES.UPDATE_ISSUE,
|
|
3153
|
+
description: updateIssueTool.description,
|
|
3154
|
+
inputSchema: UpdateIssueInputSchema,
|
|
3155
|
+
handler: handleUpdateIssue,
|
|
3156
|
+
annotations: { readOnlyHint: false }
|
|
3157
|
+
},
|
|
3158
|
+
{
|
|
3159
|
+
name: TOOL_NAMES.ADD_COMMENT,
|
|
3160
|
+
description: addCommentTool.description,
|
|
3161
|
+
inputSchema: AddCommentInputSchema,
|
|
3162
|
+
handler: handleAddComment,
|
|
3163
|
+
annotations: { readOnlyHint: false }
|
|
3164
|
+
},
|
|
3165
|
+
{
|
|
3166
|
+
name: TOOL_NAMES.CREATE_SUBTASK,
|
|
3167
|
+
description: createSubtaskTool.description,
|
|
3168
|
+
inputSchema: CreateSubtaskInputSchema,
|
|
3169
|
+
handler: handleCreateSubtask,
|
|
3170
|
+
annotations: { readOnlyHint: false }
|
|
3171
|
+
},
|
|
3172
|
+
{
|
|
3173
|
+
name: TOOL_NAMES.CREATE_ISSUE_LINK,
|
|
3174
|
+
description: createIssueLinkTool.description,
|
|
3175
|
+
inputSchema: CreateIssueLinkInputSchema,
|
|
3176
|
+
handler: handleCreateIssueLink,
|
|
3177
|
+
annotations: { readOnlyHint: false }
|
|
3178
|
+
},
|
|
3179
|
+
{
|
|
3180
|
+
name: TOOL_NAMES.ADD_ATTACHMENT,
|
|
3181
|
+
description: addAttachmentTool.description,
|
|
3182
|
+
inputSchema: AddAttachmentInputSchema,
|
|
3183
|
+
handler: handleAddAttachment,
|
|
3184
|
+
annotations: { readOnlyHint: false }
|
|
3185
|
+
},
|
|
3186
|
+
{
|
|
3187
|
+
name: TOOL_NAMES.TRANSITION_ISSUE,
|
|
3188
|
+
description: transitionIssueTool.description,
|
|
3189
|
+
inputSchema: TransitionIssueInputSchema,
|
|
3190
|
+
handler: handleTransitionIssue,
|
|
3191
|
+
annotations: { readOnlyHint: false }
|
|
3192
|
+
},
|
|
3193
|
+
{
|
|
3194
|
+
name: TOOL_NAMES.GET_ISSUE_GRAPH,
|
|
3195
|
+
description: getIssueGraphTool.description,
|
|
3196
|
+
inputSchema: GetIssueGraphInputSchema,
|
|
3197
|
+
handler: handleGetIssueGraph,
|
|
3198
|
+
annotations: { readOnlyHint: true }
|
|
3199
|
+
},
|
|
3200
|
+
// === Destructive tools ===
|
|
3201
|
+
{
|
|
3202
|
+
name: TOOL_NAMES.DELETE_ATTACHMENT,
|
|
3203
|
+
description: deleteAttachmentTool.description,
|
|
3204
|
+
inputSchema: DeleteAttachmentInputSchema,
|
|
3205
|
+
handler: handleDeleteAttachment,
|
|
3206
|
+
annotations: { readOnlyHint: false, destructiveHint: true }
|
|
3207
|
+
}
|
|
3398
3208
|
];
|
|
3399
3209
|
async function main() {
|
|
3400
3210
|
const isDryRun = (process.env.DRY_RUN || "").toLowerCase() === "1" || (process.env.DRY_RUN || "").toLowerCase() === "true";
|
|
@@ -3422,50 +3232,45 @@ async function main() {
|
|
|
3422
3232
|
version = pkg.default?.version || pkg.version || version;
|
|
3423
3233
|
} catch {
|
|
3424
3234
|
}
|
|
3425
|
-
const server = new
|
|
3235
|
+
const server = new McpServer(
|
|
3426
3236
|
{
|
|
3427
3237
|
name: "jira-mcp-server",
|
|
3428
3238
|
version
|
|
3429
3239
|
},
|
|
3430
3240
|
{
|
|
3431
3241
|
capabilities: {
|
|
3432
|
-
resources: {},
|
|
3433
3242
|
tools: {}
|
|
3434
3243
|
}
|
|
3435
3244
|
}
|
|
3436
3245
|
);
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
});
|
|
3460
|
-
server.setRequestHandler(ReadResourceRequestSchema, async () => {
|
|
3461
|
-
throw new Error("Resource reading not implemented");
|
|
3462
|
-
});
|
|
3246
|
+
for (const entry of toolRegistry) {
|
|
3247
|
+
server.registerTool(
|
|
3248
|
+
entry.name,
|
|
3249
|
+
{
|
|
3250
|
+
description: entry.description,
|
|
3251
|
+
inputSchema: entry.inputSchema,
|
|
3252
|
+
annotations: entry.annotations
|
|
3253
|
+
},
|
|
3254
|
+
async (args) => {
|
|
3255
|
+
console.error(`\u{1F6E0}\uFE0F Executing tool: ${entry.name}`);
|
|
3256
|
+
try {
|
|
3257
|
+
const result = await entry.handler(args);
|
|
3258
|
+
console.error(`\u2705 Tool ${entry.name} executed successfully`);
|
|
3259
|
+
return result;
|
|
3260
|
+
} catch (error) {
|
|
3261
|
+
console.error(`\u274C Error executing tool ${entry.name}:`, error.message);
|
|
3262
|
+
throw error;
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
);
|
|
3266
|
+
}
|
|
3267
|
+
console.error(`\u{1F4CB} Registered ${toolRegistry.length} tool(s)`);
|
|
3463
3268
|
const transport = new StdioServerTransport();
|
|
3464
3269
|
await server.connect(transport);
|
|
3465
3270
|
console.error("\u{1F680} Jira MCP server running on stdio");
|
|
3466
3271
|
}
|
|
3467
3272
|
main().catch((error) => {
|
|
3468
|
-
|
|
3273
|
+
log26.error("Fatal error:", error);
|
|
3469
3274
|
process.exit(1);
|
|
3470
3275
|
});
|
|
3471
3276
|
//# sourceMappingURL=index.js.map
|