@zzp123/mcp-zentao 1.7.4 → 1.8.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/CHANGELOG.md CHANGED
@@ -5,6 +5,23 @@ 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.8.0] - 2025-11-06
9
+
10
+ ### Changed
11
+ - **重构需求变更接口命名**
12
+ - 将 `updateStory` 工具重命名为 `changeStory`,更准确地反映其功能
13
+ - 将 `UpdateStoryRequest` 类型重命名为 `ChangeStoryRequest`
14
+ - 将 `updateStory` API方法重命名为 `changeStory`
15
+ - 使用功能完整的"修改需求其他字段"接口替代功能有限的"变更需求"接口
16
+
17
+ ### Added
18
+ - 向后兼容的类型别名:`UpdateStoryRequest` 作为 `ChangeStoryRequest` 的别名
19
+
20
+ ### Technical
21
+ - 统一需求变更相关的命名规范
22
+ - 保持向后兼容性,旧的类型名称仍然可用
23
+ - 所有测试通过,确保重构不影响现有功能
24
+
8
25
  ## [1.7.4] - 2025-11-06
9
26
 
10
27
  ### Fixed
@@ -1,4 +1,4 @@
1
- import { AssignFeedbackRequest, Bug, BugStatus, Build, CloseFeedbackRequest, CreateBuildRequest, CreateBugRequest, CreateExecutionRequest, CreateFeedbackRequest, CreatePlanRequest, CreateProductRequest, CreateProgramRequest, CreateProjectRequest, CreateStoryRequest, CreateTaskRequest, CreateTestCaseRequest, CreateTicketRequest, CreateUserRequest, Execution, Feedback, FileUploadResponse, ModulesResponse, ModuleType, Plan, Product, Program, Project, Release, ResolveBugRequest, Story, Task, TaskStatus, TaskUpdate, TestCase, Ticket, UpdateBuildRequest, UpdateBugRequest, UpdateExecutionRequest, UpdateFeedbackRequest, UpdatePlanRequest, UpdateProductRequest, UpdateProgramRequest, UpdateProjectRequest, UpdateStoryRequest, UpdateTestCaseRequest, UpdateTicketRequest, UpdateUserRequest, UploadFileRequest, UserDetail, ZentaoConfig } from '../types/zentao';
1
+ import { AssignFeedbackRequest, Bug, BugStatus, Build, CloseFeedbackRequest, CreateBuildRequest, CreateBugRequest, CreateExecutionRequest, CreateFeedbackRequest, CreatePlanRequest, CreateProductRequest, CreateProgramRequest, CreateProjectRequest, CreateStoryRequest, CreateTaskRequest, CreateTestCaseRequest, CreateTicketRequest, CreateUserRequest, Execution, Feedback, FileUploadResponse, ModulesResponse, ModuleType, Plan, Product, Program, Project, Release, ResolveBugRequest, Story, Task, TaskStatus, TaskUpdate, TestCase, Ticket, UpdateBuildRequest, UpdateBugRequest, UpdateExecutionRequest, UpdateFeedbackRequest, UpdatePlanRequest, UpdateProductRequest, UpdateProgramRequest, UpdateProjectRequest, ChangeStoryRequest, UpdateTestCaseRequest, UpdateTicketRequest, UpdateUserRequest, UploadFileRequest, UserDetail, ZentaoConfig } from '../types/zentao';
2
2
  export declare class ZentaoAPI {
3
3
  private config;
4
4
  private client;
@@ -9,8 +9,19 @@ 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): Promise<Bug[]>;
13
- getBugDetail(bugId: number): Promise<Bug>;
12
+ getMyBugs(status?: BugStatus, productId?: number, page?: number, limit?: number): Promise<{
13
+ page: number;
14
+ total: number;
15
+ limit: number;
16
+ bugs: Bug[];
17
+ }>;
18
+ getProductBugs(productId: number, page?: number, limit?: number, status?: BugStatus): Promise<{
19
+ page: number;
20
+ total: number;
21
+ limit: number;
22
+ bugs: Bug[];
23
+ }>;
24
+ getBugDetail(bugId: number, fields?: 'basic' | 'detail' | 'full'): Promise<any>;
14
25
  resolveBug(bugId: number, resolution: ResolveBugRequest): Promise<Bug>;
15
26
  updateTask(taskId: number, update: TaskUpdate): Promise<Task>;
16
27
  finishTask(taskId: number, update?: TaskUpdate): Promise<Task>;
