@daghis/teamcity-mcp 2.2.3 → 2.3.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 +14 -0
- package/dist/index.js +180 -111
- package/package.json +7 -7
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.3.1](https://github.com/Daghis/teamcity-mcp/compare/teamcity-mcp-v2.3.0...teamcity-mcp-v2.3.1) (2026-03-10)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* use toBuildLocator() for all build URL templates in api-client ([#416](https://github.com/Daghis/teamcity-mcp/issues/416)) ([2a10312](https://github.com/Daghis/teamcity-mcp/commit/2a10312e1469ed9d7c9b9e47caaddaac693df400))
|
|
9
|
+
|
|
10
|
+
## [2.3.0](https://github.com/Daghis/teamcity-mcp/compare/teamcity-mcp-v2.2.3...teamcity-mcp-v2.3.0) (2026-03-10)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* **tools:** accept buildNumber + buildTypeId across all build tools ([#410](https://github.com/Daghis/teamcity-mcp/issues/410)) ([9aa005d](https://github.com/Daghis/teamcity-mcp/commit/9aa005d01bf6db9e7ac53155680876dc36202da7))
|
|
16
|
+
|
|
3
17
|
## [2.2.3](https://github.com/Daghis/teamcity-mcp/compare/teamcity-mcp-v2.2.2...teamcity-mcp-v2.2.3) (2026-03-09)
|
|
4
18
|
|
|
5
19
|
|
package/dist/index.js
CHANGED
|
@@ -1205,7 +1205,7 @@ function debug2(message, meta) {
|
|
|
1205
1205
|
// package.json
|
|
1206
1206
|
var package_default = {
|
|
1207
1207
|
name: "@daghis/teamcity-mcp",
|
|
1208
|
-
version: "2.
|
|
1208
|
+
version: "2.3.1",
|
|
1209
1209
|
description: "Model Control Protocol server for TeamCity CI/CD integration with AI coding assistants",
|
|
1210
1210
|
mcpName: "io.github.Daghis/teamcity",
|
|
1211
1211
|
main: "dist/index.js",
|
|
@@ -1214,7 +1214,7 @@ var package_default = {
|
|
|
1214
1214
|
"teamcity-mcp": "dist/index.js"
|
|
1215
1215
|
},
|
|
1216
1216
|
engines: {
|
|
1217
|
-
node: ">=20.
|
|
1217
|
+
node: ">=20.19.0"
|
|
1218
1218
|
},
|
|
1219
1219
|
scripts: {
|
|
1220
1220
|
dev: "node ./node_modules/tsx/dist/cli.mjs watch src/index.ts",
|
|
@@ -1280,18 +1280,18 @@ var package_default = {
|
|
|
1280
1280
|
devDependencies: {
|
|
1281
1281
|
"@codecov/bundler-plugin-core": "^1.9.1",
|
|
1282
1282
|
"@esbuild-plugins/tsconfig-paths": "^0.1.2",
|
|
1283
|
+
"@eslint/js": "^10.0.1",
|
|
1283
1284
|
"@trivago/prettier-plugin-sort-imports": "^6.0.1",
|
|
1284
1285
|
"@types/jest": "^30.0.0",
|
|
1285
1286
|
"@types/js-yaml": "^4.0.9",
|
|
1286
1287
|
"@types/node": "^25.0.2",
|
|
1287
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
1288
|
-
"@typescript-eslint/parser": "^8.
|
|
1288
|
+
"@typescript-eslint/eslint-plugin": "^8.57.0",
|
|
1289
|
+
"@typescript-eslint/parser": "^8.57.0",
|
|
1289
1290
|
esbuild: "^0.27.0",
|
|
1290
|
-
eslint: "^
|
|
1291
|
+
eslint: "^10.0.3",
|
|
1291
1292
|
"eslint-config-prettier": "^10.1.8",
|
|
1292
|
-
"eslint-import-resolver-typescript": "^4.4.4",
|
|
1293
|
-
"eslint-plugin-import": "^2.32.0",
|
|
1294
1293
|
"eslint-plugin-prettier": "^5.0.1",
|
|
1294
|
+
globals: "^17.4.0",
|
|
1295
1295
|
jest: "^30.1.3",
|
|
1296
1296
|
"jest-junit": "^16.0.0",
|
|
1297
1297
|
"js-yaml": "^4.1.1",
|
|
@@ -1562,13 +1562,13 @@ var ArtifactManager = class _ArtifactManager {
|
|
|
1562
1562
|
} catch (error3) {
|
|
1563
1563
|
const err = error3;
|
|
1564
1564
|
if (err.response?.status === 401) {
|
|
1565
|
-
throw new Error("Authentication failed: Invalid TeamCity token");
|
|
1565
|
+
throw new Error("Authentication failed: Invalid TeamCity token", { cause: error3 });
|
|
1566
1566
|
}
|
|
1567
1567
|
if (err.response?.status === 404) {
|
|
1568
|
-
throw new Error(`Build not found: ${buildId}
|
|
1568
|
+
throw new Error(`Build not found: ${buildId}`, { cause: error3 });
|
|
1569
1569
|
}
|
|
1570
1570
|
const errMsg = err.message ?? String(error3);
|
|
1571
|
-
throw new Error(`Failed to fetch artifacts: ${errMsg}
|
|
1571
|
+
throw new Error(`Failed to fetch artifacts: ${errMsg}`, { cause: error3 });
|
|
1572
1572
|
}
|
|
1573
1573
|
}
|
|
1574
1574
|
/**
|
|
@@ -1708,7 +1708,7 @@ var ArtifactManager = class _ArtifactManager {
|
|
|
1708
1708
|
} else {
|
|
1709
1709
|
errMsg = error3 instanceof Error ? error3.message : "Unknown error";
|
|
1710
1710
|
}
|
|
1711
|
-
throw new Error(`Failed to download artifact: ${errMsg}
|
|
1711
|
+
throw new Error(`Failed to download artifact: ${errMsg}`, { cause: error3 });
|
|
1712
1712
|
}
|
|
1713
1713
|
}
|
|
1714
1714
|
/**
|
|
@@ -2033,7 +2033,7 @@ var BuildConfigurationCloneManager = class {
|
|
|
2033
2033
|
return null;
|
|
2034
2034
|
}
|
|
2035
2035
|
if (axiosError.response?.status === 403) {
|
|
2036
|
-
throw new Error("Permission denied: No access to source configuration");
|
|
2036
|
+
throw new Error("Permission denied: No access to source configuration", { cause: err });
|
|
2037
2037
|
}
|
|
2038
2038
|
throw err;
|
|
2039
2039
|
}
|
|
@@ -2107,7 +2107,7 @@ var BuildConfigurationCloneManager = class {
|
|
|
2107
2107
|
return { id: newId, name: newName };
|
|
2108
2108
|
} catch (err) {
|
|
2109
2109
|
error2("Failed to clone VCS root", err);
|
|
2110
|
-
throw new Error(`Failed to clone VCS root: ${err.message}
|
|
2110
|
+
throw new Error(`Failed to clone VCS root: ${err.message}`, { cause: err });
|
|
2111
2111
|
}
|
|
2112
2112
|
}
|
|
2113
2113
|
/**
|
|
@@ -2237,14 +2237,14 @@ var BuildConfigurationCloneManager = class {
|
|
|
2237
2237
|
} catch (err) {
|
|
2238
2238
|
const error3 = err;
|
|
2239
2239
|
if (error3.response?.status === 409) {
|
|
2240
|
-
throw new Error(`Build configuration already exists with ID: ${configId}
|
|
2240
|
+
throw new Error(`Build configuration already exists with ID: ${configId}`, { cause: err });
|
|
2241
2241
|
}
|
|
2242
2242
|
if (error3.response?.status === 403) {
|
|
2243
|
-
throw new Error("Permission denied: You need project edit permissions");
|
|
2243
|
+
throw new Error("Permission denied: You need project edit permissions", { cause: err });
|
|
2244
2244
|
}
|
|
2245
2245
|
if (error3.response?.status === 400) {
|
|
2246
2246
|
const message = error3.response?.data?.message ?? "Invalid configuration";
|
|
2247
|
-
throw new Error(`Invalid configuration: ${message}
|
|
2247
|
+
throw new Error(`Invalid configuration: ${message}`, { cause: err });
|
|
2248
2248
|
}
|
|
2249
2249
|
error2(
|
|
2250
2250
|
"Failed to clone build configuration",
|
|
@@ -2429,7 +2429,7 @@ var BuildConfigurationUpdateManager = class {
|
|
|
2429
2429
|
return null;
|
|
2430
2430
|
}
|
|
2431
2431
|
if (err != null && typeof err === "object" && "response" in err && err.response?.status === 403) {
|
|
2432
|
-
throw new Error("Permission denied: No access to build configuration");
|
|
2432
|
+
throw new Error("Permission denied: No access to build configuration", { cause: err });
|
|
2433
2433
|
}
|
|
2434
2434
|
throw err;
|
|
2435
2435
|
}
|
|
@@ -2622,17 +2622,17 @@ var BuildConfigurationUpdateManager = class {
|
|
|
2622
2622
|
} catch (err) {
|
|
2623
2623
|
const error3 = err;
|
|
2624
2624
|
if (error3.response?.status === 409) {
|
|
2625
|
-
throw new Error("Configuration was modified by another user");
|
|
2625
|
+
throw new Error("Configuration was modified by another user", { cause: err });
|
|
2626
2626
|
}
|
|
2627
2627
|
if (error3.response?.status === 403) {
|
|
2628
|
-
throw new Error("Permission denied: You need project edit permissions");
|
|
2628
|
+
throw new Error("Permission denied: You need project edit permissions", { cause: err });
|
|
2629
2629
|
}
|
|
2630
2630
|
if (error3.response?.status === 400) {
|
|
2631
2631
|
const message = error3.response?.data?.message ?? "Invalid configuration";
|
|
2632
|
-
throw new Error(`Invalid update: ${message}
|
|
2632
|
+
throw new Error(`Invalid update: ${message}`, { cause: err });
|
|
2633
2633
|
}
|
|
2634
2634
|
error2("Failed to apply updates", error3);
|
|
2635
|
-
throw new Error("Partial update failure");
|
|
2635
|
+
throw new Error("Partial update failure", { cause: err });
|
|
2636
2636
|
}
|
|
2637
2637
|
}
|
|
2638
2638
|
/**
|
|
@@ -2735,7 +2735,7 @@ var BuildConfigurationUpdateManager = class {
|
|
|
2735
2735
|
info2("Rollback completed successfully", { configId });
|
|
2736
2736
|
} catch (err) {
|
|
2737
2737
|
error2("Failed to rollback changes", err);
|
|
2738
|
-
throw new Error("Rollback failed: Manual intervention may be required");
|
|
2738
|
+
throw new Error("Rollback failed: Manual intervention may be required", { cause: err });
|
|
2739
2739
|
}
|
|
2740
2740
|
}
|
|
2741
2741
|
/**
|
|
@@ -38652,12 +38652,15 @@ var TeamCityAPI = class _TeamCityAPI {
|
|
|
38652
38652
|
});
|
|
38653
38653
|
return response.data;
|
|
38654
38654
|
} catch (primaryError) {
|
|
38655
|
-
const response = await this.axiosInstance.get(
|
|
38656
|
-
|
|
38657
|
-
|
|
38658
|
-
|
|
38659
|
-
|
|
38660
|
-
|
|
38655
|
+
const response = await this.axiosInstance.get(
|
|
38656
|
+
`/app/rest/builds/${toBuildLocator(buildId)}/log`,
|
|
38657
|
+
{
|
|
38658
|
+
params: { plain: true },
|
|
38659
|
+
headers: { Accept: "text/plain" },
|
|
38660
|
+
responseType: "text",
|
|
38661
|
+
transformResponse: [(data) => data]
|
|
38662
|
+
}
|
|
38663
|
+
);
|
|
38661
38664
|
return response.data;
|
|
38662
38665
|
}
|
|
38663
38666
|
}
|
|
@@ -38669,16 +38672,19 @@ var TeamCityAPI = class _TeamCityAPI {
|
|
|
38669
38672
|
const startLine = options?.startLine ?? 0;
|
|
38670
38673
|
const lineCount = options?.lineCount ?? 500;
|
|
38671
38674
|
try {
|
|
38672
|
-
const response = await this.axiosInstance.get(
|
|
38673
|
-
|
|
38674
|
-
|
|
38675
|
-
|
|
38676
|
-
|
|
38677
|
-
|
|
38678
|
-
|
|
38679
|
-
|
|
38680
|
-
|
|
38681
|
-
|
|
38675
|
+
const response = await this.axiosInstance.get(
|
|
38676
|
+
`/app/rest/builds/${toBuildLocator(buildId)}/log`,
|
|
38677
|
+
{
|
|
38678
|
+
params: {
|
|
38679
|
+
plain: true,
|
|
38680
|
+
start: startLine,
|
|
38681
|
+
count: lineCount
|
|
38682
|
+
},
|
|
38683
|
+
headers: { Accept: "text/plain" },
|
|
38684
|
+
responseType: "text",
|
|
38685
|
+
transformResponse: [(data) => data]
|
|
38686
|
+
}
|
|
38687
|
+
);
|
|
38682
38688
|
const text = response.data ?? "";
|
|
38683
38689
|
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
38684
38690
|
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
@@ -38712,7 +38718,9 @@ var TeamCityAPI = class _TeamCityAPI {
|
|
|
38712
38718
|
return response.data;
|
|
38713
38719
|
}
|
|
38714
38720
|
async listTestFailures(buildId) {
|
|
38715
|
-
const response = await this.tests.getAllTestOccurrences(
|
|
38721
|
+
const response = await this.tests.getAllTestOccurrences(
|
|
38722
|
+
`build:(${toBuildLocator(buildId)}),status:FAILURE`
|
|
38723
|
+
);
|
|
38716
38724
|
return response.data;
|
|
38717
38725
|
}
|
|
38718
38726
|
async listBuildArtifacts(buildId, options) {
|
|
@@ -38732,7 +38740,7 @@ var TeamCityAPI = class _TeamCityAPI {
|
|
|
38732
38740
|
responseType: options?.responseType ?? "arraybuffer"
|
|
38733
38741
|
};
|
|
38734
38742
|
return this.axiosInstance.get(
|
|
38735
|
-
`/app/rest/builds
|
|
38743
|
+
`/app/rest/builds/${toBuildLocator(buildId)}/artifacts/content/${normalizedPath}`,
|
|
38736
38744
|
requestOptions
|
|
38737
38745
|
);
|
|
38738
38746
|
}
|
|
@@ -38754,13 +38762,16 @@ var TeamCityAPI = class _TeamCityAPI {
|
|
|
38754
38762
|
responseType: options?.responseType ?? "text",
|
|
38755
38763
|
transformResponse: options?.transformResponse ?? [(data) => data]
|
|
38756
38764
|
};
|
|
38757
|
-
return this.axiosInstance.get(
|
|
38765
|
+
return this.axiosInstance.get(
|
|
38766
|
+
`/app/rest/builds/${toBuildLocator(buildId)}/log`,
|
|
38767
|
+
requestOptions
|
|
38768
|
+
);
|
|
38758
38769
|
}
|
|
38759
38770
|
async getBuildStatistics(buildId, fields) {
|
|
38760
38771
|
return this.builds.getBuildStatisticValues(toBuildLocator(buildId), fields);
|
|
38761
38772
|
}
|
|
38762
38773
|
async listChangesForBuild(buildId, fields) {
|
|
38763
|
-
return this.changes.getAllChanges(`build:(
|
|
38774
|
+
return this.changes.getAllChanges(`build:(${toBuildLocator(buildId)})`, fields);
|
|
38764
38775
|
}
|
|
38765
38776
|
async listSnapshotDependencies(buildId) {
|
|
38766
38777
|
const response = await this.builds.getBuild(toBuildLocator(buildId), "snapshot-dependencies");
|
|
@@ -38826,6 +38837,55 @@ var TeamCityAPI = class _TeamCityAPI {
|
|
|
38826
38837
|
// src/tools.ts
|
|
38827
38838
|
var isReadableStream = (value) => typeof value === "object" && value !== null && typeof value.pipe === "function";
|
|
38828
38839
|
var isAxios4042 = (error3) => (0, import_axios36.isAxiosError)(error3) && error3.response?.status === 404;
|
|
38840
|
+
var buildIdentifierSchema = import_zod4.z.object({
|
|
38841
|
+
buildId: import_zod4.z.string().min(1).optional(),
|
|
38842
|
+
buildNumber: import_zod4.z.union([import_zod4.z.string().min(1), import_zod4.z.number().int()]).optional(),
|
|
38843
|
+
buildTypeId: import_zod4.z.string().min(1).optional()
|
|
38844
|
+
}).superRefine((value, ctx) => {
|
|
38845
|
+
if (!value.buildId && value.buildNumber === void 0) {
|
|
38846
|
+
ctx.addIssue({
|
|
38847
|
+
code: import_zod4.z.ZodIssueCode.custom,
|
|
38848
|
+
path: ["buildId"],
|
|
38849
|
+
message: "Either buildId or (buildNumber + buildTypeId) must be provided"
|
|
38850
|
+
});
|
|
38851
|
+
}
|
|
38852
|
+
if (value.buildNumber !== void 0 && !value.buildTypeId) {
|
|
38853
|
+
ctx.addIssue({
|
|
38854
|
+
code: import_zod4.z.ZodIssueCode.custom,
|
|
38855
|
+
path: ["buildTypeId"],
|
|
38856
|
+
message: "buildTypeId is required when querying by buildNumber"
|
|
38857
|
+
});
|
|
38858
|
+
}
|
|
38859
|
+
});
|
|
38860
|
+
function resolveBuildLocator(input) {
|
|
38861
|
+
const trimmedBuildId = typeof input.buildId === "string" ? input.buildId.trim() : void 0;
|
|
38862
|
+
if (trimmedBuildId && trimmedBuildId.length > 0) {
|
|
38863
|
+
return { locator: `id:${trimmedBuildId}`, friendlyId: `ID '${trimmedBuildId}'` };
|
|
38864
|
+
}
|
|
38865
|
+
const buildNumber = input.buildNumber !== void 0 ? String(input.buildNumber).trim() : void 0;
|
|
38866
|
+
const buildTypeId = input.buildTypeId?.trim();
|
|
38867
|
+
if (buildTypeId && buildNumber) {
|
|
38868
|
+
return {
|
|
38869
|
+
locator: `buildType:(id:${buildTypeId}),number:${buildNumber}`,
|
|
38870
|
+
friendlyId: `build type '${buildTypeId}' #${buildNumber}`
|
|
38871
|
+
};
|
|
38872
|
+
}
|
|
38873
|
+
throw new TeamCityAPIError("Unable to resolve build identifier", "INVALID_BUILD_IDENTIFIER");
|
|
38874
|
+
}
|
|
38875
|
+
var buildIdentifierInputProperties = {
|
|
38876
|
+
buildId: { type: "string", description: "Build ID (internal TeamCity ID)" },
|
|
38877
|
+
buildNumber: {
|
|
38878
|
+
oneOf: [
|
|
38879
|
+
{ type: "string", description: 'Build number as TeamCity displays it (e.g. "886")' },
|
|
38880
|
+
{ type: "number", description: "Numeric build number" }
|
|
38881
|
+
],
|
|
38882
|
+
description: "Human-readable build number (requires buildTypeId)"
|
|
38883
|
+
},
|
|
38884
|
+
buildTypeId: {
|
|
38885
|
+
type: "string",
|
|
38886
|
+
description: "Build configuration ID (required when using buildNumber)"
|
|
38887
|
+
}
|
|
38888
|
+
};
|
|
38829
38889
|
var sanitizeFileName = (artifactName) => {
|
|
38830
38890
|
const base = (0, import_node_path.basename)(artifactName || "artifact");
|
|
38831
38891
|
const safeBase = base.replace(/[^a-zA-Z0-9._-]/g, "_") || "artifact";
|
|
@@ -39316,31 +39376,34 @@ var DEV_TOOLS = [
|
|
|
39316
39376
|
inputSchema: {
|
|
39317
39377
|
type: "object",
|
|
39318
39378
|
properties: {
|
|
39319
|
-
|
|
39320
|
-
}
|
|
39321
|
-
required: ["buildId"]
|
|
39379
|
+
...buildIdentifierInputProperties
|
|
39380
|
+
}
|
|
39322
39381
|
},
|
|
39323
39382
|
handler: async (args) => {
|
|
39324
|
-
const schema =
|
|
39383
|
+
const schema = buildIdentifierSchema;
|
|
39325
39384
|
return runTool(
|
|
39326
39385
|
"get_build",
|
|
39327
39386
|
schema,
|
|
39328
39387
|
async (typed) => {
|
|
39329
39388
|
const adapter = createAdapterFromTeamCityAPI(TeamCityAPI.getInstance());
|
|
39389
|
+
const { locator, friendlyId } = resolveBuildLocator(typed);
|
|
39330
39390
|
try {
|
|
39331
|
-
const
|
|
39332
|
-
return json(
|
|
39391
|
+
const build = await adapter.getBuild(locator);
|
|
39392
|
+
return json(build);
|
|
39333
39393
|
} catch (error3) {
|
|
39334
39394
|
if (!isAxios4042(error3)) throw error3;
|
|
39335
39395
|
}
|
|
39336
|
-
|
|
39337
|
-
|
|
39338
|
-
|
|
39339
|
-
|
|
39340
|
-
|
|
39396
|
+
if (typed.buildId) {
|
|
39397
|
+
try {
|
|
39398
|
+
const qb = await adapter.modules.buildQueue.getQueuedBuild(`id:${typed.buildId}`);
|
|
39399
|
+
return json({ ...qb.data, state: "queued" });
|
|
39400
|
+
} catch (queueError) {
|
|
39401
|
+
if (!isAxios4042(queueError)) throw queueError;
|
|
39402
|
+
}
|
|
39403
|
+
const build = await adapter.getBuild(locator);
|
|
39404
|
+
return json(build);
|
|
39341
39405
|
}
|
|
39342
|
-
|
|
39343
|
-
return json(build);
|
|
39406
|
+
throw new TeamCityNotFoundError(`Build not found for ${friendlyId}`);
|
|
39344
39407
|
},
|
|
39345
39408
|
args
|
|
39346
39409
|
);
|
|
@@ -39980,7 +40043,7 @@ var DEV_TOOLS = [
|
|
|
39980
40043
|
inputSchema: {
|
|
39981
40044
|
type: "object",
|
|
39982
40045
|
properties: {
|
|
39983
|
-
|
|
40046
|
+
...buildIdentifierInputProperties,
|
|
39984
40047
|
pageSize: { type: "number", description: "Items per page (default 100)" },
|
|
39985
40048
|
maxPages: { type: "number", description: "Max pages to fetch (when all=true)" },
|
|
39986
40049
|
all: { type: "boolean", description: "Fetch all pages up to maxPages" },
|
|
@@ -39988,25 +40051,26 @@ var DEV_TOOLS = [
|
|
|
39988
40051
|
type: "string",
|
|
39989
40052
|
description: "Optional fields selector for server-side projection"
|
|
39990
40053
|
}
|
|
39991
|
-
}
|
|
39992
|
-
required: ["buildId"]
|
|
40054
|
+
}
|
|
39993
40055
|
},
|
|
39994
40056
|
handler: async (args) => {
|
|
39995
|
-
const schema =
|
|
39996
|
-
|
|
39997
|
-
|
|
39998
|
-
|
|
39999
|
-
|
|
40000
|
-
|
|
40001
|
-
|
|
40057
|
+
const schema = buildIdentifierSchema.and(
|
|
40058
|
+
import_zod4.z.object({
|
|
40059
|
+
pageSize: import_zod4.z.number().int().min(1).max(1e3).optional(),
|
|
40060
|
+
maxPages: import_zod4.z.number().int().min(1).max(1e3).optional(),
|
|
40061
|
+
all: import_zod4.z.boolean().optional(),
|
|
40062
|
+
fields: import_zod4.z.string().min(1).optional()
|
|
40063
|
+
})
|
|
40064
|
+
);
|
|
40002
40065
|
return runTool(
|
|
40003
40066
|
"list_test_failures",
|
|
40004
40067
|
schema,
|
|
40005
40068
|
async (typed) => {
|
|
40006
40069
|
const adapter = createAdapterFromTeamCityAPI(TeamCityAPI.getInstance());
|
|
40070
|
+
const { locator: buildLocator } = resolveBuildLocator(typed);
|
|
40007
40071
|
const pageSize = typed.pageSize ?? 100;
|
|
40008
40072
|
const baseFetch = async ({ count, start }) => {
|
|
40009
|
-
const parts = [`build:(
|
|
40073
|
+
const parts = [`build:(${buildLocator})`, "status:FAILURE"];
|
|
40010
40074
|
if (typeof count === "number") parts.push(`count:${count}`);
|
|
40011
40075
|
if (typeof start === "number") parts.push(`start:${start}`);
|
|
40012
40076
|
const locator = parts.join(",");
|
|
@@ -40930,7 +40994,7 @@ var DEV_TOOLS = [
|
|
|
40930
40994
|
inputSchema: {
|
|
40931
40995
|
type: "object",
|
|
40932
40996
|
properties: {
|
|
40933
|
-
|
|
40997
|
+
...buildIdentifierInputProperties,
|
|
40934
40998
|
artifactPath: { type: "string", description: "Artifact path or name" },
|
|
40935
40999
|
encoding: {
|
|
40936
41000
|
type: "string",
|
|
@@ -40947,31 +41011,33 @@ var DEV_TOOLS = [
|
|
|
40947
41011
|
description: "Optional absolute path to write streamed content; defaults to a temp file when streaming"
|
|
40948
41012
|
}
|
|
40949
41013
|
},
|
|
40950
|
-
required: ["
|
|
41014
|
+
required: ["artifactPath"]
|
|
40951
41015
|
},
|
|
40952
41016
|
handler: async (args) => {
|
|
40953
|
-
const schema =
|
|
40954
|
-
|
|
40955
|
-
|
|
40956
|
-
|
|
40957
|
-
|
|
40958
|
-
|
|
40959
|
-
|
|
41017
|
+
const schema = buildIdentifierSchema.and(
|
|
41018
|
+
import_zod4.z.object({
|
|
41019
|
+
artifactPath: import_zod4.z.string().min(1),
|
|
41020
|
+
encoding: import_zod4.z.enum(["base64", "text", "stream"]).default("base64"),
|
|
41021
|
+
maxSize: import_zod4.z.number().int().positive().optional(),
|
|
41022
|
+
outputPath: import_zod4.z.string().min(1).optional()
|
|
41023
|
+
})
|
|
41024
|
+
);
|
|
40960
41025
|
return runTool(
|
|
40961
41026
|
"download_build_artifact",
|
|
40962
41027
|
schema,
|
|
40963
41028
|
async (typed) => {
|
|
40964
41029
|
const encoding = typed.encoding ?? "base64";
|
|
40965
41030
|
const adapter = createAdapterFromTeamCityAPI(TeamCityAPI.getInstance());
|
|
41031
|
+
const { locator: buildLocator } = resolveBuildLocator(typed);
|
|
40966
41032
|
debug2("tools.download_build_artifact.start", {
|
|
40967
|
-
|
|
41033
|
+
buildLocator,
|
|
40968
41034
|
encoding,
|
|
40969
41035
|
artifactPath: typed.artifactPath,
|
|
40970
41036
|
maxSize: typed.maxSize,
|
|
40971
41037
|
outputPath: typed.outputPath
|
|
40972
41038
|
});
|
|
40973
41039
|
const manager = new ArtifactManager(adapter);
|
|
40974
|
-
const artifact = await manager.downloadArtifact(
|
|
41040
|
+
const artifact = await manager.downloadArtifact(buildLocator, typed.artifactPath, {
|
|
40975
41041
|
encoding,
|
|
40976
41042
|
maxSize: typed.maxSize
|
|
40977
41043
|
});
|
|
@@ -40990,7 +41056,7 @@ var DEV_TOOLS = [
|
|
|
40990
41056
|
inputSchema: {
|
|
40991
41057
|
type: "object",
|
|
40992
41058
|
properties: {
|
|
40993
|
-
|
|
41059
|
+
...buildIdentifierInputProperties,
|
|
40994
41060
|
artifactPaths: {
|
|
40995
41061
|
type: "array",
|
|
40996
41062
|
description: "Artifact paths or names to download",
|
|
@@ -41024,7 +41090,7 @@ var DEV_TOOLS = [
|
|
|
41024
41090
|
description: "Optional absolute directory to write streamed artifacts; defaults to temp files when streaming"
|
|
41025
41091
|
}
|
|
41026
41092
|
},
|
|
41027
|
-
required: ["
|
|
41093
|
+
required: ["artifactPaths"]
|
|
41028
41094
|
},
|
|
41029
41095
|
handler: async (args) => {
|
|
41030
41096
|
const artifactInputSchema = import_zod4.z.union([
|
|
@@ -41035,31 +41101,33 @@ var DEV_TOOLS = [
|
|
|
41035
41101
|
downloadUrl: import_zod4.z.string().url().optional()
|
|
41036
41102
|
})
|
|
41037
41103
|
]);
|
|
41038
|
-
const schema =
|
|
41039
|
-
|
|
41040
|
-
|
|
41041
|
-
|
|
41042
|
-
|
|
41043
|
-
|
|
41044
|
-
|
|
41104
|
+
const schema = buildIdentifierSchema.and(
|
|
41105
|
+
import_zod4.z.object({
|
|
41106
|
+
artifactPaths: import_zod4.z.array(artifactInputSchema).min(1),
|
|
41107
|
+
encoding: import_zod4.z.enum(["base64", "text", "stream"]).default("base64"),
|
|
41108
|
+
maxSize: import_zod4.z.number().int().positive().optional(),
|
|
41109
|
+
outputDir: import_zod4.z.string().min(1).optional().refine((value) => value == null || (0, import_node_path.isAbsolute)(value), {
|
|
41110
|
+
message: "outputDir must be an absolute path"
|
|
41111
|
+
})
|
|
41112
|
+
}).superRefine((value, ctx) => {
|
|
41113
|
+
if (value.encoding !== "stream" && value.outputDir) {
|
|
41114
|
+
ctx.addIssue({
|
|
41115
|
+
code: import_zod4.z.ZodIssueCode.custom,
|
|
41116
|
+
message: 'outputDir can only be provided when encoding is set to "stream"',
|
|
41117
|
+
path: ["outputDir"]
|
|
41118
|
+
});
|
|
41119
|
+
}
|
|
41045
41120
|
})
|
|
41046
|
-
|
|
41047
|
-
if (value.encoding !== "stream" && value.outputDir) {
|
|
41048
|
-
ctx.addIssue({
|
|
41049
|
-
code: import_zod4.z.ZodIssueCode.custom,
|
|
41050
|
-
message: 'outputDir can only be provided when encoding is set to "stream"',
|
|
41051
|
-
path: ["outputDir"]
|
|
41052
|
-
});
|
|
41053
|
-
}
|
|
41054
|
-
});
|
|
41121
|
+
);
|
|
41055
41122
|
return runTool(
|
|
41056
41123
|
"download_build_artifacts",
|
|
41057
41124
|
schema,
|
|
41058
41125
|
async (typed) => {
|
|
41059
41126
|
const encoding = typed.encoding ?? "base64";
|
|
41060
41127
|
const adapter = createAdapterFromTeamCityAPI(TeamCityAPI.getInstance());
|
|
41128
|
+
const { locator: buildLocator } = resolveBuildLocator(typed);
|
|
41061
41129
|
const manager = new ArtifactManager(adapter);
|
|
41062
|
-
const requests = toNormalizedArtifactRequests(typed.artifactPaths,
|
|
41130
|
+
const requests = toNormalizedArtifactRequests(typed.artifactPaths, buildLocator);
|
|
41063
41131
|
const results = [];
|
|
41064
41132
|
for (const request of requests) {
|
|
41065
41133
|
try {
|
|
@@ -41148,22 +41216,23 @@ var DEV_TOOLS = [
|
|
|
41148
41216
|
inputSchema: {
|
|
41149
41217
|
type: "object",
|
|
41150
41218
|
properties: {
|
|
41151
|
-
|
|
41219
|
+
...buildIdentifierInputProperties,
|
|
41152
41220
|
testNameId: { type: "string", description: "Test name ID (optional)" }
|
|
41153
|
-
}
|
|
41154
|
-
required: ["buildId"]
|
|
41221
|
+
}
|
|
41155
41222
|
},
|
|
41156
41223
|
handler: async (args) => {
|
|
41157
|
-
const schema =
|
|
41158
|
-
|
|
41159
|
-
|
|
41160
|
-
|
|
41224
|
+
const schema = buildIdentifierSchema.and(
|
|
41225
|
+
import_zod4.z.object({
|
|
41226
|
+
testNameId: import_zod4.z.string().min(1).optional()
|
|
41227
|
+
})
|
|
41228
|
+
);
|
|
41161
41229
|
return runTool(
|
|
41162
41230
|
"get_test_details",
|
|
41163
41231
|
schema,
|
|
41164
41232
|
async (typed) => {
|
|
41165
41233
|
const adapter = createAdapterFromTeamCityAPI(TeamCityAPI.getInstance());
|
|
41166
|
-
|
|
41234
|
+
const { locator: buildLocator } = resolveBuildLocator(typed);
|
|
41235
|
+
let locator = `build:(${buildLocator})`;
|
|
41167
41236
|
if (typed.testNameId) locator += `,test:(id:${typed.testNameId})`;
|
|
41168
41237
|
const response = await adapter.modules.tests.getAllTestOccurrences(locator);
|
|
41169
41238
|
return json(response.data);
|
|
@@ -41178,20 +41247,20 @@ var DEV_TOOLS = [
|
|
|
41178
41247
|
inputSchema: {
|
|
41179
41248
|
type: "object",
|
|
41180
41249
|
properties: {
|
|
41181
|
-
|
|
41182
|
-
}
|
|
41183
|
-
required: ["buildId"]
|
|
41250
|
+
...buildIdentifierInputProperties
|
|
41251
|
+
}
|
|
41184
41252
|
},
|
|
41185
41253
|
handler: async (args) => {
|
|
41186
|
-
const schema =
|
|
41254
|
+
const schema = buildIdentifierSchema;
|
|
41187
41255
|
return runTool(
|
|
41188
41256
|
"analyze_build_problems",
|
|
41189
41257
|
schema,
|
|
41190
41258
|
async (typed) => {
|
|
41191
41259
|
const adapter = createAdapterFromTeamCityAPI(TeamCityAPI.getInstance());
|
|
41192
|
-
const
|
|
41193
|
-
const
|
|
41194
|
-
const
|
|
41260
|
+
const { locator: buildLocator } = resolveBuildLocator(typed);
|
|
41261
|
+
const build = await adapter.getBuild(buildLocator);
|
|
41262
|
+
const problems = await adapter.modules.builds.getBuildProblems(buildLocator);
|
|
41263
|
+
const failures = await adapter.listTestFailures(buildLocator);
|
|
41195
41264
|
return json({
|
|
41196
41265
|
buildStatus: build.status,
|
|
41197
41266
|
statusText: build.statusText,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@daghis/teamcity-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "Model Control Protocol server for TeamCity CI/CD integration with AI coding assistants",
|
|
5
5
|
"mcpName": "io.github.Daghis/teamcity",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"teamcity-mcp": "dist/index.js"
|
|
10
10
|
},
|
|
11
11
|
"engines": {
|
|
12
|
-
"node": ">=20.
|
|
12
|
+
"node": ">=20.19.0"
|
|
13
13
|
},
|
|
14
14
|
"scripts": {
|
|
15
15
|
"dev": "node ./node_modules/tsx/dist/cli.mjs watch src/index.ts",
|
|
@@ -75,18 +75,18 @@
|
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"@codecov/bundler-plugin-core": "^1.9.1",
|
|
77
77
|
"@esbuild-plugins/tsconfig-paths": "^0.1.2",
|
|
78
|
+
"@eslint/js": "^10.0.1",
|
|
78
79
|
"@trivago/prettier-plugin-sort-imports": "^6.0.1",
|
|
79
80
|
"@types/jest": "^30.0.0",
|
|
80
81
|
"@types/js-yaml": "^4.0.9",
|
|
81
82
|
"@types/node": "^25.0.2",
|
|
82
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
83
|
-
"@typescript-eslint/parser": "^8.
|
|
83
|
+
"@typescript-eslint/eslint-plugin": "^8.57.0",
|
|
84
|
+
"@typescript-eslint/parser": "^8.57.0",
|
|
84
85
|
"esbuild": "^0.27.0",
|
|
85
|
-
"eslint": "^
|
|
86
|
+
"eslint": "^10.0.3",
|
|
86
87
|
"eslint-config-prettier": "^10.1.8",
|
|
87
|
-
"eslint-import-resolver-typescript": "^4.4.4",
|
|
88
|
-
"eslint-plugin-import": "^2.32.0",
|
|
89
88
|
"eslint-plugin-prettier": "^5.0.1",
|
|
89
|
+
"globals": "^17.4.0",
|
|
90
90
|
"jest": "^30.1.3",
|
|
91
91
|
"jest-junit": "^16.0.0",
|
|
92
92
|
"js-yaml": "^4.1.1",
|
package/server.json
CHANGED
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
9
|
"websiteUrl": "https://github.com/Daghis/teamcity-mcp",
|
|
10
|
-
"version": "2.
|
|
10
|
+
"version": "2.3.1",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
15
15
|
"identifier": "@daghis/teamcity-mcp",
|
|
16
|
-
"version": "2.
|
|
16
|
+
"version": "2.3.1",
|
|
17
17
|
"runtimeHint": "npx",
|
|
18
18
|
"runtimeArguments": [
|
|
19
19
|
{
|