Skip to content

Commit 85d0f0f

Browse files
author
延枚
committed
检索工作项支持分页
Change-Id: I2e54ddcd8655b74eac5d22c5726b91c84f6d8305
1 parent 3f9bf11 commit 85d0f0f

File tree

4 files changed

+114
-13
lines changed

4 files changed

+114
-13
lines changed

operations/projex/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,9 @@ export const SearchWorkitemsSchema = z.object({
313313
// Advanced parameters
314314
advancedConditions: z.string().nullable().optional().describe("Advanced filter conditions, JSON format"),
315315
orderBy: z.string().optional().default("gmtCreate").describe("Sort field, default is gmtCreate. Possible values: gmtCreate, subject, status, priority, assignedTo"),
316+
sort: z.string().optional().default("desc").describe("Sort order, default is desc. Possible values: desc (descending), asc (ascending)"),
317+
page: z.number().int().min(1).optional().describe("Page number, starting from 1. Default is 1"),
318+
perPage: z.number().int().min(0).max(200).optional().describe("Number of items per page, range 0-200. Default is 20"),
316319
includeDetails: z.boolean().optional().describe("Set to true when you need work item descriptions/detailed content. This automatically fetches missing descriptions instead of requiring separate get_work_item calls. RECOMMENDED: Use includeDetails=true when user asks for 'detailed content', 'descriptions', or 'full information' of work items. This is more efficient than calling get_work_item multiple times. Default is false")
317320
});
318321

operations/projex/workitem.ts