@@ -28,16 +39,21 @@ export declare class ZentaoAPI {
28
39
  linkBugsToPlan(planId: number, bugIds: number[]): Promise<Plan>;
29
40
  unlinkBugsFromPlan(planId: number, bugIds: number[]): Promise<Plan>;
30
41
  getProjectReleases(projectId: number): Promise<Release[]>;
31
- getStoryDetail(storyId: number): Promise<Story>;
42
+ getStoryDetail(storyId: number, fields?: 'basic' | 'detail' | 'full'): Promise<any>;
32
43
  createBug(productId: number, bug: CreateBugRequest): Promise<Bug>;
33
44
  getProjectExecutions(projectId: number): Promise<Execution[]>;
34
45
  createPlan(productId: number, plan: CreatePlanRequest): Promise<Plan>;
35
46
  getProjects(page?: number, limit?: number): Promise<Project[]>;
36
- updateStory(storyId: number, update: UpdateStoryRequest): Promise<Story>;
47
+ changeStory(storyId: number, update: ChangeStoryRequest): Promise<Story>;
37
48
  deleteTask(taskId: number): Promise<{
38
49
  message: string;
39
50
  }>;
40
- getProductStories(productId: number): Promise<Story[]>;
51
+ getProductStories(productId: number, page?: number, limit?: number): Promise<{
52
+ page: number;
53
+ total: number;
54
+ limit: number;
55
+ stories: Story[];
56
+ }>;
41
57
  getProgramDetail(programId: number): Promise<Program>;
42
58
  createProgram(program: CreateProgramRequest): Promise<Program>;
43
59
  updateProgram(programId: number, update: UpdateProgramRequest): Promise<Program>;
@@ -111,7 +111,7 @@ export class ZentaoAPI {
111
111
  throw error;
112
112
  }
113
113
  }
