@daghis/teamcity-mcp 1.3.4 → 1.4.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 +14 -0
- package/dist/index.js +87 -40
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.4.0](https://github.com/Daghis/teamcity-mcp/compare/v1.3.5...v1.4.0) (2025-09-20)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **tests:** add batched mcp tool execution ([#163](https://github.com/Daghis/teamcity-mcp/issues/163)) ([5f48060](https://github.com/Daghis/teamcity-mcp/commit/5f4806043b95686d5dac41a9d67515740b82a3f8)), closes [#162](https://github.com/Daghis/teamcity-mcp/issues/162)
|
|
9
|
+
|
|
10
|
+
## [1.3.5](https://github.com/Daghis/teamcity-mcp/compare/v1.3.4...v1.3.5) (2025-09-19)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **tools:** repair manage_build_steps updates ([#154](https://github.com/Daghis/teamcity-mcp/issues/154)) ([b557e44](https://github.com/Daghis/teamcity-mcp/commit/b557e4424d5129de9d3b6e3240e1a876488da040))
|
|
16
|
+
|
|
3
17
|
## [1.3.4](https://github.com/Daghis/teamcity-mcp/compare/v1.3.3...v1.3.4) (2025-09-19)
|
|
4
18
|
|
|
5
19
|
|
package/dist/index.js
CHANGED
|
@@ -1317,6 +1317,9 @@ var BuildConfigurationUpdateManager = class {
|
|
|
1317
1317
|
}
|
|
1318
1318
|
};
|
|
1319
1319
|
|
|
1320
|
+
// src/teamcity/utils/build-locator.ts
|
|
1321
|
+
var toBuildLocator = (buildId) => buildId.includes(":") ? buildId : `id:${buildId}`;
|
|
1322
|
+
|
|
1320
1323
|
// src/teamcity/build-results-manager.ts
|
|
1321
1324
|
var BuildResultsManager = class _BuildResultsManager {
|
|
1322
1325
|
client;
|
|
@@ -1399,7 +1402,7 @@ var BuildResultsManager = class _BuildResultsManager {
|
|
|
1399
1402
|
*/
|
|
1400
1403
|
async fetchBuildSummary(buildId) {
|
|
1401
1404
|
const response = await this.client.modules.builds.getBuild(
|
|
1402
|
-
|
|
1405
|
+
toBuildLocator(buildId),
|
|
1403
1406
|
_BuildResultsManager.fields
|
|
1404
1407
|
);
|
|
1405
1408
|
return response.data;
|
|
@@ -1455,7 +1458,7 @@ var BuildResultsManager = class _BuildResultsManager {
|
|
|
1455
1458
|
async fetchArtifacts(buildId, options) {
|
|
1456
1459
|
try {
|
|
1457
1460
|
const response = await this.client.modules.builds.getFilesListOfBuild(
|
|
1458
|
-
|
|
1461
|
+
toBuildLocator(buildId)
|
|
1459
1462
|
);
|
|
1460
1463
|
const artifactListing = response.data;
|
|
1461
1464
|
let artifacts = artifactListing.file ?? [];
|
|
@@ -1507,7 +1510,7 @@ var BuildResultsManager = class _BuildResultsManager {
|
|
|
1507
1510
|
async fetchStatistics(buildId) {
|
|
1508
1511
|
try {
|
|
1509
1512
|
const response = await this.client.modules.builds.getBuildStatisticValues(
|
|
1510
|
-
|
|
1513
|
+
toBuildLocator(buildId)
|
|
1511
1514
|
);
|
|
1512
1515
|
const payload = response.data;
|
|
1513
1516
|
const properties = payload.property ?? [];
|
|
@@ -1573,8 +1576,9 @@ var BuildResultsManager = class _BuildResultsManager {
|
|
|
1573
1576
|
*/
|
|
1574
1577
|
async fetchDependencies(buildId) {
|
|
1575
1578
|
try {
|
|
1576
|
-
const response = await this.client.
|
|
1577
|
-
(
|
|
1579
|
+
const response = await this.client.modules.builds.getAllBuilds(
|
|
1580
|
+
`snapshotDependency:(to:(id:${buildId}))`,
|
|
1581
|
+
"build(id,number,buildTypeId,status)"
|
|
1578
1582
|
);
|
|
1579
1583
|
const depsData = response.data;
|
|
1580
1584
|
const builds = depsData.build ?? [];
|
|
@@ -1606,20 +1610,25 @@ var BuildResultsManager = class _BuildResultsManager {
|
|
|
1606
1610
|
const baseUrl = this.client.getApiConfig().baseUrl;
|
|
1607
1611
|
return baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
1608
1612
|
}
|
|
1609
|
-
toBuildLocator(buildId) {
|
|
1610
|
-
return buildId.includes(":") ? buildId : `id:${buildId}`;
|
|
1611
|
-
}
|
|
1612
1613
|
async downloadArtifactContent(buildId, artifactPath) {
|
|
1613
1614
|
const normalizedPath = artifactPath.split("/").map((segment) => encodeURIComponent(segment)).join("/");
|
|
1614
|
-
const
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1615
|
+
const buildLocator = toBuildLocator(buildId);
|
|
1616
|
+
const response = await this.client.modules.builds.downloadFileOfBuild(
|
|
1617
|
+
`content/${normalizedPath}`,
|
|
1618
|
+
buildLocator,
|
|
1619
|
+
void 0,
|
|
1620
|
+
void 0,
|
|
1621
|
+
{ responseType: "arraybuffer" }
|
|
1621
1622
|
);
|
|
1622
|
-
|
|
1623
|
+
const axiosResponse = response;
|
|
1624
|
+
const { data } = axiosResponse;
|
|
1625
|
+
if (data instanceof ArrayBuffer) {
|
|
1626
|
+
return data.slice(0);
|
|
1627
|
+
}
|
|
1628
|
+
if (Buffer.isBuffer(data)) {
|
|
1629
|
+
return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
|
|
1630
|
+
}
|
|
1631
|
+
throw new Error("Artifact download returned unexpected binary payload type");
|
|
1623
1632
|
}
|
|
1624
1633
|
/**
|
|
1625
1634
|
* Parse TeamCity date format
|
|
@@ -1693,12 +1702,24 @@ var BuildResultsManager = class _BuildResultsManager {
|
|
|
1693
1702
|
// src/teamcity/client-adapter.ts
|
|
1694
1703
|
var import_axios = __toESM(require("axios"));
|
|
1695
1704
|
var FALLBACK_BASE_URL = "http://not-configured";
|
|
1705
|
+
var toRecord = (value) => {
|
|
1706
|
+
if (typeof value === "object" && value !== null) {
|
|
1707
|
+
return value;
|
|
1708
|
+
}
|
|
1709
|
+
return {};
|
|
1710
|
+
};
|
|
1711
|
+
var createBuildApiBridge = (api) => ({
|
|
1712
|
+
getAllBuilds: (locator, fields, options) => api.getAllBuilds(locator, fields, options),
|
|
1713
|
+
getBuild: (buildLocator, fields, options) => api.getBuild(buildLocator, fields, options),
|
|
1714
|
+
getMultipleBuilds: (locator, fields, options) => api.getMultipleBuilds(locator, fields, options),
|
|
1715
|
+
getBuildProblems: (buildLocator, fields, options) => api.getBuildProblems(buildLocator, fields, options)
|
|
1716
|
+
});
|
|
1696
1717
|
var resolveModules = (api) => {
|
|
1697
1718
|
const candidate = api.modules;
|
|
1698
1719
|
if (candidate != null) {
|
|
1699
1720
|
return candidate;
|
|
1700
1721
|
}
|
|
1701
|
-
const legacy = api;
|
|
1722
|
+
const legacy = toRecord(api);
|
|
1702
1723
|
const pick = (key) => legacy[key] ?? {};
|
|
1703
1724
|
const fallback = {
|
|
1704
1725
|
agents: pick("agents"),
|
|
@@ -1760,7 +1781,7 @@ function createAdapterFromTeamCityAPI(api, options = {}) {
|
|
|
1760
1781
|
});
|
|
1761
1782
|
}
|
|
1762
1783
|
const request = async (fn) => fn({ axios: httpInstance, baseUrl: resolvedApiConfig.baseUrl, requestId: void 0 });
|
|
1763
|
-
const buildApi = modules.builds;
|
|
1784
|
+
const buildApi = createBuildApiBridge(modules.builds);
|
|
1764
1785
|
return {
|
|
1765
1786
|
modules,
|
|
1766
1787
|
http: httpInstance,
|
|
@@ -2481,6 +2502,12 @@ var esm_default = axiosRetry;
|
|
|
2481
2502
|
// src/teamcity/auth.ts
|
|
2482
2503
|
var import_crypto = require("crypto");
|
|
2483
2504
|
init_errors();
|
|
2505
|
+
var asTimingMetaContainer = (value) => {
|
|
2506
|
+
if (typeof value === "object" && value !== null) {
|
|
2507
|
+
return value;
|
|
2508
|
+
}
|
|
2509
|
+
return null;
|
|
2510
|
+
};
|
|
2484
2511
|
function generateRequestId() {
|
|
2485
2512
|
return (0, import_crypto.randomUUID)();
|
|
2486
2513
|
}
|
|
@@ -2489,7 +2516,10 @@ function addRequestId(config2) {
|
|
|
2489
2516
|
config2.headers["X-Request-ID"] = requestId;
|
|
2490
2517
|
const configWithId = config2;
|
|
2491
2518
|
configWithId.requestId = requestId;
|
|
2492
|
-
|
|
2519
|
+
const metaContainer = asTimingMetaContainer(config2);
|
|
2520
|
+
if (metaContainer) {
|
|
2521
|
+
metaContainer._tcMeta = { start: Date.now() };
|
|
2522
|
+
}
|
|
2493
2523
|
info("Starting TeamCity API request", {
|
|
2494
2524
|
requestId,
|
|
2495
2525
|
method: config2.method?.toUpperCase(),
|
|
@@ -2503,7 +2533,7 @@ function addRequestId(config2) {
|
|
|
2503
2533
|
}
|
|
2504
2534
|
function logResponse(response) {
|
|
2505
2535
|
const requestId = response.config?.requestId;
|
|
2506
|
-
const meta = response.config
|
|
2536
|
+
const meta = asTimingMetaContainer(response.config)?._tcMeta;
|
|
2507
2537
|
const headers = response.headers;
|
|
2508
2538
|
const headerDuration = headers?.["x-response-time"] ?? headers?.["x-response-duration"];
|
|
2509
2539
|
const duration = headerDuration ?? (meta?.start ? Date.now() - meta.start : void 0);
|
|
@@ -2519,7 +2549,7 @@ function logResponse(response) {
|
|
|
2519
2549
|
function logAndTransformError(error2) {
|
|
2520
2550
|
const requestId = error2.config?.requestId;
|
|
2521
2551
|
const tcError = TeamCityAPIError.fromAxiosError(error2, requestId);
|
|
2522
|
-
const meta = error2.config?._tcMeta;
|
|
2552
|
+
const meta = asTimingMetaContainer(error2.config)?._tcMeta;
|
|
2523
2553
|
const duration = meta?.start ? Date.now() - meta.start : void 0;
|
|
2524
2554
|
const sanitize = (val) => {
|
|
2525
2555
|
const redact = (s) => s.replace(/(token[=:\s]*)[^\s&]+/gi, "$1***").replace(/(password[=:\s]*)[^\s&]+/gi, "$1***").replace(/(apikey[=:\s]*)[^\s&]+/gi, "$1***").replace(/(authorization[=:\s:]*)[^\s&]+/gi, "$1***");
|
|
@@ -36242,7 +36272,7 @@ var TeamCityAPI = class _TeamCityAPI {
|
|
|
36242
36272
|
return response.data;
|
|
36243
36273
|
}
|
|
36244
36274
|
async getBuild(buildId) {
|
|
36245
|
-
const response = await this.builds.getBuild(
|
|
36275
|
+
const response = await this.builds.getBuild(toBuildLocator(buildId));
|
|
36246
36276
|
return response.data;
|
|
36247
36277
|
}
|
|
36248
36278
|
async triggerBuild(buildTypeId, branchName, comment) {
|
|
@@ -36333,7 +36363,7 @@ var TeamCityAPI = class _TeamCityAPI {
|
|
|
36333
36363
|
}
|
|
36334
36364
|
async listBuildArtifacts(buildId, options) {
|
|
36335
36365
|
return this.builds.getFilesListOfBuild(
|
|
36336
|
-
|
|
36366
|
+
toBuildLocator(buildId),
|
|
36337
36367
|
options?.basePath,
|
|
36338
36368
|
options?.locator,
|
|
36339
36369
|
options?.fields,
|
|
@@ -36351,16 +36381,13 @@ var TeamCityAPI = class _TeamCityAPI {
|
|
|
36351
36381
|
);
|
|
36352
36382
|
}
|
|
36353
36383
|
async getBuildStatistics(buildId, fields) {
|
|
36354
|
-
return this.builds.getBuildStatisticValues(
|
|
36384
|
+
return this.builds.getBuildStatisticValues(toBuildLocator(buildId), fields);
|
|
36355
36385
|
}
|
|
36356
36386
|
async listChangesForBuild(buildId, fields) {
|
|
36357
36387
|
return this.changes.getAllChanges(`build:(id:${buildId})`, fields);
|
|
36358
36388
|
}
|
|
36359
36389
|
async listSnapshotDependencies(buildId) {
|
|
36360
|
-
const response = await this.builds.getBuild(
|
|
36361
|
-
this.toBuildLocator(buildId),
|
|
36362
|
-
"snapshot-dependencies"
|
|
36363
|
-
);
|
|
36390
|
+
const response = await this.builds.getBuild(toBuildLocator(buildId), "snapshot-dependencies");
|
|
36364
36391
|
const dependencies = response.data["snapshot-dependencies"];
|
|
36365
36392
|
if (dependencies == null) {
|
|
36366
36393
|
return response;
|
|
@@ -36393,9 +36420,6 @@ var TeamCityAPI = class _TeamCityAPI {
|
|
|
36393
36420
|
this.instance = void 0;
|
|
36394
36421
|
this.instanceConfig = void 0;
|
|
36395
36422
|
}
|
|
36396
|
-
toBuildLocator(buildId) {
|
|
36397
|
-
return buildId.includes(":") ? buildId : `id:${buildId}`;
|
|
36398
|
-
}
|
|
36399
36423
|
createApi(apiCtor) {
|
|
36400
36424
|
return new apiCtor(this.config, this.baseUrl, this.axiosInstance);
|
|
36401
36425
|
}
|
|
@@ -39215,16 +39239,39 @@ var FULL_MODE_TOOLS = [
|
|
|
39215
39239
|
error: "Step ID is required for update action"
|
|
39216
39240
|
});
|
|
39217
39241
|
}
|
|
39218
|
-
const
|
|
39219
|
-
|
|
39220
|
-
|
|
39221
|
-
|
|
39222
|
-
|
|
39223
|
-
|
|
39224
|
-
|
|
39225
|
-
|
|
39226
|
-
|
|
39242
|
+
const updatePayload = {};
|
|
39243
|
+
if (typedArgs.name != null) {
|
|
39244
|
+
updatePayload["name"] = typedArgs.name;
|
|
39245
|
+
}
|
|
39246
|
+
if (typedArgs.type != null) {
|
|
39247
|
+
updatePayload["type"] = typedArgs.type;
|
|
39248
|
+
}
|
|
39249
|
+
const rawProps = typedArgs.properties ?? {};
|
|
39250
|
+
const stepProps = Object.fromEntries(
|
|
39251
|
+
Object.entries(rawProps).map(([k, v]) => [k, String(v)])
|
|
39252
|
+
);
|
|
39253
|
+
if (stepProps["script.content"]) {
|
|
39254
|
+
stepProps["use.custom.script"] = stepProps["use.custom.script"] ?? "true";
|
|
39255
|
+
stepProps["script.type"] = stepProps["script.type"] ?? "customScript";
|
|
39256
|
+
}
|
|
39257
|
+
if (Object.keys(stepProps).length > 0) {
|
|
39258
|
+
updatePayload["properties"] = {
|
|
39259
|
+
property: Object.entries(stepProps).map(([name, value]) => ({ name, value }))
|
|
39260
|
+
};
|
|
39227
39261
|
}
|
|
39262
|
+
if (Object.keys(updatePayload).length === 0) {
|
|
39263
|
+
return json({
|
|
39264
|
+
success: false,
|
|
39265
|
+
action: "update_build_step",
|
|
39266
|
+
error: "No update fields provided"
|
|
39267
|
+
});
|
|
39268
|
+
}
|
|
39269
|
+
await adapter.modules.buildTypes.replaceBuildStep(
|
|
39270
|
+
typedArgs.buildTypeId,
|
|
39271
|
+
typedArgs.stepId,
|
|
39272
|
+
void 0,
|
|
39273
|
+
updatePayload
|
|
39274
|
+
);
|
|
39228
39275
|
return json({
|
|
39229
39276
|
success: true,
|
|
39230
39277
|
action: "update_build_step",
|