Lines changed: 105 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import {RecordType, string, TypeOf, z, ZodString} from "zod";
2-
import {buildUrl, yunxiaoRequest} from "../../common/utils.js";
2+
import {buildUrl, yunxiaoRequest, getYunxiaoApiBaseUrl, getCurrentSessionToken} from "../../common/utils.js";
3+
import { createYunxiaoError } from "../../common/errors.js";
4+
import { getUserAgent } from "universal-user-agent";
5+
import { VERSION } from "../../common/version.js";
36
import {
47
WorkItemSchema,
58
FilterConditionSchema,
@@ -27,6 +30,21 @@ export async function getWorkItemFunc(
2730
return WorkItemSchema.parse(response);
2831
}
2932

33+
// 定义分页信息类型
34+
export interface PaginationInfo {
35+
page: number;
36+
perPage: number;
37+
totalPages: number;
38+
total: number;
39+
nextPage: number | null;
40+
prevPage: number | null;
41+
}
42+
43+
export interface SearchWorkitemsResult {
44+
items: z.infer<typeof WorkItemSchema>[];
45+
pagination?: PaginationInfo;
46+
}
47+
3048
export async function searchWorkitemsFunc(
3149
organizationId: string,
3250
category: string,
@@ -51,8 +69,11 @@ export async function searchWorkitemsFunc(
5169
updateStatusAtBefore?: string,
5270
advancedConditions?: string,
5371
orderBy: string = "gmtCreate",
72+
sort: string = "desc",
73+
page?: number,
74+
perPage?: number,
5475
includeDetails: boolean = false // 新增参数:是否自动补充缺失的description等详细信息
55-
): Promise<z.infer<typeof WorkItemSchema>[]> {
76+
): Promise<SearchWorkitemsResult> {
5677
// 处理assignedTo为"self"的情况,自动获取当前用户ID
5778
let finalAssignedTo = assignedTo;
5879
let finalCreator = creator;
@@ -111,17 +132,83 @@ export async function searchWorkitemsFunc(
111132
}
112133

113134
payload.orderBy = orderBy;
135+
136+
// 添加分页和排序参数
137+
if (sort) {
138+
payload.sort = sort;
139+
}
140+
if (page !== undefined) {
141+
payload.page = page;
142+
}
143+
if (perPage !== undefined) {
144+
payload.perPage = perPage;
145+
}
114146

115-
const response = await yunxiaoRequest(url, {
147+
// 使用 fetch 直接获取响应,以便读取响应头中的分页信息
148+
const isAbsolute = url.startsWith("http://") || url.startsWith("https://");
149+
const fullUrl = isAbsolute ? url : `${getYunxiaoApiBaseUrl()}${url.startsWith("/") ? url : `/${url}`}`;
150+
151+
const requestHeaders: Record<string, string> = {
152+
"Accept": "application/json",
153+
"Content-Type": "application/json",
154+
"User-Agent": `modelcontextprotocol/servers/alibabacloud-devops-mcp-server/v${VERSION} ${getUserAgent()}`,
155+
};
156+
157+
const token = getCurrentSessionToken();
158+
if (token) {
159+
requestHeaders["x-yunxiao-token"] = token;
160+
}
161+
162+
const response = await fetch(fullUrl, {
116163
method: "POST",
117-
body: payload,
118-
});
164+
headers: requestHeaders,
165+
body: JSON.stringify(payload),
166+
} as RequestInit);
167+
168+
if (!response.ok) {
169+
const responseBody = await response.json().catch(() => ({}));
170+
throw createYunxiaoError(
171+
response.status,
172+
responseBody,
173+
fullUrl,
174+
"POST",
175+
requestHeaders,
176+
payload
177+
);
178+
}
119179

120-
if (!Array.isArray(response)) {
121-
return [];
180+
const responseBody = await response.json();
181+
182+
// 从响应头中提取分页信息
183+
const pagination: PaginationInfo | undefined = (() => {
184+
const xPage = response.headers.get("x-page");
185+
const xPerPage = response.headers.get("x-per-page");
186+
const xTotalPages = response.headers.get("x-total-pages");
187+
const xTotal = response.headers.get("x-total");
188+
const xNextPage = response.headers.get("x-next-page");
189+
const xPrevPage = response.headers.get("x-prev-page");
190+
191+
if (xPage && xPerPage && xTotalPages && xTotal) {
192+
return {
193+
page: parseInt(xPage, 10),
194+
perPage: parseInt(xPerPage, 10),
195+
totalPages: parseInt(xTotalPages, 10),
196+
total: parseInt(xTotal, 10),
197+
nextPage: xNextPage ? parseInt(xNextPage, 10) : null,
198+
prevPage: xPrevPage ? parseInt(xPrevPage, 10) : null,
199+
};
200+
}
201+
return undefined;
202+
})();
203+
204+
if (!Array.isArray(responseBody)) {
205+
return {
206+
items: [],
207+
pagination,
208+
};
122209
}
123210

124-
const workItems = response.map(workitem => WorkItemSchema.parse(workitem));
211+
const workItems = responseBody.map(workitem => WorkItemSchema.parse(workitem));
125212

126213
// 如果需要补充详细信息,使用分批并发方式获取
127214
if (includeDetails) {
@@ -135,7 +222,7 @@ export async function searchWorkitemsFunc(
135222
const descriptionMap = await batchGetWorkItemDetails(organizationId, itemsNeedingDetails);
136223

137224
// 更新workItems中的description
138-
return workItems.map(item => {
225+
const updatedItems = workItems.map(item => {
139226
if (descriptionMap.has(item.id)) {
140227
return {
141228
...item,
@@ -144,10 +231,18 @@ export async function searchWorkitemsFunc(
144231
}
145232
return item;
146233
});
234+
235+
return {
236+
items: updatedItems,
237+
pagination,
238+
};
147239
}
148240
}
149241

150-
return workItems;
242+
return {
243+
items: workItems,
244+
pagination,
245+
};
151246
}
152247

153248
// 分批并发获取工作项详情

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "alibabacloud-devops-mcp-server",
3-
"version": "0.3.2",
3+
"version": "0.3.3",
44
"description": "MCP Server for using the alibabacloud-devops API: allows AI assistants to directly participate in development collaboration, helping teams optimize development processes and improve efficiency.",
55
"type": "module",
66
"license": "Apache-2.0",

tool-handlers/project-management.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export const handleProjectManagementTools = async (request: any) => {
127127

128128
case "search_workitems": {
129129
const args = types.SearchWorkitemsSchema.parse(request.params.arguments);
130-
const workItems = await workitem.searchWorkitemsFunc(
130+
const result = await workitem.searchWorkitemsFunc(
131131
args.organizationId,
132132
args.category,
133133
args.spaceId,
@@ -151,10 +151,13 @@ export const handleProjectManagementTools = async (request: any) => {
151151
args.updateStatusAtBefore ?? undefined,
152152
args.advancedConditions ?? undefined,
153153
args.orderBy ?? "gmtCreate",
154+
args.sort ?? "desc",
155+
args.page,
156+
args.perPage,
154157
args.includeDetails ?? false
155158
);
156159
return {
157-
content: [{ type: "text", text: JSON.stringify(workItems, null, 2) }],
160+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
158161
};
159162
}
160163

0 commit comments

Comments
 (0)