114
- async getMyBugs(status, productId) {
114
+ async getMyBugs(status, productId, page, limit) {
115
115
  if (!productId) {
116
116
  // 如果没有提供产品ID,获取第一个可用的产品
117
117
  const products = await this.getProducts();
@@ -121,20 +121,36 @@ export class ZentaoAPI {
121
121
  productId = products[0].id;
122
122
  console.log(`使用第一个可用的产品ID: ${productId}`);
123
123
  }
124
+ // 默认每页20条,最多100条
125
+ const finalLimit = limit ? Math.min(limit, 100) : 20;
126
+ const finalPage = page || 1;
124
127
  const params = {
125
128
  assignedTo: this.config.username,
126
129
  status: status || 'all',
127
- product: productId
130
+ product: productId,
131
+ page: finalPage,
132
+ limit: finalLimit
128
133
  };
129
134
  try {
130
- console.log('正在获取Bug列表,参数:', params);
135
+ console.log(`正在获取Bug列表 (page=${finalPage}, limit=${finalLimit}),参数:`, params);
131
136
  const response = await this.request('GET', '/bugs', params);
132
- console.log('Bug列表响应:', response);
137
+ console.log(`Bug列表响应: 获取到 ${response.bugs?.length || 0} 条数据`);
133
138
  if (Array.isArray(response)) {
134
- return response;
139
+ // 如果返回的是数组,转换为标准格式
140
+ return {
141
+ page: finalPage,
142
+ total: response.length,
143
+ limit: finalLimit,
144
+ bugs: response
145
+ };
135
146
  }
136
147
  else if (response && typeof response === 'object' && Array.isArray(response.bugs)) {
137
- return response.bugs;
148
+ return {
149
+ page: response.page || finalPage,
150
+ total: response.total || response.bugs.length,
151
+ limit: response.limit || finalLimit,
152
+ bugs: response.bugs
153
+ };
138
154
  }
139
155
  throw new Error(`获取Bug列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
140
156
  }
@@ -146,12 +162,80 @@ export class ZentaoAPI {
146
162
  throw error;
147
163
  }
148
164
  }
149
- async getBugDetail(bugId) {
165
+ async getProductBugs(productId, page, limit, status) {
166
+ try {
167
+ // 默认每页20条,最多100条
168
+ const finalLimit = limit ? Math.min(limit, 100) : 20;
169
+ const finalPage = page || 1;
170
+ console.log(`正在获取产品 ${productId} 的Bug列表 (page=${finalPage}, limit=${finalLimit})...`);
171
+ // 构建查询参数
172
+ const queryParams = new URLSearchParams();
173
+ queryParams.append('page', finalPage.toString());
174
+ queryParams.append('limit', finalLimit.toString());
175
+ if (status && status !== 'all') {
176
+ queryParams.append('status', status);
177
+ }
178
+ const response = await this.request('GET', `/products/${productId}/bugs?${queryParams.toString()}`);
179
+ console.log(`产品Bug列表响应: 获取到 ${response.bugs?.length || 0} 条数据`);
180
+ if (Array.isArray(response)) {
181
+ // 如果返回的是数组,转换为标准格式
182
+ return {
183
+ page: finalPage,
184
+ total: response.length,
185
+ limit: finalLimit,
186
+ bugs: response
187
+ };
188
+ }
189
+ else if (response && typeof response === 'object') {
190
+ if (Array.isArray(response.bugs)) {
191
+ return {
192
+ page: response.page || finalPage,
193
+ total: response.total || response.bugs.length,
194
+ limit: response.limit || finalLimit,
195
+ bugs: response.bugs
196
+ };
197
+ }
198
+ }
199
+ throw new Error(`获取产品Bug列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
200
+ }
201
+ catch (error) {
202
+ console.error('获取产品Bug列表失败:', error);
203
+ throw error;
204
+ }
205
+ }
206
+ async getBugDetail(bugId, fields) {
150
207
  try {
151
- console.log(`正在获取Bug ${bugId} 的详情...`);
208
+ console.log(`正在获取Bug ${bugId} 的详情 (fields=${fields || 'full'})...`);
152
209
  const response = await this.request('GET', `/bugs/${bugId}`);
153
210
  console.log('Bug详情响应:', response);
154
- return response;
211
+ // 根据 fields 参数过滤返回的字段
212
+ const fieldLevel = fields || 'full';
213
+ if (fieldLevel === 'basic') {
214
+ // 基本信息:只返回核心字段
215
+ return {
216
+ id: response.id,
217
+ title: response.title,
218
+ product: response.product,
219
+ module: response.module,
220
+ status: response.status,
221
+ severity: response.severity,
222
+ pri: response.pri,
223
+ type: response.type,
224
+ assignedTo: response.assignedTo,
225
+ openedBy: response.openedBy,
226
+ openedDate: response.openedDate,
227
+ deadline: response.deadline
228
+ };
229
+ }
230
+ else if (fieldLevel === 'detail') {
231
+ // 详细信息:包含步骤描述,但排除不常用字段
232
+ const { files, cases, linkBugs, ...detailData } = response;
233
+ return detailData;
234
+ }
235
+ else {
236
+ // 完整信息:返回所有字段
237
+ return response;
238
+ }
155
239
  }
156
240
  catch (error) {
157
241
  console.error('获取Bug详情失败:', error);
@@ -414,12 +498,39 @@ export class ZentaoAPI {
414
498
  throw error;
415
499
  }
416
500
  }
417
- async getStoryDetail(storyId) {
501
+ async getStoryDetail(storyId, fields) {
418
502
  try {
419
- console.log(`正在获取需求 ${storyId} 的详情...`);
503
+ console.log(`正在获取需求 ${storyId} 的详情 (fields=${fields || 'full'})...`);
420
504
  const response = await this.request('GET', `/stories/${storyId}`);
421
505
  console.log('需求详情响应:', response);
422
- return response;
506
+ // 根据 fields 参数过滤返回的字段
507
+ const fieldLevel = fields || 'full';
508
+ if (fieldLevel === 'basic') {
509
+ // 基本信息:只返回核心字段
510
+ return {
511
+ id: response.id,
512
+ title: response.title,
513
+ product: response.product,
514
+ module: response.module,
515
+ status: response.status,
516
+ stage: response.stage,
517
+ pri: response.pri,
518
+ category: response.category,
519
+ estimate: response.estimate,
520
+ assignedTo: response.assignedTo,
521
+ openedBy: response.openedBy,
522
+ openedDate: response.openedDate
523
+ };
524
+ }
525
+ else if (fieldLevel === 'detail') {
526
+ // 详细信息:包含描述和验收标准,但不包含关联数据
527
+ const { executions, tasks, stages, children, ...detailData } = response;
528
+ return detailData;
529
+ }
530
+ else {
531
+ // 完整信息:返回所有字段
532
+ return response;
533
+ }
423
534
  }
424
535
  catch (error) {
425
536
  console.error('获取需求详情失败:', error);
@@ -495,9 +606,9 @@ export class ZentaoAPI {
495
606
  throw error;
496
607
  }
497
608
  }
498
- async updateStory(storyId, update) {
609
+ async changeStory(storyId, update) {
499
610
  try {
500
- console.log(`正在更新需求 ${storyId}...`);
611
+ console.log(`正在变更需求 ${storyId}...`);
501
612
  // 自动处理评审人问题
502
613
  const updateData = { ...update };
503
614
  // 如果用户没有设置评审人,也没有指定无需评审,则自动跳过评审
@@ -506,11 +617,11 @@ export class ZentaoAPI {
506
617
  console.log('自动设置needNotReview=true以跳过评审要求');
507
618
  }
508
619
  const response = await this.request('PUT', `/stories/${storyId}`, undefined, updateData);
509
- console.log('更新需求响应:', response);
620
+ console.log('变更需求响应:', response);
510
621
  return response;
511
622
  }
512
623
  catch (error) {
513
- console.error('更新需求失败:', error);
624
+ console.error('变更需求失败:', error);
514
625
  throw error;
515
626
  }
516
627
  }
@@ -526,17 +637,35 @@ export class ZentaoAPI {
526
637
  throw error;
527
638
  }
528
639
  }
529
- async getProductStories(productId) {
640
+ async getProductStories(productId, page, limit) {
530
641
  try {
531
- console.log(`正在获取产品 ${productId} 的需求列表...`);
532
- const response = await this.request('GET', `/products/${productId}/stories`);
533
- console.log('产品需求列表响应:', response);
642
+ // 默认每页20条,最多100条
643
+ const finalLimit = limit ? Math.min(limit, 100) : 20;
644
+ const finalPage = page || 1;
645
+ console.log(`正在获取产品 ${productId} 的需求列表 (page=${finalPage}, limit=${finalLimit})...`);
646
+ // 构建查询参数
647
+ const queryParams = new URLSearchParams();
648
+ queryParams.append('page', finalPage.toString());
649
+ queryParams.append('limit', finalLimit.toString());
650
+ const response = await this.request('GET', `/products/${productId}/stories?${queryParams.toString()}`);
651
+ console.log(`产品需求列表响应: 获取到 ${response.stories?.length || 0} 条数据`);
534
652
  if (Array.isArray(response)) {
535
- return response;
653
+ // 如果返回的是数组,转换为标准格式
654
+ return {
655
+ page: finalPage,
656
+ total: response.length,
657
+ limit: finalLimit,
658
+ stories: response
659
+ };
536
660
  }
537
661
  else if (response && typeof response === 'object') {
538
662
  if (Array.isArray(response.stories)) {
539
- return response.stories;
663
+ return {
664
+ page: response.page || finalPage,
665
+ total: response.total || response.stories.length,
666
+ limit: response.limit || finalLimit,
667
+ stories: response.stories
668
+ };
540
669
  }
541
670
  }
542
671
  throw new Error(`获取产品需求列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
package/dist/index.js CHANGED
@@ -89,24 +89,80 @@ server.tool("getProducts", {}, async () => {
89
89
  // Add getMyBugs tool
90
90
  server.tool("getMyBugs", {
91
91
  status: z.enum(['active', 'resolved', 'closed', 'all']).optional(),
92
- productId: z.number().optional()
93
- }, async ({ status, productId }) => {
94
- if (!zentaoApi)
95
- throw new Error("Please initialize Zentao API first");
96
- const bugs = await zentaoApi.getMyBugs(status, productId);
92
+ productId: z.number().optional(),
93
+ page: z.number().optional().describe("页码,从1开始,默认为1"),
94
+ limit: z.number().optional().describe("每页数量,默认20,最大100")
95
+ }, async ({ status, productId, page, limit }) => {
96
+ if (!zentaoApi)
97
+ throw new Error("Please initialize Zentao API first");
98
+ const result = await zentaoApi.getMyBugs(status, productId, page, limit);
99
+ // 返回分页信息和数据
100
+ const summary = {
101
+ summary: `当前第 ${result.page} 页,共 ${result.total} 个Bug,本页显示 ${result.bugs.length} 个`,
102
+ pagination: {
103
+ page: result.page,
104
+ limit: result.limit,
105
+ total: result.total,
106
+ totalPages: Math.ceil(result.total / result.limit)
107
+ },
108
+ bugs: result.bugs
109
+ };
110
+ return {
111
+ content: [{ type: "text", text: JSON.stringify(summary, null, 2) }]
112
+ };
113
+ });
114
+ // Add getProductBugs tool
115
+ server.tool("getProductBugs", {
116
+ productId: z.number(),
117
+ page: z.number().optional().describe("页码,从1开始,默认为1"),
118
+ limit: z.number().optional().describe("每页数量,默认20,最大100"),
119
+ status: z.enum(['active', 'resolved', 'closed', 'all']).optional()
120
+ }, async ({ productId, page, limit, status }) => {
121
+ if (!zentaoApi)
122
+ throw new Error("Please initialize Zentao API first");
123
+ const result = await zentaoApi.getProductBugs(productId, page, limit, status);
124
+ // 返回分页信息和数据
125
+ const summary = {
126
+ summary: `当前第 ${result.page} 页,共 ${result.total} 个Bug,本页显示 ${result.bugs.length} 个`,
127
+ pagination: {
128
+ page: result.page,
129
+ limit: result.limit,
130
+ total: result.total,
131
+ totalPages: Math.ceil(result.total / result.limit)
132
+ },
133
+ bugs: result.bugs
134
+ };
97
135
  return {
98
- content: [{ type: "text", text: JSON.stringify(bugs, null, 2) }]
136
+ content: [{ type: "text", text: JSON.stringify(summary, null, 2) }]
99
137
  };
100
138
  });
101
139
  // Add getBugDetail tool
102
140
  server.tool("getBugDetail", {
103
- bugId: z.number()
104
- }, async ({ bugId }) => {
105
- if (!zentaoApi)
106
- throw new Error("Please initialize Zentao API first");
107
- const bug = await zentaoApi.getBugDetail(bugId);
141
+ bugId: z.number(),
142
+ fields: z.enum(['basic', 'detail', 'full']).optional().describe(`
143
+ 字段级别:
144
+ - basic: 基本信息(id, title, status, severity, pri等核心字段)
145
+ - detail: 详细信息(包含steps步骤,但不包含files/cases/linkBugs等关联数据)
146
+ - full: 完整信息(包含所有字段,默认值)
147
+ `.trim())
148
+ }, async ({ bugId, fields }) => {
149
+ if (!zentaoApi)
150
+ throw new Error("Please initialize Zentao API first");
151
+ const bug = await zentaoApi.getBugDetail(bugId, fields);
152
+ // 添加说明信息
153
+ const result = {
154
+ fieldLevel: fields || 'full',
155
+ bug: bug
156
+ };
157
+ // 根据字段级别添加提示
158
+ if (fields === 'basic') {
159
+ result.note = '仅显示基本信息,如需完整内容请使用 fields=detail 或 fields=full';
160
+ }
161
+ else if (fields === 'detail') {
162
+ result.note = '显示详细信息但不包含关联数据(files/cases/linkBugs),如需完整内容请使用 fields=full';
163
+ }
108
164
  return {
109
- content: [{ type: "text", text: JSON.stringify(bug, null, 2) }]
165
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
110
166
  };
111
167
  });
112
168
  // Add resolveBug tool
@@ -360,13 +416,31 @@ server.tool("getProjectReleases", {
360
416
  });
361
417
  // Add getStoryDetail tool
362
418
  server.tool("getStoryDetail", {
363
- storyId: z.number()
364
- }, async ({ storyId }) => {
365
- if (!zentaoApi)
366
- throw new Error("Please initialize Zentao API first");
367
- const story = await zentaoApi.getStoryDetail(storyId);
419
+ storyId: z.number(),
420
+ fields: z.enum(['basic', 'detail', 'full']).optional().describe(`
421
+ 字段级别:
422
+ - basic: 基本信息(id, title, status, stage, pri等核心字段)
423
+ - detail: 详细信息(包含spec和verify,但不包含executions/tasks/stages/children等关联数据)
424
+ - full: 完整信息(包含所有字段,默认值)
425
+ `.trim())
426
+ }, async ({ storyId, fields }) => {
427
+ if (!zentaoApi)
428
+ throw new Error("Please initialize Zentao API first");
429
+ const story = await zentaoApi.getStoryDetail(storyId, fields);
430
+ // 添加说明信息
431
+ const result = {
432
+ fieldLevel: fields || 'full',
433
+ story: story
434
+ };
435
+ // 根据字段级别添加提示
436
+ if (fields === 'basic') {
437
+ result.note = '仅显示基本信息,如需完整内容请使用 fields=detail 或 fields=full';
438
+ }
439
+ else if (fields === 'detail') {
440
+ result.note = '显示详细信息但不包含关联数据(executions/tasks/stages/children),如需完整内容请使用 fields=full';
441
+ }
368
442
  return {
369
- content: [{ type: "text", text: JSON.stringify(story, null, 2) }]
443
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
370
444
  };
371
445
  });
372
446
  // Add createBug tool
@@ -460,8 +534,8 @@ server.tool("getProjects", {
460
534
  content: [{ type: "text", text: JSON.stringify(projects, null, 2) }]
461
535
  };
462
536
  });
463
- // Add updateStory tool
464
- server.tool("updateStory", {
537
+ // Add changeStory tool
538
+ server.tool("changeStory", {
465
539
  storyId: z.number(),
466
540
  update: z.union([
467
541
  z.object({
@@ -507,7 +581,7 @@ server.tool("updateStory", {
507
581
  comment: z.string().optional()
508
582
  }),
509
583
  z.string()
510
- ]).describe("需求更新字段 - 支持对象或JSON字符串格式")
584
+ ]).describe("需求变更字段 - 支持对象或JSON字符串格式")
511
585
  }, async ({ storyId, update }) => {
512
586
  if (!zentaoApi)
513
587
  throw new Error("Please initialize Zentao API first");
@@ -524,7 +598,7 @@ server.tool("updateStory", {
524
598
  else {
525
599
  updateData = update;
526
600
  }
527
- const story = await zentaoApi.updateStory(storyId, updateData);
601
+ const story = await zentaoApi.changeStory(storyId, updateData);
528
602
  return {
529
603
  content: [{ type: "text", text: JSON.stringify(story, null, 2) }]
530
604
  };
@@ -542,13 +616,26 @@ server.tool("deleteTask", {
542
616
  });
543
617
  // Add getProductStories tool
544
618
  server.tool("getProductStories", {
545
- productId: z.number()
546
- }, async ({ productId }) => {
547
- if (!zentaoApi)
548
- throw new Error("Please initialize Zentao API first");
549
- const stories = await zentaoApi.getProductStories(productId);
619
+ productId: z.number(),
620
+ page: z.number().optional().describe("页码,从1开始,默认为1"),
621
+ limit: z.number().optional().describe("每页数量,默认20,最大100")
622
+ }, async ({ productId, page, limit }) => {
623
+ if (!zentaoApi)
624
+ throw new Error("Please initialize Zentao API first");
625
+ const result = await zentaoApi.getProductStories(productId, page, limit);
626
+ // 返回分页信息和数据
627
+ const summary = {
628
+ summary: `当前第 ${result.page} 页,共 ${result.total} 条需求,本页显示 ${result.stories.length} 条`,
629
+ pagination: {
630
+ page: result.page,
631
+ limit: result.limit,
632
+ total: result.total,
633
+ totalPages: Math.ceil(result.total / result.limit)
634
+ },
635
+ stories: result.stories
636
+ };
550
637
  return {
551
- content: [{ type: "text", text: JSON.stringify(stories, null, 2) }]
638
+ content: [{ type: "text", text: JSON.stringify(summary, null, 2) }]
552
639
  };
553
640
  });
554
641
  // Program tools
@@ -5,8 +5,8 @@ export class BugService {
5
5
  this.api = api;
6
6
  }
7
7
  async getMyBugs(status) {
8
- const bugs = await this.api.getMyBugs(status);
9
- return bugs.map(bug => this.enrichBugData(bug));
8
+ const result = await this.api.getMyBugs(status);
9
+ return result.bugs.map((bug) => this.enrichBugData(bug));
10
10
  }
11
11
  async getBugDetail(bugId) {
12
12
  const bug = await this.api.getBugDetail(bugId);
@@ -256,7 +256,7 @@ export interface Project {
256
256
  PM: string | User;
257
257
  progress: number;
258
258
  }
259
- export interface UpdateStoryRequest {
259
+ export interface ChangeStoryRequest {
260
260
  title?: string;
261
261
  product?: number;
262
262
  parent?: number;
@@ -287,6 +287,7 @@ export interface UpdateStoryRequest {
287
287
  verify?: string;
288
288
  comment?: string;
289
289
  }
290
+ export type UpdateStoryRequest = ChangeStoryRequest;
290
291
  export interface CreateProgramRequest {
291
292
  name?: string;
292
293
  parent?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zzp123/mcp-zentao",
3
- "version": "1.7.4",
3
+ "version": "1.8.1",
4
4
  "description": "禅道项目管理系统的高级API集成包,提供任务管理、Bug跟踪等功能的完整封装,专为Cursor IDE设计的MCP扩展",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",