@zzp123/mcp-zentao 1.8.9 → 1.10.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,49 @@ 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.10.0] - 2025-11-07
9
+
10
+ ### Fixed
11
+ - **修复 Bug 获取工具的 API 端点和参数问题** 🔧
12
+ - 从错误的 `/bugs` 端点改为正确的 `/products/{productId}/bugs` 端点
13
+ - 移除了低效的客户端过滤逻辑,改用服务器端原生支持的 `assigntome` 状态
14
+ - 修复了 `onlyAssignedToMe` 参数无法正确工作的问题
15
+
16
+ ### Added
17
+ - **添加排序参数支持** ✨
18
+ - 为 `getMyBugs` 和 `getProductBugs` 工具添加 `order` 参数
19
+ - 支持多种排序方式:`id_desc`(ID降序)、`id_asc`(ID升序)、`pri_desc`(优先级降序)等
20
+ - 默认使用 `id_desc` 排序,确保最新的 Bug 显示在前面
21
+ - 与禅道官方 API 完全一致的参数格式
22
+
23
+ ### Improved
24
+ - **性能优化**
25
+ - 使用服务器端过滤替代客户端过滤,显著提升查询效率
26
+ - 减少不必要的数据传输,降低网络开销
27
+ - 更准确的分页信息和总数统计
28
+
29
+ ### Changed
30
+ - 更新了 `getMyBugs` 方法签名,添加 `order` 参数
31
+ - 更新了 `getProductBugs` 方法签名,添加 `order` 参数
32
+ - 优化了查询参数的构建方式,使用 URLSearchParams 确保参数正确编码
33
+
34
+ ## [1.9.0] - 2025-11-06
35
+
36
+ ### Fixed
37
+ - **修复 getMyBugs 工具过滤逻辑问题** 🔧
38
+ - 禅道API的 `/bugs` 接口不支持 `assignedTo` 参数进行服务端过滤
39
+ - 改为使用客户端过滤:获取更多数据后在本地筛选分配给当前用户的Bug
40
+ - 修复了使用 `onlyAssignedToMe=true` 时无法正确获取当前用户Bug的问题
41
+ - 现在能够正确识别 `assignedTo` 字段(支持对象和字符串两种格式)
42
+
43
+ ### Improved
44
+ - 优化了 `getMyBugs` 的性能:当需要过滤时自动获取100条数据以确保有足够的结果
45
+ - 增加了详细的过滤日志输出,便于调试和追踪
46
+
47
+ ### Changed
48
+ - 扩展了 `Bug` 类型定义,添加了 `assignedTo`、`openedBy`、`resolvedBy` 等字段
49
+ - 更新了文档,说明了禅道API的限制和客户端过滤的实现方式
50
+
8
51
  ## [1.8.9] - 2025-11-06
9
52
 
10
53
  ### Fixed
package/README.md CHANGED
@@ -15,17 +15,17 @@ npm install @zzp123/mcp-zentao -g
15
15
 
16
16
  查看完整的版本更新历史,请访问 [CHANGELOG.md](./CHANGELOG.md)
17
17
 
18
- **最新版本**: v1.6.1
19
- - 修复 Windows 剪贴板图片读取问题
20
- - 使用新的 PowerShell 脚本确保正确读取剪贴板图片
21
- - 改进错误处理和日志输出
22
-
23
- **主要版本**:
24
- - v1.4.1 - 修复 uploadImageFromClipboard 返回值问题
18
+ **最新版本**: v1.9.0
19
+ - 修复 getMyBugs 工具的过滤逻辑问题
20
+ - 改为客户端过滤,正确获取当前用户的bug
21
+ - ✅ 支持 assignedTo 的对象和字符串两种格式
22
+
23
+ **近期版本**:
24
+ - v1.8.9 - 修复 resolveBug 工具自动设置默认 resolvedBuild
25
+ - v1.8.8 - 修复 getMyBugs 工具返回Bug数量为0的问题
26
+ - v1.6.1 - 修复 Windows 剪贴板图片读取问题
25
27
  - v1.4.0 - 新增解决Bug接口
26
- - v1.3.1 - 修复剪贴板图片上传核心问题
27
28
  - v1.3.0 - 添加命令行脚本支持
