@aipper/zentao-mcp-server 0.1.11 → 0.1.13
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/.env.example +3 -0
- package/package.json +1 -1
- package/src/index.js +7 -3
- package/src/tools.js +16 -0
- package/src/zentao.js +40 -0
package/.env.example
CHANGED
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -82,6 +82,7 @@ function getConfigFromEnv() {
|
|
|
82
82
|
const timeoutMs = Number(process.env.ZENTAO_HTTP_TIMEOUT_MS || "30000");
|
|
83
83
|
const defaultProductId = Number(process.env.ZENTAO_PRODUCT_ID || "0") || null;
|
|
84
84
|
const defaultProjectSetId = Number(process.env.ZENTAO_PROJECT_SET_ID || "0") || null;
|
|
85
|
+
const defaultProjectId = Number(process.env.ZENTAO_PROJECT_ID || "0") || null;
|
|
85
86
|
const myBugsPath = String(process.env.ZENTAO_MY_BUGS_PATH || "").trim();
|
|
86
87
|
const bugsFallbackPaths = String(process.env.ZENTAO_BUGS_FALLBACK_PATHS || "")
|
|
87
88
|
.split(",")
|
|
@@ -104,6 +105,7 @@ function getConfigFromEnv() {
|
|
|
104
105
|
allowInsecureHttp: ALLOW_INSECURE_HTTP,
|
|
105
106
|
defaultProductId,
|
|
106
107
|
defaultProjectSetId,
|
|
108
|
+
defaultProjectId,
|
|
107
109
|
myBugsPath,
|
|
108
110
|
bugsFallbackPaths,
|
|
109
111
|
projectSetBugsPaths,
|
|
@@ -162,6 +164,7 @@ async function main() {
|
|
|
162
164
|
limit: args.limit,
|
|
163
165
|
page: args.page,
|
|
164
166
|
productId: args.productId,
|
|
167
|
+
projectId: args.projectId,
|
|
165
168
|
projectSetId: args.projectSetId,
|
|
166
169
|
path: args.path || "/bugs",
|
|
167
170
|
});
|
|
@@ -192,6 +195,7 @@ async function main() {
|
|
|
192
195
|
limit: args.limit,
|
|
193
196
|
page: args.page,
|
|
194
197
|
productId: args.productId,
|
|
198
|
+
projectId: args.projectId,
|
|
195
199
|
projectSetId: args.projectSetId,
|
|
196
200
|
maxItems: args.maxItems,
|
|
197
201
|
resolution: args.resolution || "fixed",
|
|
@@ -236,9 +240,9 @@ async function main() {
|
|
|
236
240
|
ok: false,
|
|
237
241
|
tool: rawToolName,
|
|
238
242
|
message: String(err?.message || err),
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
243
|
+
status: err?.status ?? null,
|
|
244
|
+
hint: "If you see 'Need product id', set env ZENTAO_PRODUCT_ID or pass productId in get_my_bugs. For project-scoped bugs, set ZENTAO_PROJECT_ID or pass projectId.",
|
|
245
|
+
hint2: "For project-set instances, prefer get_my_bugs with projectSetId or ZENTAO_MY_BUGS_PATH=/my/bug; list_my_projects may miss project sets without concrete projects.",
|
|
242
246
|
};
|
|
243
247
|
return toMcpTextResult(JSON.stringify(errorPayload, null, 2), { isError: true });
|
|
244
248
|
}
|
package/src/tools.js
CHANGED
|
@@ -41,6 +41,11 @@ export const TOOLS = [
|
|
|
41
41
|
limit: { type: "number", minimum: 1, maximum: 200, description: "Default 20, max 200" },
|
|
42
42
|
page: { type: "number", minimum: 1, description: "Default 1" },
|
|
43
43
|
productId: { type: "number", minimum: 1, description: "Optional product id (for instances requiring product scope)" },
|
|
44
|
+
projectId: {
|
|
45
|
+
type: "number",
|
|
46
|
+
minimum: 1,
|
|
47
|
+
description: "Optional project id. Directly query /projects/{id}/bugs, no cross-project merge.",
|
|
48
|
+
},
|
|
44
49
|
projectSetId: {
|
|
45
50
|
type: "number",
|
|
46
51
|
minimum: 1,
|
|
@@ -100,6 +105,11 @@ export const TOOLS = [
|
|
|
100
105
|
limit: { type: "number", minimum: 1, maximum: 200, description: "List page size, default 50" },
|
|
101
106
|
page: { type: "number", minimum: 1, description: "Default 1" },
|
|
102
107
|
productId: { type: "number", minimum: 1, description: "Optional product id (for instances requiring product scope)" },
|
|
108
|
+
projectId: {
|
|
109
|
+
type: "number",
|
|
110
|
+
minimum: 1,
|
|
111
|
+
description: "Optional project id. Directly query /projects/{id}/bugs, no cross-project merge.",
|
|
112
|
+
},
|
|
103
113
|
projectSetId: {
|
|
104
114
|
type: "number",
|
|
105
115
|
minimum: 1,
|
|
@@ -196,6 +206,9 @@ export function assertToolArgs(name, args) {
|
|
|
196
206
|
if (args.projectSetId !== undefined && (!Number.isFinite(args.projectSetId) || args.projectSetId < 1)) {
|
|
197
207
|
throw new Error("get_my_bugs.projectSetId must be a number >= 1");
|
|
198
208
|
}
|
|
209
|
+
if (args.projectId !== undefined && (!Number.isFinite(args.projectId) || args.projectId < 1)) {
|
|
210
|
+
throw new Error("get_my_bugs.projectId must be a number >= 1");
|
|
211
|
+
}
|
|
199
212
|
}
|
|
200
213
|
if (name === "get_bug_detail") {
|
|
201
214
|
if (!Number.isFinite(args.id) || Number(args.id) < 1) {
|
|
@@ -232,6 +245,9 @@ export function assertToolArgs(name, args) {
|
|
|
232
245
|
if (args.projectSetId !== undefined && (!Number.isFinite(args.projectSetId) || args.projectSetId < 1)) {
|
|
233
246
|
throw new Error("batch_resolve_my_bugs.projectSetId must be a number >= 1");
|
|
234
247
|
}
|
|
248
|
+
if (args.projectId !== undefined && (!Number.isFinite(args.projectId) || args.projectId < 1)) {
|
|
249
|
+
throw new Error("batch_resolve_my_bugs.projectId must be a number >= 1");
|
|
250
|
+
}
|
|
235
251
|
if (args.path !== undefined) {
|
|
236
252
|
if (typeof args.path !== "string") throw new Error("batch_resolve_my_bugs.path must be a string");
|
|
237
253
|
if (!SAFE_BUG_LIST_PATHS.has(args.path)) {
|
package/src/zentao.js
CHANGED
|
@@ -95,6 +95,7 @@ function createAbortSignal(timeoutMs) {
|
|
|
95
95
|
* @param {number} config.timeoutMs - Request timeout in milliseconds
|
|
96
96
|
* @param {number} [config.defaultProductId] - Default product ID
|
|
97
97
|
* @param {number} [config.defaultProjectSetId] - Default project set ID
|
|
98
|
+
* @param {number} [config.defaultProjectId] - Default project ID
|
|
98
99
|
* @param {string} [config.myBugsPath] - My bugs path
|
|
99
100
|
* @param {string[]} [config.bugsFallbackPaths] - Bug fallback paths
|
|
100
101
|
* @param {string[]} [config.projectSetBugsPaths] - Project set bug paths
|
|
@@ -113,6 +114,7 @@ export function createZenTaoClient(config) {
|
|
|
113
114
|
allowInsecureHttp,
|
|
114
115
|
defaultProductId,
|
|
115
116
|
defaultProjectSetId,
|
|
117
|
+
defaultProjectId,
|
|
116
118
|
myBugsPath,
|
|
117
119
|
bugsFallbackPaths,
|
|
118
120
|
projectSetBugsPaths,
|
|
@@ -748,6 +750,7 @@ export function createZenTaoClient(config) {
|
|
|
748
750
|
limit = 20,
|
|
749
751
|
page = 1,
|
|
750
752
|
productId,
|
|
753
|
+
projectId,
|
|
751
754
|
projectSetId,
|
|
752
755
|
path = "/bugs",
|
|
753
756
|
} = {}) {
|
|
@@ -755,6 +758,41 @@ export function createZenTaoClient(config) {
|
|
|
755
758
|
const safePage = Math.max(1, Number(page) || 1);
|
|
756
759
|
const dashboardScanLimit = Math.max(safeLimit, 100);
|
|
757
760
|
const assignee = normalizeString(auth.account);
|
|
761
|
+
const effectiveProjectId = normalizePositiveInt(projectId) || normalizePositiveInt(defaultProjectId);
|
|
762
|
+
|
|
763
|
+
if (effectiveProjectId) {
|
|
764
|
+
const query = { limit: safeLimit, page: safePage, assignedTo: assignee, status: status || undefined };
|
|
765
|
+
try {
|
|
766
|
+
const resp = await call({ path: `/projects/${effectiveProjectId}/bugs`, method: "GET", query });
|
|
767
|
+
const bugs = parseBugsFromResponse(resp?.data);
|
|
768
|
+
const filtered = bugs.filter((bug) => matchesBugFilters(bug, { status, keyword, assignee }));
|
|
769
|
+
return {
|
|
770
|
+
total: filtered.length,
|
|
771
|
+
matched: filtered.length,
|
|
772
|
+
page: safePage,
|
|
773
|
+
limit: safeLimit,
|
|
774
|
+
projectId: effectiveProjectId,
|
|
775
|
+
assignedTo: assignee,
|
|
776
|
+
bugs: filtered,
|
|
777
|
+
raw: {
|
|
778
|
+
status: resp?.status ?? null,
|
|
779
|
+
path: `/projects/${effectiveProjectId}/bugs`,
|
|
780
|
+
triedPaths: [{
|
|
781
|
+
path: `/projects/${effectiveProjectId}/bugs`,
|
|
782
|
+
status: resp?.status ?? null,
|
|
783
|
+
total: bugs.length,
|
|
784
|
+
matched: filtered.length,
|
|
785
|
+
}],
|
|
786
|
+
scannedTotal: bugs.length,
|
|
787
|
+
paths: [{ path: `/projects/${effectiveProjectId}/bugs`, status: resp?.status ?? null, total: bugs.length, matched: filtered.length }],
|
|
788
|
+
merged: false,
|
|
789
|
+
},
|
|
790
|
+
};
|
|
791
|
+
} catch (err) {
|
|
792
|
+
throw err;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
758
796
|
const effectiveProductId = normalizePositiveInt(productId) || normalizePositiveInt(defaultProductId);
|
|
759
797
|
const effectiveProjectSetId = normalizePositiveInt(projectSetId) || normalizePositiveInt(defaultProjectSetId);
|
|
760
798
|
const requestedPath = normalizeBugsListPath(path);
|
|
@@ -1287,6 +1325,7 @@ export function createZenTaoClient(config) {
|
|
|
1287
1325
|
limit = 50,
|
|
1288
1326
|
page = 1,
|
|
1289
1327
|
productId,
|
|
1328
|
+
projectId,
|
|
1290
1329
|
projectSetId,
|
|
1291
1330
|
maxItems = 20,
|
|
1292
1331
|
resolution = "fixed",
|
|
@@ -1302,6 +1341,7 @@ export function createZenTaoClient(config) {
|
|
|
1302
1341
|
limit,
|
|
1303
1342
|
page,
|
|
1304
1343
|
productId,
|
|
1344
|
+
projectId,
|
|
1305
1345
|
projectSetId,
|
|
1306
1346
|
path,
|
|
1307
1347
|
});
|