@zzp123/mcp-zentao 1.10.0 → 1.11.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/CHANGELOG.md CHANGED
@@ -5,6 +5,41 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.11.0] - 2025-11-07
9
+
10
+ ### Added
11
+ - **完整的 Bug 状态筛选支持** ✨
12
+ - 扩展 `BugStatus` 类型,新增 16 种状态筛选类型
13
+ - 支持所有禅道官方 API 的状态筛选:assigntome、openedbyme、resolvedbyme、assignedbyme、assigntonull、unconfirmed、unclosed、unresolved、toclosed、postponedbugs、longlifebugs、overduebugs、review、feedback、needconfirm、bysearch
14
+ - MCP 工具现在提供完整的 20 种状态选项供选择
15
+
16
+ - **分支筛选功能** 🌿
17
+ - 为 `getMyBugs` 和 `getProductBugs` 添加 `branch` 参数
18
+ - 支持 'all'(所有分支)、'0'(主干分支)、分支ID
19
+ - 默认值为 'all',符合禅道官方 API 规范
20
+
21
+ ### Changed
22
+ - **重构 Bug 列表 API 参数** 🔄
23
+ - 移除 `onlyAssignedToMe` 参数,改用更灵活的 `status='assigntome'`
24
+ - 调整参数顺序:`status, productId, page, limit, branch, order`
25
+ - 优化参数构建逻辑,确保与禅道官方 API 完全一致
26
+
27
+ ### Improved
28
+ - **API 文档完善**
29
+ - 为 `getMyBugs` 和 `getProductBugs` 添加详细的 JSDoc 注释
30
+ - 更新工具描述,明确说明支持的状态筛选类型
31
+ - 参数说明更加清晰,包含默认值和示例
32
+
33
+ - **更好的用户体验**
34
+ - MCP 工具提供完整的状态枚举,IDE 可以自动补全
35
+ - 所有状态选项都有中文注释说明
36
+ - 更符合禅道用户的使用习惯
37
+
38
+ ### Technical
39
+ - 完全符合禅道官方 Bug 列表 API 文档规范
40
+ - 支持所有官方 API 参数:branch、status、order、limit、page
41
+ - 默认值与官方 API 保持一致
42
+
8
43
  ## [1.10.0] - 2025-11-07
9
44
 
10
45
  ### Fixed