28
- - v1.2.0 - 添加文件上传/下载功能
29
29
 
30
30
  ## 使用方法
31
31
 
@@ -9,13 +9,13 @@ 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): Promise<{
12
+ getMyBugs(status?: BugStatus, productId?: number, page?: number, limit?: number, onlyAssignedToMe?: boolean, order?: string): Promise<{
13
13
  page: number;
14
14
  total: number;
15
15
  limit: number;
16
16
  bugs: Bug[];
17
17
  }>;
18
- getProductBugs(productId: number, page?: number, limit?: number, status?: BugStatus): Promise<{
18
+ getProductBugs(productId: number, page?: number, limit?: number, status?: BugStatus, order?: string): Promise<{
19
19
  page: number;
20
20
  total: number;
21
21
  limit: number;
@@ -111,7 +111,7 @@ export class ZentaoAPI {
111
111
  throw error;
112
112
  }
113
113
  }
114
- async getMyBugs(status, productId, page, limit, onlyAssignedToMe = false) {
114
+ async getMyBugs(status, productId, page, limit, onlyAssignedToMe = false, order) {
115
115
  if (!productId) {
116
116
  // 如果没有提供产品ID,获取第二个可用的产品(索引为1)
117
117
  const products = await this.getProducts();
@@ -125,19 +125,23 @@ export class ZentaoAPI {
125
125
  // 默认每页20条,最多100条
126
126
  const finalLimit = limit ? Math.min(limit, 100) : 20;
127
127
  const finalPage = page || 1;
128
- const params = {
129
- status: status || 'all',
130
- product: productId,
131
- page: finalPage,
132
- limit: finalLimit
133
- };
134
- // 只有当明确指定时才过滤 assignedTo
128
+ // 构建查询参数
129
+ const queryParams = new URLSearchParams();
130
+ // 如果需要只获取分配给我的Bug,使用 assigntome 状态
135
131
  if (onlyAssignedToMe) {
136
- params.assignedTo = this.config.username;
132
+ queryParams.append('status', 'assigntome');
137
133
  }
134
+ else if (status && status !== 'all') {
135
+ queryParams.append('status', status);
136
+ }
137
+ queryParams.append('page', finalPage.toString());
138
+ queryParams.append('limit', finalLimit.toString());
139
+ // 添加排序参数,默认按ID降序
140
+ const finalOrder = order || 'id_desc';
141
+ queryParams.append('order', finalOrder);
138
142
  try {
139
- console.log(`正在获取Bug列表 (page=${finalPage}, limit=${finalLimit}),参数:`, params);
140
- const response = await this.request('GET', '/bugs', params);
143
+ console.log(`正在获取产品 ${productId} 的Bug列表,参数: status=${onlyAssignedToMe ? 'assigntome' : (status || 'all')}, page=${finalPage}, limit=${finalLimit}, order=${finalOrder}`);
144
+ const response = await this.request('GET', `/products/${productId}/bugs?${queryParams.toString()}`);
141
145
  console.log(`Bug列表响应: 获取到 ${response.bugs?.length || 0} 条数据`);
142
146
  if (Array.isArray(response)) {
143
147
  // 如果返回的是数组,转换为标准格式
@@ -148,35 +152,40 @@ export class ZentaoAPI {
148
152
  bugs: response
149
153
  };
150
154
  }
151
- else if (response && typeof response === 'object' && Array.isArray(response.bugs)) {
152
- return {
153
- page: response.page || finalPage,
154
- total: response.total || response.bugs.length,
155
- limit: response.limit || finalLimit,
156
- bugs: response.bugs
157
- };
155
+ else if (response && typeof response === 'object') {
156
+ if (Array.isArray(response.bugs)) {
157
+ return {
158
+ page: response.page || finalPage,
159
+ total: response.total || response.bugs.length,
160
+ limit: response.limit || finalLimit,
161
+ bugs: response.bugs
162
+ };
163
+ }
158
164
  }
159
165
  throw new Error(`获取Bug列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
160
166
  }
161
167
  catch (error) {
162
- if (error instanceof Error && error.message.includes('Need product id')) {
163
- throw new Error('获取Bug列表失败: 请提供产品ID');
164
- }
165
168
  console.error('获取Bug列表失败:', error);
166
169
  throw error;
167
170
  }
168
171
  }
169
- async getProductBugs(productId, page, limit, status) {
172
+ async getProductBugs(productId, page, limit, status, order) {
170
173
  try {
171
174
  // 默认每页20条,最多100条
172
175
  const finalLimit = limit ? Math.min(limit, 100) : 20;
173
176
  const finalPage = page || 1;
174
- console.log(`正在获取产品 ${productId} 的Bug列表 (page=${finalPage}, limit=${finalLimit})...`);
177
+ const finalOrder = order || 'id_desc';
178
+ console.log(`正在获取产品 ${productId} 的Bug列表 (page=${finalPage}, limit=${finalLimit}, order=${finalOrder})...`);
175
179
  // 构建查询参数
176
180
  const queryParams = new URLSearchParams();
177
181
  queryParams.append('page', finalPage.toString());
178
182
  queryParams.append('limit', finalLimit.toString());
179
- if (status && status !== 'all') {
183
+ queryParams.append('order', finalOrder);
184
+ // 支持 assigntome 状态
185
+ if (status === 'assigntome') {
186
+ queryParams.append('status', 'assigntome');
187
+ }
188
+ else if (status && status !== 'all') {
180
189
  queryParams.append('status', status);
181
190
  }
182
191
  const response = await this.request('GET', `/products/${productId}/bugs?${queryParams.toString()}`);
package/dist/index.js CHANGED
@@ -92,11 +92,12 @@ server.tool("getMyBugs", "获取Bug列表 - 默认获取所有Bug,可选择只
92
92
  productId: z.number().optional(),
93
93
  page: z.number().optional().describe("页码,从1开始,默认为1"),
94
94
  limit: z.number().optional().describe("每页数量,默认20,最大100"),
95
- onlyAssignedToMe: z.boolean().optional().describe("是否只获取分配给我的Bug,默认false(获取所有Bug)")
96
- }, async ({ status, productId, page, limit, onlyAssignedToMe }) => {
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 }) => {
97
98
  if (!zentaoApi)
98
99
  throw new Error("Please initialize Zentao API first");
99
- const result = await zentaoApi.getMyBugs(status, productId, page, limit, onlyAssignedToMe || false);
100
+ const result = await zentaoApi.getMyBugs(status, productId, page, limit, onlyAssignedToMe || false, order);
100
101
  // 返回分页信息和数据
101
102
  const summary = {
102
103
  summary: `当前第 ${result.page} 页,共 ${result.total} 个Bug,本页显示 ${result.bugs.length} 个`,
@@ -117,11 +118,12 @@ server.tool("getProductBugs", {
117
118
  productId: z.number(),
118
119
  page: z.number().optional().describe("页码,从1开始,默认为1"),
119
120
  limit: z.number().optional().describe("每页数量,默认20,最大100"),
120
- status: z.enum(['active', 'resolved', 'closed', 'all']).optional()
121
- }, async ({ productId, page, limit, status }) => {
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 }) => {
122
124
  if (!zentaoApi)
123
125
  throw new Error("Please initialize Zentao API first");
124
- const result = await zentaoApi.getProductBugs(productId, page, limit, status);
126
+ const result = await zentaoApi.getProductBugs(productId, page, limit, status, order);
125
127
  // 返回分页信息和数据
126
128
  const summary = {
127
129
  summary: `当前第 ${result.page} 页,共 ${result.total} 个Bug,本页显示 ${result.bugs.length} 个`,
@@ -40,6 +40,13 @@ export interface Bug {
40
40
  days_open?: number;
41
41
  aging_status?: string;
42
42
  aging_description?: string;
43
+ assignedTo?: any;
44
+ openedBy?: any;
45
+ resolvedBy?: any;
46
+ product?: number;
47
+ module?: number;
48
+ pri?: number;
49
+ type?: string;
43
50
  }
44
51
  export interface TaskUpdate {
45
52
  consumed?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zzp123/mcp-zentao",
3
- "version": "1.8.9",
3
+ "version": "1.10.0",
4
4
  "description": "禅道项目管理系统的高级API集成包,提供任务管理、Bug跟踪等功能的完整封装,专为Cursor IDE设计的MCP扩展",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",