@neosamon/jira-mcp-server 0.1.0 → 0.2.0
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/LICENSE +21 -0
- package/README.md +74 -24
- package/build/index.js +218 -2
- package/package.json +9 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 wuyan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
## 功能
|
|
6
6
|
|
|
7
7
|
- **查询 Issue**: 通过 Issue Key 获取 Issue 的详细信息,包括类型、状态、优先级、描述和评论
|
|
8
|
+
- **搜索 Issues**: 使用 JQL (Jira Query Language) 批量搜索 Issues
|
|
8
9
|
- **创建评论**: 为指定的 Issue 添加评论
|
|
10
|
+
- **字段发现**: 探测 Issue 的所有可用字段,用于配置自定义字段映射
|
|
11
|
+
- **自定义字段**: 支持通过环境变量配置,提取 Jira 自定义字段
|
|
9
12
|
|
|
10
13
|
## 环境变量配置
|
|
11
14
|
|
|
@@ -48,35 +51,48 @@ JIRA_AUTH_TYPE 环境变量
|
|
|
48
51
|
3. 点击 **Create API token**
|
|
49
52
|
4. 复制生成的 Token 并设置为 `JIRA_API_TOKEN` 环境变量
|
|
50
53
|
|
|
54
|
+
### 自定义字段配置(可选)
|
|
55
|
+
|
|
56
|
+
Jira 实例通常包含自定义字段(如测试步骤、预期结果、代码分支等)。要提取这些字段,需要配置字段映射。
|
|
57
|
+
|
|
58
|
+
#### 配置步骤
|
|
59
|
+
|
|
60
|
+
1. **使用字段发现工具**找出目标字段的 ID:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
"使用 get_issue_fields 工具查看 Issue PROJ-123 的所有字段"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
2. **配置环境变量**将字段名映射到字段 ID:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
export JIRA_FIELD_TEST_STEP="customfield_10206"
|
|
70
|
+
export JIRA_FIELD_EXPECTED_RESULT="customfield_10208"
|
|
71
|
+
export JIRA_FIELD_ACTUAL_RESULT="customfield_10210"
|
|
72
|
+
export JIRA_FIELD_CODE_BRANCH="customfield_10300"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
3. **重启服务器**,`get_issue` 工具将自动包含配置的自定义字段
|
|
76
|
+
|
|
77
|
+
#### 字段映射规则
|
|
78
|
+
|
|
79
|
+
- 环境变量格式:`JIRA_FIELD_<NAME>=<field_id>`
|
|
80
|
+
- 字段名会自动转换为驼峰命名(如 `JIRA_FIELD_TEST_STEP` → `testStep`)
|
|
81
|
+
- 未配置的字段不会出现在输出中
|
|
82
|
+
- 字段不存在或为空时显示 `N/A`
|
|
83
|
+
|
|
51
84
|
## 安装
|
|
52
85
|
|
|
53
86
|
### 通过 npm 全局安装
|
|
54
87
|
|
|
55
88
|
```bash
|
|
56
|
-
npm install -g jira-mcp-server
|
|
89
|
+
npm install -g @neosamon/jira-mcp-server
|
|
57
90
|
```
|
|
58
91
|
|
|
59
92
|
### 使用 npx 运行(无需安装)
|
|
60
93
|
|
|
61
94
|
```bash
|
|
62
|
-
npx jira-mcp-server
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### 从源码构建
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
# 克隆仓库
|
|
69
|
-
git clone <repository-url>
|
|
70
|
-
cd jira-mcp-server-ts
|
|
71
|
-
|
|
72
|
-
# 安装依赖
|
|
73
|
-
npm install
|
|
74
|
-
|
|
75
|
-
# 构建
|
|
76
|
-
npm run build
|
|
77
|
-
|
|
78
|
-
# 运行
|
|
79
|
-
node build/index.js
|
|
95
|
+
npx @neosamon/jira-mcp-server
|
|
80
96
|
```
|
|
81
97
|
|
|
82
98
|
## 使用方法
|
|
@@ -90,7 +106,7 @@ export JIRA_BASE_URL="https://your-jira.example.com"
|
|
|
90
106
|
export JIRA_USERNAME="your-email@example.com"
|
|
91
107
|
export JIRA_API_TOKEN="your-api-token"
|
|
92
108
|
|
|
93
|
-
npx jira-mcp-server
|
|
109
|
+
npx @neosamon/jira-mcp-server
|
|
94
110
|
```
|
|
95
111
|
|
|
96
112
|
#### 使用密码认证
|
|
@@ -100,7 +116,7 @@ export JIRA_BASE_URL="https://your-jira.example.com"
|
|
|
100
116
|
export JIRA_USERNAME="your-email@example.com"
|
|
101
117
|
export JIRA_PASSWORD="your-password"
|
|
102
118
|
|
|
103
|
-
npx jira-mcp-server
|
|
119
|
+
npx @neosamon/jira-mcp-server
|
|
104
120
|
```
|
|
105
121
|
|
|
106
122
|
#### 显式指定认证方式
|
|
@@ -135,7 +151,8 @@ export JIRA_PASSWORD="your-password"
|
|
|
135
151
|
{
|
|
136
152
|
"mcpServers": {
|
|
137
153
|
"jira": {
|
|
138
|
-
"command": "
|
|
154
|
+
"command": "npx",
|
|
155
|
+
"args": ["@neosamon/jira-mcp-server"],
|
|
139
156
|
"env": {
|
|
140
157
|
"JIRA_BASE_URL": "https://your-jira.example.com",
|
|
141
158
|
"JIRA_USERNAME": "your-email@example.com",
|
|
@@ -152,7 +169,8 @@ export JIRA_PASSWORD="your-password"
|
|
|
152
169
|
{
|
|
153
170
|
"mcpServers": {
|
|
154
171
|
"jira": {
|
|
155
|
-
"command": "
|
|
172
|
+
"command": "npx",
|
|
173
|
+
"args": ["@neosamon/jira-mcp-server"],
|
|
156
174
|
"env": {
|
|
157
175
|
"JIRA_BASE_URL": "https://your-jira.example.com",
|
|
158
176
|
"JIRA_USERNAME": "your-email@example.com",
|
|
@@ -163,15 +181,47 @@ export JIRA_PASSWORD="your-password"
|
|
|
163
181
|
}
|
|
164
182
|
```
|
|
165
183
|
|
|
166
|
-
|
|
184
|
+
## Claude CLI 配置
|
|
185
|
+
|
|
186
|
+
### 基于项目添加
|
|
187
|
+
```bash
|
|
188
|
+
claude mcp add jira --transport stdio \
|
|
189
|
+
--env JIRA_BASE_URL="https://your-jira.example.com" \
|
|
190
|
+
--env JIRA_USERNAME="your-email@example.com" \
|
|
191
|
+
--env JIRA_PASSWORD="your-password" \
|
|
192
|
+
-- npx @neosamon/jira-mcp-server
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### 全局添加
|
|
196
|
+
```bash
|
|
197
|
+
claude mcp add jira --scope user --transport stdio \
|
|
198
|
+
--env JIRA_BASE_URL="https://your-jira.example.com" \
|
|
199
|
+
--env JIRA_USERNAME="your-email@example.com" \
|
|
200
|
+
--env JIRA_PASSWORD="your-password" \
|
|
201
|
+
-- npx @neosamon/jira-mcp-server
|
|
202
|
+
```
|
|
167
203
|
|
|
168
204
|
## 使用示例
|
|
169
205
|
|
|
170
206
|
配置完成后,您可以在 Claude 中使用以下命令:
|
|
171
207
|
|
|
208
|
+
### 基本功能
|
|
209
|
+
|
|
172
210
|
- "查询 Jira Issue PROJ-123 的详情"
|
|
173
211
|
- "为 PROJ-123 添加评论:已完成代码审查"
|
|
174
212
|
|
|
213
|
+
### 字段发现
|
|
214
|
+
|
|
215
|
+
- "使用 get_issue_fields 工具查看 Issue PROJ-123 的所有可用字段"
|
|
216
|
+
- "列出 PROJ-123 的字段,帮我找出测试步骤对应的字段 ID"
|
|
217
|
+
|
|
218
|
+
### JQL 搜索
|
|
219
|
+
|
|
220
|
+
- "搜索分配给我的所有进行中任务"
|
|
221
|
+
- "查找项目 PROJ 中所有高优先级的 Bug"
|
|
222
|
+
- "列出本周创建的所有 Issues"
|
|
223
|
+
- "搜索状态为 Open 且优先级为 High 的 Issues"
|
|
224
|
+
|
|
175
225
|
## 兼容性
|
|
176
226
|
|
|
177
227
|
- **Node.js 版本**: 18 或更高版本
|
package/build/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
4
|
import { z } from "zod";
|
|
@@ -35,6 +36,21 @@ function loadConfig() {
|
|
|
35
36
|
}
|
|
36
37
|
return { baseURL, username, apiToken, password, authType };
|
|
37
38
|
}
|
|
39
|
+
// 加载自定义字段映射配置
|
|
40
|
+
function loadFieldMapping() {
|
|
41
|
+
const mapping = {};
|
|
42
|
+
const prefix = "JIRA_FIELD_";
|
|
43
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
44
|
+
if (key.startsWith(prefix) && value) {
|
|
45
|
+
// 将 JIRA_FIELD_TEST_STEP 转换为 testStep (驼峰命名)
|
|
46
|
+
const fieldName = key.substring(prefix.length)
|
|
47
|
+
.toLowerCase()
|
|
48
|
+
.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
49
|
+
mapping[fieldName] = value;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return mapping;
|
|
53
|
+
}
|
|
38
54
|
// ==================== HTTP 客户端 ====================
|
|
39
55
|
// 根据 authType 确定使用哪种认证凭据
|
|
40
56
|
function getAuthCredential(config) {
|
|
@@ -90,13 +106,58 @@ async function addComment(config, issueKey, body) {
|
|
|
90
106
|
});
|
|
91
107
|
}
|
|
92
108
|
// ==================== 输出格式化函数 ====================
|
|
109
|
+
/**
|
|
110
|
+
* 格式化字段值用于显示
|
|
111
|
+
* 根据值的类型采用不同的展示策略
|
|
112
|
+
*/
|
|
113
|
+
function formatFieldValue(value) {
|
|
114
|
+
// null 或 undefined
|
|
115
|
+
if (value === null || value === undefined) {
|
|
116
|
+
return "N/A";
|
|
117
|
+
}
|
|
118
|
+
// 字符串类型 - 截断过长内容
|
|
119
|
+
if (typeof value === "string") {
|
|
120
|
+
if (value.length <= 50) {
|
|
121
|
+
return value;
|
|
122
|
+
}
|
|
123
|
+
return `${value.substring(0, 50)}...`;
|
|
124
|
+
}
|
|
125
|
+
// 数组类型
|
|
126
|
+
if (Array.isArray(value)) {
|
|
127
|
+
return `[Array] (${value.length} items)`;
|
|
128
|
+
}
|
|
129
|
+
// 对象类型
|
|
130
|
+
if (typeof value === "object") {
|
|
131
|
+
// 提取 name 属性(如用户、状态等)
|
|
132
|
+
if ("name" in value && typeof value.name === "string") {
|
|
133
|
+
return value.name;
|
|
134
|
+
}
|
|
135
|
+
// 提取 value 属性(如选项字段)
|
|
136
|
+
if ("value" in value && typeof value.value === "string") {
|
|
137
|
+
return value.value;
|
|
138
|
+
}
|
|
139
|
+
// 其他复杂对象 - JSON 序列化
|
|
140
|
+
try {
|
|
141
|
+
const jsonStr = JSON.stringify(value);
|
|
142
|
+
if (jsonStr.length <= 50) {
|
|
143
|
+
return jsonStr;
|
|
144
|
+
}
|
|
145
|
+
return `${jsonStr.substring(0, 50)}...`;
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return "[Object]";
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// 数字、布尔等基本类型
|
|
152
|
+
return String(value);
|
|
153
|
+
}
|
|
93
154
|
function formatComment(comment) {
|
|
94
155
|
const author = comment.author.displayName;
|
|
95
156
|
const created = comment.created;
|
|
96
157
|
const commentBody = comment.body || "(无内容)";
|
|
97
158
|
return `**${author}** - ${created}\n${commentBody}\n`;
|
|
98
159
|
}
|
|
99
|
-
function formatIssue(issue) {
|
|
160
|
+
function formatIssue(issue, fieldMapping) {
|
|
100
161
|
const output = [];
|
|
101
162
|
// 标题
|
|
102
163
|
output.push(`## Issue: ${issue.key}\n`);
|
|
@@ -125,6 +186,16 @@ function formatIssue(issue) {
|
|
|
125
186
|
output.push(`**描述**:\n${descText}\n`);
|
|
126
187
|
}
|
|
127
188
|
}
|
|
189
|
+
// 自定义字段
|
|
190
|
+
if (fieldMapping && Object.keys(fieldMapping).length > 0) {
|
|
191
|
+
output.push(`**自定义字段**:\n`);
|
|
192
|
+
for (const [fieldName, fieldId] of Object.entries(fieldMapping)) {
|
|
193
|
+
const fieldValue = issue.fields[fieldId];
|
|
194
|
+
const displayValue = formatFieldValue(fieldValue);
|
|
195
|
+
output.push(`- **${fieldName}**: ${displayValue}\n`);
|
|
196
|
+
}
|
|
197
|
+
output.push(`\n`);
|
|
198
|
+
}
|
|
128
199
|
// 评论
|
|
129
200
|
if (issue.fields.comment?.comments && issue.fields.comment.comments.length > 0) {
|
|
130
201
|
const allComments = issue.fields.comment.comments;
|
|
@@ -168,6 +239,7 @@ server.registerTool("get_issue", {
|
|
|
168
239
|
},
|
|
169
240
|
}, async ({ issueKey }) => {
|
|
170
241
|
const config = loadConfig();
|
|
242
|
+
const fieldMapping = loadFieldMapping();
|
|
171
243
|
const issue = await getIssue(config, issueKey);
|
|
172
244
|
if (!issue) {
|
|
173
245
|
return {
|
|
@@ -183,7 +255,7 @@ server.registerTool("get_issue", {
|
|
|
183
255
|
content: [
|
|
184
256
|
{
|
|
185
257
|
type: "text",
|
|
186
|
-
text: formatIssue(issue),
|
|
258
|
+
text: formatIssue(issue, fieldMapping),
|
|
187
259
|
},
|
|
188
260
|
],
|
|
189
261
|
};
|
|
@@ -229,6 +301,150 @@ server.registerTool("add_comment", {
|
|
|
229
301
|
],
|
|
230
302
|
};
|
|
231
303
|
});
|
|
304
|
+
// 注册 get_issue_fields 工具
|
|
305
|
+
server.registerTool("get_issue_fields", {
|
|
306
|
+
title: "Get Issue Fields",
|
|
307
|
+
description: "Get all available fields for a Jira Issue. This helps discover custom field IDs for configuration.",
|
|
308
|
+
inputSchema: {
|
|
309
|
+
issueKey: z.string().describe("Jira Issue Key (e.g., PROJ-123)"),
|
|
310
|
+
},
|
|
311
|
+
}, async ({ issueKey }) => {
|
|
312
|
+
const config = loadConfig();
|
|
313
|
+
const issue = await getIssue(config, issueKey);
|
|
314
|
+
if (!issue) {
|
|
315
|
+
return {
|
|
316
|
+
content: [
|
|
317
|
+
{
|
|
318
|
+
type: "text",
|
|
319
|
+
text: `错误: 无法连接到 Jira 服务器或 Issue '${issueKey}' 不存在`,
|
|
320
|
+
},
|
|
321
|
+
],
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
// 遍历所有字段并格式化
|
|
325
|
+
const fieldsList = [];
|
|
326
|
+
for (const [fieldId, fieldValue] of Object.entries(issue.fields)) {
|
|
327
|
+
fieldsList.push({
|
|
328
|
+
fieldId,
|
|
329
|
+
valuePreview: formatFieldValue(fieldValue),
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
// 格式化输出
|
|
333
|
+
const output = `## Issue ${issueKey} - 字段列表\n\n` +
|
|
334
|
+
`共找到 ${fieldsList.length} 个字段:\n\n` +
|
|
335
|
+
fieldsList.map(f => `- **${f.fieldId}**: ${f.valuePreview}`).join("\n");
|
|
336
|
+
return {
|
|
337
|
+
content: [
|
|
338
|
+
{
|
|
339
|
+
type: "text",
|
|
340
|
+
text: output,
|
|
341
|
+
},
|
|
342
|
+
],
|
|
343
|
+
};
|
|
344
|
+
});
|
|
345
|
+
// 注册 search_issues 工具
|
|
346
|
+
server.registerTool("search_issues", {
|
|
347
|
+
title: "Search Issues with JQL",
|
|
348
|
+
description: "Search for Jira Issues using JQL (Jira Query Language). Returns a list of matching Issues with Key, Summary, and Status.",
|
|
349
|
+
inputSchema: {
|
|
350
|
+
jql: z.string().describe("JQL query string (e.g., project = PROJ AND status = 'In Progress')"),
|
|
351
|
+
maxResults: z.number().optional().describe("Maximum number of results to return (default: 50, max: 100)"),
|
|
352
|
+
},
|
|
353
|
+
}, async ({ jql, maxResults = 50 }) => {
|
|
354
|
+
// 参数验证
|
|
355
|
+
if (!jql || jql.trim().length === 0) {
|
|
356
|
+
return {
|
|
357
|
+
content: [
|
|
358
|
+
{
|
|
359
|
+
type: "text",
|
|
360
|
+
text: "错误: JQL 查询不能为空",
|
|
361
|
+
},
|
|
362
|
+
],
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
// 验证 maxResults
|
|
366
|
+
const limit = Math.min(Math.max(1, Math.floor(maxResults)), 100);
|
|
367
|
+
if (limit !== maxResults) {
|
|
368
|
+
return {
|
|
369
|
+
content: [
|
|
370
|
+
{
|
|
371
|
+
type: "text",
|
|
372
|
+
text: `错误: maxResults 必须是 1-100 之间的整数,已请求: ${maxResults}`,
|
|
373
|
+
},
|
|
374
|
+
],
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
const config = loadConfig();
|
|
378
|
+
// 调用 Jira API 搜索
|
|
379
|
+
const credential = getAuthCredential(config);
|
|
380
|
+
const authHeader = getBasicAuthHeader(config.username, credential);
|
|
381
|
+
try {
|
|
382
|
+
const url = new URL(`${config.baseURL}/rest/api/2/search`);
|
|
383
|
+
url.searchParams.set("jql", jql);
|
|
384
|
+
url.searchParams.set("maxResults", String(limit));
|
|
385
|
+
url.searchParams.set("fields", "key,summary,status");
|
|
386
|
+
const searchResponse = await fetch(url.toString(), {
|
|
387
|
+
headers: {
|
|
388
|
+
Authorization: authHeader,
|
|
389
|
+
Accept: "application/json",
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
if (!searchResponse.ok) {
|
|
393
|
+
const errorText = await searchResponse.text();
|
|
394
|
+
return {
|
|
395
|
+
content: [
|
|
396
|
+
{
|
|
397
|
+
type: "text",
|
|
398
|
+
text: `Jira 查询失败: ${searchResponse.status}\n${errorText}`,
|
|
399
|
+
},
|
|
400
|
+
],
|
|
401
|
+
isError: true,
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
const data = await searchResponse.json();
|
|
405
|
+
const issues = data.issues || [];
|
|
406
|
+
// 格式化结果
|
|
407
|
+
if (issues.length === 0) {
|
|
408
|
+
return {
|
|
409
|
+
content: [
|
|
410
|
+
{
|
|
411
|
+
type: "text",
|
|
412
|
+
text: `未找到匹配的 Issues\n\nJQL: ${jql}`,
|
|
413
|
+
},
|
|
414
|
+
],
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
const total = data.total || issues.length;
|
|
418
|
+
const output = `## 搜索结果\n\n` +
|
|
419
|
+
`**JQL**: ${jql}\n` +
|
|
420
|
+
`**找到**: ${total} 个 Issues (显示 ${issues.length} 个)\n\n` +
|
|
421
|
+
issues.map((issue) => {
|
|
422
|
+
const key = issue.key;
|
|
423
|
+
const summary = issue.fields?.summary || "无摘要";
|
|
424
|
+
const status = issue.fields?.status?.name || "未知";
|
|
425
|
+
return `- **${key}**: ${summary} [${status}]`;
|
|
426
|
+
}).join("\n");
|
|
427
|
+
return {
|
|
428
|
+
content: [
|
|
429
|
+
{
|
|
430
|
+
type: "text",
|
|
431
|
+
text: output,
|
|
432
|
+
},
|
|
433
|
+
],
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
return {
|
|
438
|
+
content: [
|
|
439
|
+
{
|
|
440
|
+
type: "text",
|
|
441
|
+
text: `搜索失败: ${error instanceof Error ? error.message : String(error)}`,
|
|
442
|
+
},
|
|
443
|
+
],
|
|
444
|
+
isError: true,
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
});
|
|
232
448
|
// ==================== 服务器启动 ====================
|
|
233
449
|
async function main() {
|
|
234
450
|
// 加载并验证配置
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neosamon/jira-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Jira MCP Server - Model Context Protocol server for Jira integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"jira-mcp-server": "./build/index.js"
|
|
9
9
|
},
|
|
10
|
-
"files": [
|
|
10
|
+
"files": [
|
|
11
|
+
"build"
|
|
12
|
+
],
|
|
11
13
|
"engines": {
|
|
12
14
|
"node": ">=18"
|
|
13
15
|
},
|
|
@@ -15,7 +17,11 @@
|
|
|
15
17
|
"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
|
|
16
18
|
"prepublishOnly": "npm run build"
|
|
17
19
|
},
|
|
18
|
-
"keywords": [
|
|
20
|
+
"keywords": [
|
|
21
|
+
"mcp",
|
|
22
|
+
"jira",
|
|
23
|
+
"model-context-protocol"
|
|
24
|
+
],
|
|
19
25
|
"author": "",
|
|
20
26
|
"license": "MIT",
|
|
21
27
|
"dependencies": {
|