mcp-jira-stdio 1.5.2 → 1.5.5
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/README.md +31 -0
- package/dist/index.js +73 -124
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,25 @@
|
|
|
16
16
|
|
|
17
17
|
A Model Context Protocol (MCP) server for Jira API integration. Enables reading, writing, and managing Jira issues and projects directly from your MCP client (e.g., Claude Desktop).
|
|
18
18
|
|
|
19
|
+
## ⚡ Quick Install for Claude Code
|
|
20
|
+
|
|
21
|
+
The fastest way to add this MCP server to Claude Code:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
claude mcp add jira npx mcp-jira-stdio@latest
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
You will be prompted to enter your Jira credentials:
|
|
28
|
+
- **JIRA_BASE_URL**: Your Jira instance URL (e.g., `https://yourcompany.atlassian.net`)
|
|
29
|
+
- **JIRA_EMAIL**: Your Jira account email
|
|
30
|
+
- **JIRA_API_TOKEN**: Your Jira API token ([generate here](https://id.atlassian.com/manage-profile/security/api-tokens))
|
|
31
|
+
|
|
32
|
+
That's it! The server will be automatically configured and ready to use.
|
|
33
|
+
|
|
34
|
+
### Alternative: Manual Configuration
|
|
35
|
+
|
|
36
|
+
If you prefer to configure manually or use Claude Desktop, see the [Configuration](#6-configure-mcp-client) section below.
|
|
37
|
+
|
|
19
38
|
## 🚀 Quick Start
|
|
20
39
|
|
|
21
40
|
### 1. Prerequisites
|
|
@@ -95,6 +114,16 @@ task jira:projects
|
|
|
95
114
|
|
|
96
115
|
### 6. Configure MCP Client
|
|
97
116
|
|
|
117
|
+
#### For Claude Code
|
|
118
|
+
|
|
119
|
+
Use the quick install command (recommended):
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
claude mcp add jira npx mcp-jira-stdio@latest
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### For Claude Desktop
|
|
126
|
+
|
|
98
127
|
Add to your Claude Desktop config:
|
|
99
128
|
|
|
100
129
|
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
@@ -157,10 +186,12 @@ Restart Claude Desktop after adding the configuration.
|
|
|
157
186
|
|
|
158
187
|
### Metadata & Users
|
|
159
188
|
|
|
189
|
+
- `jira_get_create_meta`: Get create metadata for a project showing all available fields (including custom fields) with their allowed values. Essential for discovering required fields before creating issues.
|
|
160
190
|
- `jira_get_issue_types`: List issue types (optionally per project).
|
|
161
191
|
- `jira_get_users`: Search for users (by query, username, or accountId).
|
|
162
192
|
- `jira_get_priorities`: List available priorities.
|
|
163
193
|
- `jira_get_statuses`: List available statuses (global or project-specific).
|
|
194
|
+
- `jira_get_custom_fields`: List all custom fields in Jira with their types and schemas.
|
|
164
195
|
|
|
165
196
|
### My Work
|
|
166
197
|
|
package/dist/index.js
CHANGED
|
@@ -439,7 +439,7 @@ var require_package2 = __commonJS({
|
|
|
439
439
|
"package.json"(exports, module) {
|
|
440
440
|
module.exports = {
|
|
441
441
|
name: "mcp-jira-stdio",
|
|
442
|
-
version: "1.5.
|
|
442
|
+
version: "1.5.5",
|
|
443
443
|
description: "Model Context Protocol (MCP) server for Jira API integration",
|
|
444
444
|
author: "graslt",
|
|
445
445
|
license: "MIT",
|
|
@@ -824,7 +824,6 @@ var GetCustomFieldsInputSchema = z.object({
|
|
|
824
824
|
});
|
|
825
825
|
|
|
826
826
|
// src/utils/api-helpers.ts
|
|
827
|
-
var log2 = createLogger("api-helpers");
|
|
828
827
|
function ensureAdfDescription(desc) {
|
|
829
828
|
if (!desc) return desc;
|
|
830
829
|
if (typeof desc === "object") return desc;
|
|
@@ -1211,56 +1210,6 @@ async function createSubtask(parentIssueKey, subtaskData) {
|
|
|
1211
1210
|
return await getIssue(response.key);
|
|
1212
1211
|
}
|
|
1213
1212
|
async function getCreateMeta(options = {}) {
|
|
1214
|
-
if (options.projectKeys && options.projectKeys.length === 1) {
|
|
1215
|
-
const projectKey = options.projectKeys[0];
|
|
1216
|
-
const allIssueTypes = await getIssueTypes(projectKey);
|
|
1217
|
-
let issueTypesToFetch = allIssueTypes;
|
|
1218
|
-
if (options.issueTypeNames && options.issueTypeNames.length > 0) {
|
|
1219
|
-
issueTypesToFetch = allIssueTypes.filter(
|
|
1220
|
-
(type) => options.issueTypeNames?.includes(type.name)
|
|
1221
|
-
);
|
|
1222
|
-
}
|
|
1223
|
-
const issueTypesWithFields = [];
|
|
1224
|
-
for (const issueType of issueTypesToFetch) {
|
|
1225
|
-
try {
|
|
1226
|
-
const config2 = {
|
|
1227
|
-
method: "GET",
|
|
1228
|
-
url: `/issue/createmeta/${projectKey}/issuetypes/${issueType.id}`
|
|
1229
|
-
};
|
|
1230
|
-
const issueTypeMetadata = await makeJiraRequest(config2);
|
|
1231
|
-
const fieldsMap = {};
|
|
1232
|
-
if (issueTypeMetadata.values && Array.isArray(issueTypeMetadata.values)) {
|
|
1233
|
-
for (const field of issueTypeMetadata.values) {
|
|
1234
|
-
const fieldKey = field.key || field.fieldId || field.name;
|
|
1235
|
-
if (fieldKey) {
|
|
1236
|
-
fieldsMap[fieldKey] = field;
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
issueTypesWithFields.push({
|
|
1241
|
-
id: issueType.id,
|
|
1242
|
-
name: issueType.name,
|
|
1243
|
-
description: issueType.description,
|
|
1244
|
-
iconUrl: issueType.iconUrl,
|
|
1245
|
-
subtask: issueType.subtask,
|
|
1246
|
-
fields: fieldsMap
|
|
1247
|
-
});
|
|
1248
|
-
} catch (error) {
|
|
1249
|
-
log2.error(`Failed to get metadata for issue type ${issueType.name}:`, error);
|
|
1250
|
-
}
|
|
1251
|
-
}
|
|
1252
|
-
const projectDetails = await getProjectDetails(projectKey);
|
|
1253
|
-
return {
|
|
1254
|
-
projects: [
|
|
1255
|
-
{
|
|
1256
|
-
id: projectDetails.id,
|
|
1257
|
-
key: projectDetails.key,
|
|
1258
|
-
name: projectDetails.name,
|
|
1259
|
-
issuetypes: issueTypesWithFields
|
|
1260
|
-
}
|
|
1261
|
-
]
|
|
1262
|
-
};
|
|
1263
|
-
}
|
|
1264
1213
|
const params = {};
|
|
1265
1214
|
if (options.projectKeys && options.projectKeys.length > 0) {
|
|
1266
1215
|
params.projectKeys = options.projectKeys.join(",");
|
|
@@ -1728,7 +1677,7 @@ ${fieldsList}`
|
|
|
1728
1677
|
}
|
|
1729
1678
|
|
|
1730
1679
|
// src/utils/error-handler.ts
|
|
1731
|
-
var
|
|
1680
|
+
var log2 = createLogger("error-handler");
|
|
1732
1681
|
var JiraApiError = class extends Error {
|
|
1733
1682
|
constructor(message, statusCode, jiraErrors, originalError) {
|
|
1734
1683
|
super(message);
|
|
@@ -1739,7 +1688,7 @@ var JiraApiError = class extends Error {
|
|
|
1739
1688
|
}
|
|
1740
1689
|
};
|
|
1741
1690
|
function handleError(error) {
|
|
1742
|
-
|
|
1691
|
+
log2.error("Tool error:", error);
|
|
1743
1692
|
if (typeof error === "string") {
|
|
1744
1693
|
return formatErrorResponse(error);
|
|
1745
1694
|
}
|
|
@@ -1776,7 +1725,7 @@ function handleError(error) {
|
|
|
1776
1725
|
}
|
|
1777
1726
|
|
|
1778
1727
|
// src/tools/get-visible-projects.ts
|
|
1779
|
-
var
|
|
1728
|
+
var log3 = createLogger("tool:get-visible-projects");
|
|
1780
1729
|
var getVisibleProjectsTool = {
|
|
1781
1730
|
name: TOOL_NAMES.GET_VISIBLE_PROJECTS,
|
|
1782
1731
|
description: "Retrieves all projects accessible to the authenticated user. Returns project keys, names, descriptions, and basic metadata.",
|
|
@@ -1802,21 +1751,21 @@ var getVisibleProjectsTool = {
|
|
|
1802
1751
|
async function handleGetVisibleProjects(input) {
|
|
1803
1752
|
try {
|
|
1804
1753
|
const validated = validateInput(GetVisibleProjectsInputSchema, input);
|
|
1805
|
-
|
|
1754
|
+
log3.info("Getting visible projects...");
|
|
1806
1755
|
const getParams = {};
|
|
1807
1756
|
if (validated.expand !== void 0) getParams.expand = validated.expand;
|
|
1808
1757
|
if (validated.recent !== void 0) getParams.recent = validated.recent;
|
|
1809
1758
|
const projects = await getVisibleProjects(getParams);
|
|
1810
|
-
|
|
1759
|
+
log3.info(`Found ${projects.length} project(s)`);
|
|
1811
1760
|
return formatProjectsResponse(projects);
|
|
1812
1761
|
} catch (error) {
|
|
1813
|
-
|
|
1762
|
+
log3.error("Error in handleGetVisibleProjects:", error);
|
|
1814
1763
|
return handleError(error);
|
|
1815
1764
|
}
|
|
1816
1765
|
}
|
|
1817
1766
|
|
|
1818
1767
|
// src/tools/get-issue.ts
|
|
1819
|
-
var
|
|
1768
|
+
var log4 = createLogger("tool:get-issue");
|
|
1820
1769
|
var getIssueTool = {
|
|
1821
1770
|
name: TOOL_NAMES.GET_ISSUE,
|
|
1822
1771
|
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.',
|
|
@@ -1847,21 +1796,21 @@ async function handleGetIssue(input) {
|
|
|
1847
1796
|
const validated = validateInput(GetIssueInputSchema, input);
|
|
1848
1797
|
const trimmedInput = (validated.issueKey || "").trim();
|
|
1849
1798
|
const key = extractIssueKey(trimmedInput) || trimmedInput;
|
|
1850
|
-
|
|
1799
|
+
log4.info(`Getting issue ${key}...`);
|
|
1851
1800
|
const getParams = {};
|
|
1852
1801
|
if (validated.expand !== void 0) getParams.expand = validated.expand;
|
|
1853
1802
|
if (validated.fields !== void 0) getParams.fields = validated.fields;
|
|
1854
1803
|
const issue = await getIssue(key, getParams);
|
|
1855
|
-
|
|
1804
|
+
log4.info(`Retrieved issue ${issue.key}`);
|
|
1856
1805
|
return formatIssueResponse(issue);
|
|
1857
1806
|
} catch (error) {
|
|
1858
|
-
|
|
1807
|
+
log4.error("Error in handleGetIssue:", error);
|
|
1859
1808
|
return handleError(error);
|
|
1860
1809
|
}
|
|
1861
1810
|
}
|
|
1862
1811
|
|
|
1863
1812
|
// src/tools/search-issues.ts
|
|
1864
|
-
var
|
|
1813
|
+
var log5 = createLogger("tool:search-issues");
|
|
1865
1814
|
var searchIssuesTool = {
|
|
1866
1815
|
name: TOOL_NAMES.SEARCH_ISSUES,
|
|
1867
1816
|
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.',
|
|
@@ -1901,7 +1850,7 @@ var searchIssuesTool = {
|
|
|
1901
1850
|
async function handleSearchIssues(input) {
|
|
1902
1851
|
try {
|
|
1903
1852
|
const validated = validateInput(SearchIssuesInputSchema, input);
|
|
1904
|
-
|
|
1853
|
+
log5.info(`Searching issues with JQL: "${validated.jql}"...`);
|
|
1905
1854
|
const searchParams = {
|
|
1906
1855
|
jql: validated.jql
|
|
1907
1856
|
};
|
|
@@ -1910,16 +1859,16 @@ async function handleSearchIssues(input) {
|
|
|
1910
1859
|
if (validated.fields !== void 0) searchParams.fields = validated.fields;
|
|
1911
1860
|
if (validated.expand !== void 0) searchParams.expand = validated.expand;
|
|
1912
1861
|
const result = await searchIssues(searchParams);
|
|
1913
|
-
|
|
1862
|
+
log5.info(`Found ${result.total} issue(s), showing ${result.issues.length}`);
|
|
1914
1863
|
return formatSearchResultsResponse(result);
|
|
1915
1864
|
} catch (error) {
|
|
1916
|
-
|
|
1865
|
+
log5.error("Error in handleSearchIssues:", error);
|
|
1917
1866
|
return handleError(error);
|
|
1918
1867
|
}
|
|
1919
1868
|
}
|
|
1920
1869
|
|
|
1921
1870
|
// src/tools/get-my-issues.ts
|
|
1922
|
-
var
|
|
1871
|
+
var log6 = createLogger("tool:get-my-issues");
|
|
1923
1872
|
var getMyIssuesTool = {
|
|
1924
1873
|
name: TOOL_NAMES.GET_MY_ISSUES,
|
|
1925
1874
|
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.",
|
|
@@ -1955,23 +1904,23 @@ var getMyIssuesTool = {
|
|
|
1955
1904
|
async function handleGetMyIssues(input) {
|
|
1956
1905
|
try {
|
|
1957
1906
|
const validated = validateInput(GetMyIssuesInputSchema, input);
|
|
1958
|
-
|
|
1907
|
+
log6.info("Getting issues assigned to current user...");
|
|
1959
1908
|
const getParams = {};
|
|
1960
1909
|
if (validated.nextPageToken !== void 0) getParams.nextPageToken = validated.nextPageToken;
|
|
1961
1910
|
if (validated.maxResults !== void 0) getParams.maxResults = validated.maxResults;
|
|
1962
1911
|
if (validated.fields !== void 0) getParams.fields = validated.fields;
|
|
1963
1912
|
if (validated.expand !== void 0) getParams.expand = validated.expand;
|
|
1964
1913
|
const result = await getMyIssues(getParams);
|
|
1965
|
-
|
|
1914
|
+
log6.info(`Found ${result.total} issue(s) assigned to you, showing ${result.issues.length}`);
|
|
1966
1915
|
return formatSearchResultsResponse(result);
|
|
1967
1916
|
} catch (error) {
|
|
1968
|
-
|
|
1917
|
+
log6.error("Error in handleGetMyIssues:", error);
|
|
1969
1918
|
return handleError(error);
|
|
1970
1919
|
}
|
|
1971
1920
|
}
|
|
1972
1921
|
|
|
1973
1922
|
// src/tools/get-issue-types.ts
|
|
1974
|
-
var
|
|
1923
|
+
var log7 = createLogger("tool:get-issue-types");
|
|
1975
1924
|
var getIssueTypesTool = {
|
|
1976
1925
|
name: TOOL_NAMES.GET_ISSUE_TYPES,
|
|
1977
1926
|
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.).",
|
|
@@ -1990,21 +1939,21 @@ async function handleGetIssueTypes(input) {
|
|
|
1990
1939
|
try {
|
|
1991
1940
|
const validated = validateInput(GetIssueTypesInputSchema, input);
|
|
1992
1941
|
if (validated.projectKey) {
|
|
1993
|
-
|
|
1942
|
+
log7.info(`Getting issue types for project ${validated.projectKey}...`);
|
|
1994
1943
|
} else {
|
|
1995
|
-
|
|
1944
|
+
log7.info("Getting global issue types...");
|
|
1996
1945
|
}
|
|
1997
1946
|
const issueTypes = await getIssueTypes(validated.projectKey);
|
|
1998
|
-
|
|
1947
|
+
log7.info(`Found ${issueTypes.length} issue type(s)`);
|
|
1999
1948
|
return formatIssueTypesResponse(issueTypes);
|
|
2000
1949
|
} catch (error) {
|
|
2001
|
-
|
|
1950
|
+
log7.error("Error in handleGetIssueTypes:", error);
|
|
2002
1951
|
return handleError(error);
|
|
2003
1952
|
}
|
|
2004
1953
|
}
|
|
2005
1954
|
|
|
2006
1955
|
// src/tools/get-users.ts
|
|
2007
|
-
var
|
|
1956
|
+
var log8 = createLogger("tool:get-users");
|
|
2008
1957
|
var getUsersTool = {
|
|
2009
1958
|
name: TOOL_NAMES.GET_USERS,
|
|
2010
1959
|
description: "Search for users by name, email, username, or account ID. Returns display name, email, account status, and account type. Supports pagination.",
|
|
@@ -2044,13 +1993,13 @@ async function handleGetUsers(input) {
|
|
|
2044
1993
|
try {
|
|
2045
1994
|
const validated = validateInput(GetUsersInputSchema, input);
|
|
2046
1995
|
if (validated.query) {
|
|
2047
|
-
|
|
1996
|
+
log8.info(`Searching users with query: "${validated.query}"...`);
|
|
2048
1997
|
} else if (validated.username) {
|
|
2049
|
-
|
|
1998
|
+
log8.info(`Searching for username: "${validated.username}"...`);
|
|
2050
1999
|
} else if (validated.accountId) {
|
|
2051
|
-
|
|
2000
|
+
log8.info(`Searching for account ID: "${validated.accountId}"...`);
|
|
2052
2001
|
} else {
|
|
2053
|
-
|
|
2002
|
+
log8.info("Getting all users...");
|
|
2054
2003
|
}
|
|
2055
2004
|
const getParams = {};
|
|
2056
2005
|
if (validated.query !== void 0) getParams.query = validated.query;
|
|
@@ -2059,16 +2008,16 @@ async function handleGetUsers(input) {
|
|
|
2059
2008
|
if (validated.startAt !== void 0) getParams.startAt = validated.startAt;
|
|
2060
2009
|
if (validated.maxResults !== void 0) getParams.maxResults = validated.maxResults;
|
|
2061
2010
|
const users = await getUsers(getParams);
|
|
2062
|
-
|
|
2011
|
+
log8.info(`Found ${users.length} user(s)`);
|
|
2063
2012
|
return formatUsersResponse(users);
|
|
2064
2013
|
} catch (error) {
|
|
2065
|
-
|
|
2014
|
+
log8.error("Error in handleGetUsers:", error);
|
|
2066
2015
|
return handleError(error);
|
|
2067
2016
|
}
|
|
2068
2017
|
}
|
|
2069
2018
|
|
|
2070
2019
|
// src/tools/get-priorities.ts
|
|
2071
|
-
var
|
|
2020
|
+
var log9 = createLogger("tool:get-priorities");
|
|
2072
2021
|
var getPrioritiesTool = {
|
|
2073
2022
|
name: TOOL_NAMES.GET_PRIORITIES,
|
|
2074
2023
|
description: "Retrieves available priorities (e.g., Highest, High, Medium, Low, Lowest). Returns IDs, names, and descriptions.",
|
|
@@ -2081,18 +2030,18 @@ var getPrioritiesTool = {
|
|
|
2081
2030
|
async function handleGetPriorities(input) {
|
|
2082
2031
|
try {
|
|
2083
2032
|
validateInput(GetPrioritiesInputSchema, input);
|
|
2084
|
-
|
|
2033
|
+
log9.info("Getting all priority levels...");
|
|
2085
2034
|
const priorities = await getPriorities();
|
|
2086
|
-
|
|
2035
|
+
log9.info(`Found ${priorities.length} priority level(s)`);
|
|
2087
2036
|
return formatPrioritiesResponse(priorities);
|
|
2088
2037
|
} catch (error) {
|
|
2089
|
-
|
|
2038
|
+
log9.error("Error in handleGetPriorities:", error);
|
|
2090
2039
|
return handleError(error);
|
|
2091
2040
|
}
|
|
2092
2041
|
}
|
|
2093
2042
|
|
|
2094
2043
|
// src/tools/get-statuses.ts
|
|
2095
|
-
var
|
|
2044
|
+
var log10 = createLogger("tool:get-statuses");
|
|
2096
2045
|
var getStatusesTool = {
|
|
2097
2046
|
name: TOOL_NAMES.GET_STATUSES,
|
|
2098
2047
|
description: "Retrieves available statuses (global or project-specific, e.g., To Do, In Progress, Done). Returns status categories and workflow information.",
|
|
@@ -2115,28 +2064,28 @@ async function handleGetStatuses(input) {
|
|
|
2115
2064
|
try {
|
|
2116
2065
|
const validated = validateInput(GetStatusesInputSchema, input);
|
|
2117
2066
|
if (validated.projectKey && validated.issueTypeId) {
|
|
2118
|
-
|
|
2067
|
+
log10.info(
|
|
2119
2068
|
`Getting statuses for project ${validated.projectKey} and issue type ${validated.issueTypeId}...`
|
|
2120
2069
|
);
|
|
2121
2070
|
} else if (validated.projectKey) {
|
|
2122
|
-
|
|
2071
|
+
log10.info(`Getting statuses for project ${validated.projectKey}...`);
|
|
2123
2072
|
} else {
|
|
2124
|
-
|
|
2073
|
+
log10.info("Getting global statuses...");
|
|
2125
2074
|
}
|
|
2126
2075
|
const getParams = {};
|
|
2127
2076
|
if (validated.projectKey !== void 0) getParams.projectKey = validated.projectKey;
|
|
2128
2077
|
if (validated.issueTypeId !== void 0) getParams.issueTypeId = validated.issueTypeId;
|
|
2129
2078
|
const statuses = await getStatuses(getParams);
|
|
2130
|
-
|
|
2079
|
+
log10.info(`Found ${statuses.length} status(es)`);
|
|
2131
2080
|
return formatStatusesResponse(statuses);
|
|
2132
2081
|
} catch (error) {
|
|
2133
|
-
|
|
2082
|
+
log10.error("Error in handleGetStatuses:", error);
|
|
2134
2083
|
return handleError(error);
|
|
2135
2084
|
}
|
|
2136
2085
|
}
|
|
2137
2086
|
|
|
2138
2087
|
// src/tools/create-issue.ts
|
|
2139
|
-
var
|
|
2088
|
+
var log11 = createLogger("tool:create-issue");
|
|
2140
2089
|
var createIssueTool = {
|
|
2141
2090
|
name: TOOL_NAMES.CREATE_ISSUE,
|
|
2142
2091
|
description: 'Creates a new Jira issue in the specified project. Supports setting issue type, priority, assignee, labels, components, and custom fields. Description accepts plain text and is auto-formatted to ADF: lines ending with ":" become headings, numbered lines create ordered lists, and URLs are linkified. For required custom fields, supply them via customFields (e.g., { "customfield_12345": { id: "..." } }). Returns the created issue with all details.',
|
|
@@ -2197,7 +2146,7 @@ var createIssueTool = {
|
|
|
2197
2146
|
async function handleCreateIssue(input) {
|
|
2198
2147
|
try {
|
|
2199
2148
|
const validated = validateInput(CreateIssueInputSchema, input);
|
|
2200
|
-
|
|
2149
|
+
log11.info(`Creating issue in project ${validated.projectKey}...`);
|
|
2201
2150
|
const createParams = {
|
|
2202
2151
|
projectKey: validated.projectKey,
|
|
2203
2152
|
summary: validated.summary,
|
|
@@ -2217,20 +2166,20 @@ async function handleCreateIssue(input) {
|
|
|
2217
2166
|
}
|
|
2218
2167
|
if (validated.returnIssue === false) {
|
|
2219
2168
|
const key = typeof issueOrKey === "string" ? issueOrKey : issueOrKey.key;
|
|
2220
|
-
|
|
2169
|
+
log11.info(`Created issue ${key}`);
|
|
2221
2170
|
return formatSuccessResponse(`Issue created: ${key}`);
|
|
2222
2171
|
}
|
|
2223
2172
|
const issue = issueOrKey;
|
|
2224
|
-
|
|
2173
|
+
log11.info(`Created issue ${issue.key}`);
|
|
2225
2174
|
return formatIssueResponse(issue);
|
|
2226
2175
|
} catch (error) {
|
|
2227
|
-
|
|
2176
|
+
log11.error("Error in handleCreateIssue:", error);
|
|
2228
2177
|
return handleError(error);
|
|
2229
2178
|
}
|
|
2230
2179
|
}
|
|
2231
2180
|
|
|
2232
2181
|
// src/tools/update-issue.ts
|
|
2233
|
-
var
|
|
2182
|
+
var log12 = createLogger("tool:update-issue");
|
|
2234
2183
|
var updateIssueTool = {
|
|
2235
2184
|
name: TOOL_NAMES.UPDATE_ISSUE,
|
|
2236
2185
|
description: 'Updates an existing Jira issue by its key. Supports updating summary, description, priority, assignee, labels, and components. Description accepts plain text and is auto-formatted to ADF: headings (lines ending with ":"), numbered/bullet lists, and links. Only specified fields will be updated.',
|
|
@@ -2279,7 +2228,7 @@ var updateIssueTool = {
|
|
|
2279
2228
|
async function handleUpdateIssue(input) {
|
|
2280
2229
|
try {
|
|
2281
2230
|
const validated = validateInput(UpdateIssueInputSchema, input);
|
|
2282
|
-
|
|
2231
|
+
log12.info(`Updating issue ${validated.issueKey}...`);
|
|
2283
2232
|
const updateParams = {};
|
|
2284
2233
|
if (validated.summary !== void 0) updateParams.summary = validated.summary;
|
|
2285
2234
|
if (validated.description !== void 0) updateParams.description = validated.description;
|
|
@@ -2289,20 +2238,20 @@ async function handleUpdateIssue(input) {
|
|
|
2289
2238
|
if (validated.components !== void 0) updateParams.components = validated.components;
|
|
2290
2239
|
await updateIssue(validated.issueKey, updateParams);
|
|
2291
2240
|
if (validated.returnIssue === false) {
|
|
2292
|
-
|
|
2241
|
+
log12.info(`Updated issue ${validated.issueKey}`);
|
|
2293
2242
|
return formatSuccessResponse(`Issue ${validated.issueKey} updated successfully`);
|
|
2294
2243
|
}
|
|
2295
2244
|
const updatedIssue = await getIssue(validated.issueKey);
|
|
2296
|
-
|
|
2245
|
+
log12.info(`Updated issue ${updatedIssue.key}`);
|
|
2297
2246
|
return formatIssueResponse(updatedIssue);
|
|
2298
2247
|
} catch (error) {
|
|
2299
|
-
|
|
2248
|
+
log12.error("Error in handleUpdateIssue:", error);
|
|
2300
2249
|
return handleError(error);
|
|
2301
2250
|
}
|
|
2302
2251
|
}
|
|
2303
2252
|
|
|
2304
2253
|
// src/tools/add-comment.ts
|
|
2305
|
-
var
|
|
2254
|
+
var log13 = createLogger("tool:add-comment");
|
|
2306
2255
|
var addCommentTool = {
|
|
2307
2256
|
name: TOOL_NAMES.ADD_COMMENT,
|
|
2308
2257
|
description: "Adds a comment to an issue. Supports visibility restrictions for groups or roles. Returns the created comment with author details and timestamp.",
|
|
@@ -2341,18 +2290,18 @@ var addCommentTool = {
|
|
|
2341
2290
|
async function handleAddComment(input) {
|
|
2342
2291
|
try {
|
|
2343
2292
|
const validated = validateInput(AddCommentInputSchema, input);
|
|
2344
|
-
|
|
2293
|
+
log13.info(`Adding comment to issue ${validated.issueKey}...`);
|
|
2345
2294
|
const comment = await addComment(validated.issueKey, validated.body, validated.visibility);
|
|
2346
|
-
|
|
2295
|
+
log13.info(`Added comment to ${validated.issueKey}`);
|
|
2347
2296
|
return formatCommentResponse(comment);
|
|
2348
2297
|
} catch (error) {
|
|
2349
|
-
|
|
2298
|
+
log13.error("Error in handleAddComment:", error);
|
|
2350
2299
|
return handleError(error);
|
|
2351
2300
|
}
|
|
2352
2301
|
}
|
|
2353
2302
|
|
|
2354
2303
|
// src/tools/get-project-info.ts
|
|
2355
|
-
var
|
|
2304
|
+
var log14 = createLogger("tool:get-project-info");
|
|
2356
2305
|
var getProjectInfoTool = {
|
|
2357
2306
|
name: TOOL_NAMES.GET_PROJECT_INFO,
|
|
2358
2307
|
description: "Retrieves detailed information about a project (components, versions, issue types, roles, insights). More comprehensive than the basic project list.",
|
|
@@ -2376,18 +2325,18 @@ var getProjectInfoTool = {
|
|
|
2376
2325
|
async function handleGetProjectInfo(input) {
|
|
2377
2326
|
try {
|
|
2378
2327
|
const validated = validateInput(GetProjectInfoInputSchema, input);
|
|
2379
|
-
|
|
2328
|
+
log14.info(`Getting detailed project information for ${validated.projectKey}...`);
|
|
2380
2329
|
const project = await getProjectDetails(validated.projectKey, validated.expand);
|
|
2381
|
-
|
|
2330
|
+
log14.info(`Retrieved project details for ${project.key}`);
|
|
2382
2331
|
return formatProjectDetailsResponse(project);
|
|
2383
2332
|
} catch (error) {
|
|
2384
|
-
|
|
2333
|
+
log14.error("Error in handleGetProjectInfo:", error);
|
|
2385
2334
|
return handleError(error);
|
|
2386
2335
|
}
|
|
2387
2336
|
}
|
|
2388
2337
|
|
|
2389
2338
|
// src/tools/create-subtask.ts
|
|
2390
|
-
var
|
|
2339
|
+
var log15 = createLogger("tool:create-subtask");
|
|
2391
2340
|
var createSubtaskTool = {
|
|
2392
2341
|
name: TOOL_NAMES.CREATE_SUBTASK,
|
|
2393
2342
|
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.",
|
|
@@ -2434,7 +2383,7 @@ var createSubtaskTool = {
|
|
|
2434
2383
|
async function handleCreateSubtask(input) {
|
|
2435
2384
|
try {
|
|
2436
2385
|
const validated = validateInput(CreateSubtaskInputSchema, input);
|
|
2437
|
-
|
|
2386
|
+
log15.info(`Creating subtask under parent issue ${validated.parentIssueKey}...`);
|
|
2438
2387
|
const subtaskParams = {
|
|
2439
2388
|
summary: validated.summary
|
|
2440
2389
|
};
|
|
@@ -2444,16 +2393,16 @@ async function handleCreateSubtask(input) {
|
|
|
2444
2393
|
if (validated.labels !== void 0) subtaskParams.labels = validated.labels;
|
|
2445
2394
|
if (validated.components !== void 0) subtaskParams.components = validated.components;
|
|
2446
2395
|
const subtask = await createSubtask(validated.parentIssueKey, subtaskParams);
|
|
2447
|
-
|
|
2396
|
+
log15.info(`Created subtask ${subtask.key}`);
|
|
2448
2397
|
return formatIssueResponse(subtask);
|
|
2449
2398
|
} catch (error) {
|
|
2450
|
-
|
|
2399
|
+
log15.error("Error in handleCreateSubtask:", error);
|
|
2451
2400
|
return handleError(error);
|
|
2452
2401
|
}
|
|
2453
2402
|
}
|
|
2454
2403
|
|
|
2455
2404
|
// src/tools/get-create-meta.ts
|
|
2456
|
-
var
|
|
2405
|
+
var log16 = createLogger("tool:get-create-meta");
|
|
2457
2406
|
var getCreateMetaTool = {
|
|
2458
2407
|
name: TOOL_NAMES.GET_CREATE_META,
|
|
2459
2408
|
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.",
|
|
@@ -2475,7 +2424,7 @@ var getCreateMetaTool = {
|
|
|
2475
2424
|
async function handleGetCreateMeta(input) {
|
|
2476
2425
|
try {
|
|
2477
2426
|
const validated = validateInput(GetCreateMetaInputSchema, input);
|
|
2478
|
-
|
|
2427
|
+
log16.info(`Getting create metadata for project ${validated.projectKey}...`);
|
|
2479
2428
|
const options = {
|
|
2480
2429
|
projectKeys: [validated.projectKey],
|
|
2481
2430
|
expand: "projects.issuetypes.fields"
|
|
@@ -2484,16 +2433,16 @@ async function handleGetCreateMeta(input) {
|
|
|
2484
2433
|
options.issueTypeNames = [validated.issueTypeName];
|
|
2485
2434
|
}
|
|
2486
2435
|
const meta = await getCreateMeta(options);
|
|
2487
|
-
|
|
2436
|
+
log16.info(`Retrieved create metadata for ${validated.projectKey}`);
|
|
2488
2437
|
return formatCreateMetaResponse(meta);
|
|
2489
2438
|
} catch (error) {
|
|
2490
|
-
|
|
2439
|
+
log16.error("Error in handleGetCreateMeta:", error);
|
|
2491
2440
|
return handleError(error);
|
|
2492
2441
|
}
|
|
2493
2442
|
}
|
|
2494
2443
|
|
|
2495
2444
|
// src/tools/get-custom-fields.ts
|
|
2496
|
-
var
|
|
2445
|
+
var log17 = createLogger("tool:get-custom-fields");
|
|
2497
2446
|
var getCustomFieldsTool = {
|
|
2498
2447
|
name: TOOL_NAMES.GET_CUSTOM_FIELDS,
|
|
2499
2448
|
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.",
|
|
@@ -2512,12 +2461,12 @@ async function handleGetCustomFields(input) {
|
|
|
2512
2461
|
try {
|
|
2513
2462
|
const validated = validateInput(GetCustomFieldsInputSchema, input);
|
|
2514
2463
|
const projectMsg = validated.projectKey ? ` for project ${validated.projectKey}` : "";
|
|
2515
|
-
|
|
2464
|
+
log17.info(`Getting custom fields${projectMsg}...`);
|
|
2516
2465
|
const fields = await getFields();
|
|
2517
|
-
|
|
2466
|
+
log17.info(`Retrieved ${fields.filter((f) => f.custom).length} custom fields`);
|
|
2518
2467
|
return formatCustomFieldsResponse(fields, validated.projectKey);
|
|
2519
2468
|
} catch (error) {
|
|
2520
|
-
|
|
2469
|
+
log17.error("Error in handleGetCustomFields:", error);
|
|
2521
2470
|
return handleError(error);
|
|
2522
2471
|
}
|
|
2523
2472
|
}
|
|
@@ -2530,7 +2479,7 @@ if (process.env.NODE_ENV !== "production") {
|
|
|
2530
2479
|
} catch {
|
|
2531
2480
|
}
|
|
2532
2481
|
}
|
|
2533
|
-
var
|
|
2482
|
+
var log18 = createLogger("server");
|
|
2534
2483
|
var toolHandlers = /* @__PURE__ */ new Map([
|
|
2535
2484
|
[TOOL_NAMES.GET_VISIBLE_PROJECTS, handleGetVisibleProjects],
|
|
2536
2485
|
[TOOL_NAMES.GET_ISSUE, handleGetIssue],
|
|
@@ -2634,7 +2583,7 @@ async function main() {
|
|
|
2634
2583
|
console.error("\u{1F680} Jira MCP server running on stdio");
|
|
2635
2584
|
}
|
|
2636
2585
|
main().catch((error) => {
|
|
2637
|
-
|
|
2586
|
+
log18.error("Fatal error:", error);
|
|
2638
2587
|
process.exit(1);
|
|
2639
2588
|
});
|
|
2640
2589
|
//# sourceMappingURL=index.js.map
|