@@ -9,13 +9,35 @@ export declare class ZentaoAPI {
9
9
  getMyTasks(status?: TaskStatus): Promise<Task[]>;
10
10
  getTaskDetail(taskId: number): Promise<Task>;
11
11
  getProducts(): Promise<Product[]>;
12
- getMyBugs(status?: BugStatus, productId?: number, page?: number, limit?: number, onlyAssignedToMe?: boolean, order?: string): Promise<{
12
+ /**
13
+ * 获取 Bug 列表
14
+ *
15
+ * @param status Bug状态筛选(支持多种状态,详见BugStatus类型)
16
+ * @param productId 产品ID(可选,默认使用第二个产品)
17
+ * @param page 页码(从1开始,默认1)
18
+ * @param limit 每页数量(默认20,最大100)
19
+ * @param branch 分支筛选('all'所有分支/'0'主干/分支ID,默认'all')
20
+ * @param order 排序字段(如:'id_desc'、'pri_desc'等,默认'id_desc')
21
+ * @returns Promise<Bug列表及分页信息>
22
+ */
23
+ getMyBugs(status?: BugStatus, productId?: number, page?: number, limit?: number, branch?: string, order?: string): Promise<{
13
24
  page: number;
14
25
  total: number;
15
26
  limit: number;
16
27
  bugs: Bug[];
17
28
  }>;
18
- getProductBugs(productId: number, page?: number, limit?: number, status?: BugStatus, order?: string): Promise<{
29
+ /**
30
+ * 获取产品 Bug 列表
31
+ *
32
+ * @param productId 产品ID(必填)
33
+ * @param page 页码(从1开始,默认1)
34
+ * @param limit 每页数量(默认20,最大100)
35
+ * @param status Bug状态筛选(支持多种状态,详见BugStatus类型)
36
+ * @param branch 分支筛选('all'所有分支/'0'主干/分支ID,默认'all')
37
+ * @param order 排序字段(如:'id_desc'、'pri_desc'等,默认'id_desc')
38
+ * @returns Promise<Bug列表及分页信息>
39
+ */
40
+ getProductBugs(productId: number, page?: number, limit?: number, status?: BugStatus, branch?: string, order?: string): Promise<{
19
41
  page: number;
20
42
  total: number;
21
43
  limit: number;
@@ -111,7 +111,18 @@ export class ZentaoAPI {
111
111
  throw error;
112
112
  }
113
113
  }
114
- async getMyBugs(status, productId, page, limit, onlyAssignedToMe = false, order) {
114
+ /**
115
+ * 获取 Bug 列表
116
+ *
117
+ * @param status Bug状态筛选(支持多种状态,详见BugStatus类型)
118
+ * @param productId 产品ID(可选,默认使用第二个产品)
119
+ * @param page 页码(从1开始,默认1)
120
+ * @param limit 每页数量(默认20,最大100)
121
+ * @param branch 分支筛选('all'所有分支/'0'主干/分支ID,默认'all')
122
+ * @param order 排序字段(如:'id_desc'、'pri_desc'等,默认'id_desc')
123
+ * @returns Promise<Bug列表及分页信息>
124
+ */
125
+ async getMyBugs(status, productId, page, limit, branch, order) {
115
126
  if (!productId) {
116
127
  // 如果没有提供产品ID,获取第二个可用的产品(索引为1)
117
128
  const products = await this.getProducts();
@@ -125,22 +136,20 @@ export class ZentaoAPI {
125
136
  // 默认每页20条,最多100条
126
137
  const finalLimit = limit ? Math.min(limit, 100) : 20;
127
138
  const finalPage = page || 1;
139
+ const finalBranch = branch || 'all';
140
+ const finalOrder = order || 'id_desc';
128
141
  // 构建查询参数
129
142
  const queryParams = new URLSearchParams();
130
- // 如果需要只获取分配给我的Bug,使用 assigntome 状态
131
- if (onlyAssignedToMe) {
132
- queryParams.append('status', 'assigntome');
133
- }
134
- else if (status && status !== 'all') {
135
- queryParams.append('status', status);
136
- }
143
+ queryParams.append('branch', finalBranch);
137
144
  queryParams.append('page', finalPage.toString());
138
145
  queryParams.append('limit', finalLimit.toString());
139
- // 添加排序参数,默认按ID降序
140
- const finalOrder = order || 'id_desc';
141
146
  queryParams.append('order', finalOrder);
147
+ // 添加状态筛选
148
+ if (status && status !== 'all') {
149
+ queryParams.append('status', status);
150
+ }
142
151
  try {
143
- console.log(`正在获取产品 ${productId} 的Bug列表,参数: status=${onlyAssignedToMe ? 'assigntome' : (status || 'all')}, page=${finalPage}, limit=${finalLimit}, order=${finalOrder}`);
152
+ console.log(`正在获取产品 ${productId} 的Bug列表,参数: status=${status || 'all'}, branch=${finalBranch}, page=${finalPage}, limit=${finalLimit}, order=${finalOrder}`);
144
153
  const response = await this.request('GET', `/products/${productId}/bugs?${queryParams.toString()}`);
145
154
  console.log(`Bug列表响应: 获取到 ${response.bugs?.length || 0} 条数据`);
146
155
  if (Array.isArray(response)) {
@@ -169,23 +178,33 @@ export class ZentaoAPI {
169
178
  throw error;
170
179
  }
171
180
  }
172
- async getProductBugs(productId, page, limit, status, order) {
181
+ /**
182
+ * 获取产品 Bug 列表
183
+ *
184
+ * @param productId 产品ID(必填)
185
+ * @param page 页码(从1开始,默认1)
186
+ * @param limit 每页数量(默认20,最大100)
187
+ * @param status Bug状态筛选(支持多种状态,详见BugStatus类型)
188
+ * @param branch 分支筛选('all'所有分支/'0'主干/分支ID,默认'all')
189
+ * @param order 排序字段(如:'id_desc'、'pri_desc'等,默认'id_desc')
190
+ * @returns Promise<Bug列表及分页信息>
191
+ */
192
+ async getProductBugs(productId, page, limit, status, branch, order) {
173
193
  try {
174
194
  // 默认每页20条,最多100条
175
195
  const finalLimit = limit ? Math.min(limit, 100) : 20;
176
196
  const finalPage = page || 1;
197
+ const finalBranch = branch || 'all';
177
198
  const finalOrder = order || 'id_desc';
178
- console.log(`正在获取产品 ${productId} 的Bug列表 (page=${finalPage}, limit=${finalLimit}, order=${finalOrder})...`);
199
+ console.log(`正在获取产品 ${productId} 的Bug列表 (status=${status || 'all'}, branch=${finalBranch}, page=${finalPage}, limit=${finalLimit}, order=${finalOrder})...`);
179
200
  // 构建查询参数
180
201
  const queryParams = new URLSearchParams();
202
+ queryParams.append('branch', finalBranch);
181
203
  queryParams.append('page', finalPage.toString());
182
204
  queryParams.append('limit', finalLimit.toString());
183
205
  queryParams.append('order', finalOrder);
184
- // 支持 assigntome 状态
185
- if (status === 'assigntome') {
186
- queryParams.append('status', 'assigntome');
187
- }
188
- else if (status && status !== 'all') {
206
+ // 添加状态筛选
207
+ if (status && status !== 'all') {
189
208
  queryParams.append('status', status);
190
209
  }
191
210
  const response = await this.request('GET', `/products/${productId}/bugs?${queryParams.toString()}`);
package/dist/index.js CHANGED
@@ -87,17 +87,38 @@ server.tool("getProducts", {}, async () => {
87
87
  };
88
88
  });
89
89
  // Add getMyBugs tool
90
- server.tool("getMyBugs", "获取Bug列表 - 默认获取所有Bug,可选择只获取分配给我的Bug", {
91
- status: z.enum(['active', 'resolved', 'closed', 'all']).optional(),
92
- productId: z.number().optional(),
90
+ server.tool("getMyBugs", "获取Bug列表 - 支持多种状态筛选(指派给我、由我创建、未关闭等)和分支筛选", {
91
+ status: z.enum([
92
+ 'active', // 激活状态
93
+ 'resolved', // 已解决
94
+ 'closed', // 已关闭
95
+ 'all', // 所有状态
96
+ 'assigntome', // 指派给我的
97
+ 'openedbyme', // 由我创建
98
+ 'resolvedbyme', // 由我解决
99
+ 'assignedbyme', // 由我指派
100
+ 'assigntonull', // 未指派
101
+ 'unconfirmed', // 未确认
102
+ 'unclosed', // 未关闭
103
+ 'unresolved', // 未解决(激活状态)
104
+ 'toclosed', // 待关闭(已解决)
105
+ 'postponedbugs', // 延期的Bug
106
+ 'longlifebugs', // 长期未处理的Bug
107
+ 'overduebugs', // 已过期的Bug
108
+ 'review', // 待我审核
109
+ 'feedback', // 用户反馈
110
+ 'needconfirm', // 需求变更需确认
111
+ 'bysearch' // 自定义搜索
112
+ ]).optional().describe("Bug状态筛选,默认返回所有状态"),
113
+ productId: z.number().optional().describe("产品ID,默认使用第二个产品"),
93
114
  page: z.number().optional().describe("页码,从1开始,默认为1"),
94
115
  limit: z.number().optional().describe("每页数量,默认20,最大100"),
95
- onlyAssignedToMe: z.boolean().optional().describe("是否只获取分配给我的Bug,默认false(获取所有Bug)"),
96
- order: z.string().optional().describe("排序方式,如 id_desc(ID降序), id_asc(ID升序), pri_desc(优先级降序)等,默认id_desc")
97
- }, async ({ status, productId, page, limit, onlyAssignedToMe, order }) => {
116
+ branch: z.string().optional().describe("分支筛选:'all'(所有分支,默认)、'0'(主干分支)、分支ID"),
117
+ order: z.string().optional().describe("排序方式,如 id_desc(ID降序), pri_desc(优先级降序), openedDate_desc(创建时间降序)等,默认id_desc")
118
+ }, async ({ status, productId, page, limit, branch, order }) => {
98
119
  if (!zentaoApi)
99
120
  throw new Error("Please initialize Zentao API first");
100
- const result = await zentaoApi.getMyBugs(status, productId, page, limit, onlyAssignedToMe || false, order);
121
+ const result = await zentaoApi.getMyBugs(status, productId, page, limit, branch, order);
101
122
  // 返回分页信息和数据
102
123
  const summary = {
103
124
  summary: `当前第 ${result.page} 页,共 ${result.total} 个Bug,本页显示 ${result.bugs.length} 个`,
@@ -114,16 +135,38 @@ server.tool("getMyBugs", "获取Bug列表 - 默认获取所有Bug,可选择只
114
135
  };
115
136
  });
116
137
  // Add getProductBugs tool
117
- server.tool("getProductBugs", {
118
- productId: z.number(),
138
+ server.tool("getProductBugs", "获取指定产品的Bug列表 - 支持多种状态筛选和分支筛选", {
139
+ productId: z.number().describe("产品ID(必填)"),
119
140
  page: z.number().optional().describe("页码,从1开始,默认为1"),
120
141
  limit: z.number().optional().describe("每页数量,默认20,最大100"),
121
- status: z.enum(['active', 'resolved', 'closed', 'all']).optional(),
122
- order: z.string().optional().describe("排序方式,如 id_desc(ID降序), id_asc(ID升序), pri_desc(优先级降序)等,默认id_desc")
123
- }, async ({ productId, page, limit, status, order }) => {
124
- if (!zentaoApi)
125
- throw new Error("Please initialize Zentao API first");
126
- const result = await zentaoApi.getProductBugs(productId, page, limit, status, order);
142
+ status: z.enum([
143
+ 'active', // 激活状态
144
+ 'resolved', // 已解决
145
+ 'closed', // 已关闭
146
+ 'all', // 所有状态
147
+ 'assigntome', // 指派给我的
148
+ 'openedbyme', // 由我创建
149
+ 'resolvedbyme', // 由我解决
150
+ 'assignedbyme', // 由我指派
151
+ 'assigntonull', // 未指派
152
+ 'unconfirmed', // 未确认
153
+ 'unclosed', // 未关闭
154
+ 'unresolved', // 未解决(激活状态)
155
+ 'toclosed', // 待关闭(已解决)
156
+ 'postponedbugs', // 延期的Bug
157
+ 'longlifebugs', // 长期未处理的Bug
158
+ 'overduebugs', // 已过期的Bug
159
+ 'review', // 待我审核
160
+ 'feedback', // 用户反馈
161
+ 'needconfirm', // 需求变更需确认
162
+ 'bysearch' // 自定义搜索
163
+ ]).optional().describe("Bug状态筛选,默认返回所有状态"),
164
+ branch: z.string().optional().describe("分支筛选:'all'(所有分支,默认)、'0'(主干分支)、分支ID"),
165
+ order: z.string().optional().describe("排序方式,如 id_desc(ID降序), pri_desc(优先级降序), openedDate_desc(创建时间降序)等,默认id_desc")
166
+ }, async ({ productId, page, limit, status, branch, order }) => {
167
+ if (!zentaoApi)
168
+ throw new Error("Please initialize Zentao API first");
169
+ const result = await zentaoApi.getProductBugs(productId, page, limit, status, branch, order);
127
170
  // 返回分页信息和数据
128
171
  const summary = {
129
172
  summary: `当前第 ${result.page} 页,共 ${result.total} 个Bug,本页显示 ${result.bugs.length} 个`,
@@ -56,7 +56,34 @@ export interface TaskUpdate {
56
56
  comment?: string;
57
57
  }
58
58
  export type TaskStatus = 'wait' | 'doing' | 'done' | 'all';
59
- export type BugStatus = 'active' | 'resolved' | 'closed' | 'all';
59
+ /**
60
+ * Bug 状态筛选类型
61
+ *
62
+ * 基础状态:
63
+ * - active: 激活状态
64
+ * - resolved: 已解决
65
+ * - closed: 已关闭
66
+ * - all: 所有状态
67
+ *
68
+ * 筛选条件:
69
+ * - assigntome: 指派给我的
70
+ * - openedbyme: 由我创建
71
+ * - resolvedbyme: 由我解决
72
+ * - assignedbyme: 由我指派
73
+ * - assigntonull: 未指派
74
+ * - unconfirmed: 未确认
75
+ * - unclosed: 未关闭
76
+ * - unresolved: 未解决(激活状态)
77
+ * - toclosed: 待关闭(已解决)
78
+ * - postponedbugs: 延期的Bug
79
+ * - longlifebugs: 长期未处理的Bug
80
+ * - overduebugs: 已过期的Bug
81
+ * - review: 待我审核
82
+ * - feedback: 用户反馈
83
+ * - needconfirm: 需求变更需确认
84
+ * - bysearch: 自定义搜索(需配合queryID使用)
85
+ */
86
+ export type BugStatus = 'active' | 'resolved' | 'closed' | 'all' | 'assigntome' | 'openedbyme' | 'resolvedbyme' | 'assignedbyme' | 'assigntonull' | 'unconfirmed' | 'unclosed' | 'unresolved' | 'toclosed' | 'postponedbugs' | 'longlifebugs' | 'overduebugs' | 'review' | 'feedback' | 'needconfirm' | 'bysearch';
60
87
  export type ResolutionType = 'fixed' | 'bydesign' | 'duplicate' | 'external' | 'notrepro' | 'postponed' | 'willnotfix';
61
88
  export interface ResolveBugRequest {
62
89
  resolution: ResolutionType;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zzp123/mcp-zentao",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "description": "禅道项目管理系统的高级API集成包,提供任务管理、Bug跟踪等功能的完整封装,专为Cursor IDE设计的MCP扩展",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",