@daghis/teamcity-mcp 1.12.0 → 1.13.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/README.md +30 -0
- package/dist/index.js +330 -46
- package/package.json +2 -2
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.13.0](https://github.com/Daghis/teamcity-mcp/compare/teamcity-mcp-v1.12.1...teamcity-mcp-v1.13.0) (2025-12-22)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add CLI argument support for Windows workaround ([#320](https://github.com/Daghis/teamcity-mcp/issues/320)) ([#326](https://github.com/Daghis/teamcity-mcp/issues/326)) ([cc05a4d](https://github.com/Daghis/teamcity-mcp/commit/cc05a4dd19c1d7e1f547cdd35bb910035141909d))
|
|
9
|
+
|
|
10
|
+
## [1.12.1](https://github.com/Daghis/teamcity-mcp/compare/teamcity-mcp-v1.12.0...teamcity-mcp-v1.12.1) (2025-12-22)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* handle queued builds in get_build and get_build_status ([#324](https://github.com/Daghis/teamcity-mcp/issues/324)) ([4cb2dab](https://github.com/Daghis/teamcity-mcp/commit/4cb2dabfc9161e07708a899622d78b886742459d))
|
|
16
|
+
|
|
3
17
|
## [1.12.0](https://github.com/Daghis/teamcity-mcp/compare/teamcity-mcp-v1.11.20...teamcity-mcp-v1.12.0) (2025-12-06)
|
|
4
18
|
|
|
5
19
|
|
package/README.md
CHANGED
|
@@ -85,10 +85,40 @@ npx -y @daghis/teamcity-mcp
|
|
|
85
85
|
- `claude mcp add [-s user] teamcity -- npx -y @daghis/teamcity-mcp`
|
|
86
86
|
- With env vars (if not using .env):
|
|
87
87
|
- `claude mcp add [-s user] teamcity -- env TEAMCITY_URL="https://teamcity.example.com" TEAMCITY_TOKEN="tc_<your_token>" MCP_MODE=dev npx -y @daghis/teamcity-mcp`
|
|
88
|
+
- With CLI arguments (recommended for Windows):
|
|
89
|
+
- `claude mcp add [-s user] teamcity -- npx -y @daghis/teamcity-mcp --url "https://teamcity.example.com" --token "tc_<your_token>" --mode dev`
|
|
88
90
|
- Context usage (Opus 4.1, estimates):
|
|
89
91
|
- Dev (default): ~14k tokens for MCP tools
|
|
90
92
|
- Full (`MCP_MODE=full`): ~26k tokens for MCP tools
|
|
91
93
|
|
|
94
|
+
### Windows Users
|
|
95
|
+
|
|
96
|
+
On Windows, Claude Code's MCP configuration may not properly merge environment variables. Use CLI arguments as a workaround:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"mcpServers": {
|
|
101
|
+
"teamcity": {
|
|
102
|
+
"command": "npx",
|
|
103
|
+
"args": ["-y", "@daghis/teamcity-mcp", "--url", "https://teamcity.example.com", "--token", "YOUR_TOKEN"]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or use a config file for better security (token not visible in process list):
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"mcpServers": {
|
|
114
|
+
"teamcity": {
|
|
115
|
+
"command": "npx",
|
|
116
|
+
"args": ["-y", "@daghis/teamcity-mcp", "--config", "C:\\path\\to\\teamcity.env"]
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
92
122
|
## Configuration
|
|
93
123
|
|
|
94
124
|
Environment is validated centrally with Zod. Supported variables and defaults:
|
package/dist/index.js
CHANGED
|
@@ -221,6 +221,12 @@ var build_status_manager_exports = {};
|
|
|
221
221
|
__export(build_status_manager_exports, {
|
|
222
222
|
BuildStatusManager: () => BuildStatusManager
|
|
223
223
|
});
|
|
224
|
+
function isAxios404(error3) {
|
|
225
|
+
return error3 != null && typeof error3 === "object" && "response" in error3 && error3.response?.status === 404;
|
|
226
|
+
}
|
|
227
|
+
function isAxios403(error3) {
|
|
228
|
+
return error3 != null && typeof error3 === "object" && "response" in error3 && error3.response?.status === 403;
|
|
229
|
+
}
|
|
224
230
|
var BuildStatusManager;
|
|
225
231
|
var init_build_status_manager = __esm({
|
|
226
232
|
"src/teamcity/build-status-manager.ts"() {
|
|
@@ -235,7 +241,11 @@ var init_build_status_manager = __esm({
|
|
|
235
241
|
this.cache = /* @__PURE__ */ new Map();
|
|
236
242
|
}
|
|
237
243
|
/**
|
|
238
|
-
* Get build status by ID or number
|
|
244
|
+
* Get build status by ID or number.
|
|
245
|
+
* Uses 3-step fallback to handle builds in queue and race conditions:
|
|
246
|
+
* 1. Try builds endpoint
|
|
247
|
+
* 2. On 404, try build queue (build may be queued)
|
|
248
|
+
* 3. On 404 again, retry builds endpoint (build may have left queue between checks)
|
|
239
249
|
*/
|
|
240
250
|
async getBuildStatus(options) {
|
|
241
251
|
if (!options.buildId && !options.buildNumber) {
|
|
@@ -252,41 +262,93 @@ var init_build_status_manager = __esm({
|
|
|
252
262
|
}
|
|
253
263
|
}
|
|
254
264
|
try {
|
|
255
|
-
|
|
256
|
-
if (options.buildId) {
|
|
257
|
-
const response = await this.client.builds.getBuild(
|
|
258
|
-
`id:${options.buildId}`,
|
|
259
|
-
this.getFieldSelection(options)
|
|
260
|
-
);
|
|
261
|
-
buildData = response.data;
|
|
262
|
-
} else {
|
|
263
|
-
const locator = this.buildLocator(options);
|
|
264
|
-
const response = await this.client.builds.getBuild(
|
|
265
|
-
locator,
|
|
266
|
-
this.getFieldSelection(options)
|
|
267
|
-
);
|
|
268
|
-
buildData = response.data;
|
|
269
|
-
}
|
|
270
|
-
if (buildData == null) {
|
|
271
|
-
throw new BuildNotFoundError("Build data is undefined");
|
|
272
|
-
}
|
|
273
|
-
const result = this.transformBuildResponse(buildData, options);
|
|
274
|
-
if (result.state === "finished" || result.state === "canceled") {
|
|
275
|
-
this.setCachedResult(cacheKey, result);
|
|
276
|
-
}
|
|
277
|
-
return result;
|
|
265
|
+
return await this.getBuildStatusFromBuildsEndpoint(options, cacheKey);
|
|
278
266
|
} catch (error3) {
|
|
279
|
-
if (error3
|
|
280
|
-
|
|
267
|
+
if (!isAxios404(error3) || !options.buildId) {
|
|
268
|
+
this.handleBuildStatusError(error3, options);
|
|
281
269
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
270
|
+
}
|
|
271
|
+
const buildId = options.buildId;
|
|
272
|
+
try {
|
|
273
|
+
return await this.getQueuedBuildStatus(buildId);
|
|
274
|
+
} catch (queueError) {
|
|
275
|
+
if (!isAxios404(queueError)) {
|
|
276
|
+
this.handleBuildStatusError(queueError, options);
|
|
286
277
|
}
|
|
287
|
-
|
|
278
|
+
}
|
|
279
|
+
try {
|
|
280
|
+
return await this.getBuildStatusFromBuildsEndpoint(options, cacheKey);
|
|
281
|
+
} catch (error3) {
|
|
282
|
+
this.handleBuildStatusError(error3, options);
|
|
288
283
|
}
|
|
289
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* Get build status from the builds endpoint
|
|
287
|
+
*/
|
|
288
|
+
async getBuildStatusFromBuildsEndpoint(options, cacheKey) {
|
|
289
|
+
let buildData;
|
|
290
|
+
if (options.buildId) {
|
|
291
|
+
const response = await this.client.builds.getBuild(
|
|
292
|
+
`id:${options.buildId}`,
|
|
293
|
+
this.getFieldSelection(options)
|
|
294
|
+
);
|
|
295
|
+
buildData = response.data;
|
|
296
|
+
} else {
|
|
297
|
+
const locator = this.buildLocator(options);
|
|
298
|
+
const response = await this.client.builds.getBuild(locator, this.getFieldSelection(options));
|
|
299
|
+
buildData = response.data;
|
|
300
|
+
}
|
|
301
|
+
if (buildData == null) {
|
|
302
|
+
throw new BuildNotFoundError("Build data is undefined");
|
|
303
|
+
}
|
|
304
|
+
const result = this.transformBuildResponse(buildData, options);
|
|
305
|
+
if (result.state === "finished" || result.state === "canceled") {
|
|
306
|
+
this.setCachedResult(cacheKey, result);
|
|
307
|
+
}
|
|
308
|
+
return result;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Get build status from the build queue
|
|
312
|
+
*/
|
|
313
|
+
async getQueuedBuildStatus(buildId) {
|
|
314
|
+
const response = await this.client.modules.buildQueue.getQueuedBuild(
|
|
315
|
+
`id:${buildId}`,
|
|
316
|
+
"id,number,state,status,buildTypeId,branchName,webUrl,queuedDate,waitReason"
|
|
317
|
+
);
|
|
318
|
+
const queuedBuild = response.data;
|
|
319
|
+
if (queuedBuild == null) {
|
|
320
|
+
throw new BuildNotFoundError("Queued build data is undefined");
|
|
321
|
+
}
|
|
322
|
+
const result = {
|
|
323
|
+
buildId: String(queuedBuild.id),
|
|
324
|
+
buildNumber: queuedBuild.number,
|
|
325
|
+
buildTypeId: queuedBuild.buildTypeId,
|
|
326
|
+
state: "queued",
|
|
327
|
+
status: void 0,
|
|
328
|
+
percentageComplete: 0,
|
|
329
|
+
branchName: queuedBuild.branchName,
|
|
330
|
+
webUrl: queuedBuild.webUrl,
|
|
331
|
+
waitReason: queuedBuild.waitReason
|
|
332
|
+
};
|
|
333
|
+
if (queuedBuild.queuedDate) {
|
|
334
|
+
result.queuedDate = this.parseDate(queuedBuild.queuedDate);
|
|
335
|
+
}
|
|
336
|
+
return result;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Handle and re-throw build status errors with appropriate error types
|
|
340
|
+
*/
|
|
341
|
+
handleBuildStatusError(error3, options) {
|
|
342
|
+
if (isAxios404(error3)) {
|
|
343
|
+
throw new BuildNotFoundError(`Build not found: ${options.buildId ?? options.buildNumber}`);
|
|
344
|
+
}
|
|
345
|
+
if (isAxios403(error3)) {
|
|
346
|
+
throw new BuildAccessDeniedError(
|
|
347
|
+
`Access denied to build: ${options.buildId ?? options.buildNumber}`
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
throw error3;
|
|
351
|
+
}
|
|
290
352
|
/**
|
|
291
353
|
* Get build status using custom locator
|
|
292
354
|
*/
|
|
@@ -679,6 +741,185 @@ async function startServerLifecycle(server, transport) {
|
|
|
679
741
|
});
|
|
680
742
|
}
|
|
681
743
|
|
|
744
|
+
// src/utils/cli-args.ts
|
|
745
|
+
var import_fs = require("fs");
|
|
746
|
+
var import_path = require("path");
|
|
747
|
+
function parseCliArgs(argv) {
|
|
748
|
+
const result = {
|
|
749
|
+
help: false,
|
|
750
|
+
version: false
|
|
751
|
+
};
|
|
752
|
+
for (let i = 0; i < argv.length; i++) {
|
|
753
|
+
const arg = argv[i];
|
|
754
|
+
if (arg === void 0) continue;
|
|
755
|
+
if (arg === "--help" || arg === "-h") {
|
|
756
|
+
result.help = true;
|
|
757
|
+
continue;
|
|
758
|
+
}
|
|
759
|
+
if (arg === "--version" || arg === "-v") {
|
|
760
|
+
result.version = true;
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
if (arg.startsWith("--url=")) {
|
|
764
|
+
result.url = arg.slice("--url=".length);
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
if (arg.startsWith("--token=")) {
|
|
768
|
+
result.token = arg.slice("--token=".length);
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
if (arg.startsWith("--mode=")) {
|
|
772
|
+
const mode = arg.slice("--mode=".length);
|
|
773
|
+
if (mode === "dev" || mode === "full") {
|
|
774
|
+
result.mode = mode;
|
|
775
|
+
} else if (mode.length > 0) {
|
|
776
|
+
process.stderr.write(
|
|
777
|
+
`Warning: Invalid mode '${mode}'. Valid values are 'dev' or 'full'.
|
|
778
|
+
`
|
|
779
|
+
);
|
|
780
|
+
}
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
if (arg.startsWith("--config=")) {
|
|
784
|
+
result.config = arg.slice("--config=".length);
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
787
|
+
const nextArg = argv[i + 1];
|
|
788
|
+
if (nextArg !== void 0 && !nextArg.startsWith("-")) {
|
|
789
|
+
if (arg === "--url") {
|
|
790
|
+
result.url = nextArg;
|
|
791
|
+
i++;
|
|
792
|
+
continue;
|
|
793
|
+
}
|
|
794
|
+
if (arg === "--token") {
|
|
795
|
+
result.token = nextArg;
|
|
796
|
+
i++;
|
|
797
|
+
continue;
|
|
798
|
+
}
|
|
799
|
+
if (arg === "--mode") {
|
|
800
|
+
if (nextArg === "dev" || nextArg === "full") {
|
|
801
|
+
result.mode = nextArg;
|
|
802
|
+
} else {
|
|
803
|
+
process.stderr.write(
|
|
804
|
+
`Warning: Invalid mode '${nextArg}'. Valid values are 'dev' or 'full'.
|
|
805
|
+
`
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
i++;
|
|
809
|
+
continue;
|
|
810
|
+
}
|
|
811
|
+
if (arg === "--config") {
|
|
812
|
+
result.config = nextArg;
|
|
813
|
+
i++;
|
|
814
|
+
continue;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
return result;
|
|
819
|
+
}
|
|
820
|
+
function getVersion() {
|
|
821
|
+
try {
|
|
822
|
+
const possiblePaths = [
|
|
823
|
+
(0, import_path.join)(__dirname, "../package.json"),
|
|
824
|
+
// bundled: dist/ -> package.json
|
|
825
|
+
(0, import_path.join)(__dirname, "../../package.json")
|
|
826
|
+
// source: src/utils/ -> package.json
|
|
827
|
+
];
|
|
828
|
+
for (const packagePath of possiblePaths) {
|
|
829
|
+
try {
|
|
830
|
+
const packageJson = JSON.parse((0, import_fs.readFileSync)(packagePath, "utf-8"));
|
|
831
|
+
if (packageJson.version) {
|
|
832
|
+
return packageJson.version;
|
|
833
|
+
}
|
|
834
|
+
} catch {
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
return "unknown";
|
|
838
|
+
} catch {
|
|
839
|
+
return "unknown";
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
function getHelpText() {
|
|
843
|
+
const version = getVersion();
|
|
844
|
+
return `teamcity-mcp v${version}
|
|
845
|
+
Model Context Protocol server for TeamCity CI/CD integration
|
|
846
|
+
|
|
847
|
+
USAGE:
|
|
848
|
+
teamcity-mcp [OPTIONS]
|
|
849
|
+
|
|
850
|
+
OPTIONS:
|
|
851
|
+
--url <url> TeamCity server URL (e.g., https://tc.example.com)
|
|
852
|
+
--token <token> TeamCity API token for authentication
|
|
853
|
+
--mode <dev|full> Tool exposure mode: dev (limited) or full (all tools)
|
|
854
|
+
--config <path> Path to .env format configuration file
|
|
855
|
+
|
|
856
|
+
-h, --help Show this help message
|
|
857
|
+
-v, --version Show version number
|
|
858
|
+
|
|
859
|
+
CONFIGURATION PRECEDENCE (highest to lowest):
|
|
860
|
+
1. CLI arguments (--url, --token, --mode)
|
|
861
|
+
2. Config file (--config)
|
|
862
|
+
3. Environment variables (TEAMCITY_URL, TEAMCITY_TOKEN, MCP_MODE)
|
|
863
|
+
4. .env file in current directory
|
|
864
|
+
|
|
865
|
+
SECURITY WARNING:
|
|
866
|
+
Avoid using --token on the command line when possible. The token value
|
|
867
|
+
is visible in process lists and may be logged in shell history. For
|
|
868
|
+
production use, prefer environment variables or a config file with
|
|
869
|
+
restricted permissions (chmod 600).
|
|
870
|
+
|
|
871
|
+
EXAMPLES:
|
|
872
|
+
# Using CLI arguments
|
|
873
|
+
teamcity-mcp --url https://tc.example.com --token tc_abc123
|
|
874
|
+
|
|
875
|
+
# Using a config file
|
|
876
|
+
teamcity-mcp --config /path/to/teamcity.env
|
|
877
|
+
|
|
878
|
+
# Override config file with CLI arg
|
|
879
|
+
teamcity-mcp --config prod.env --mode dev
|
|
880
|
+
|
|
881
|
+
CONFIG FILE FORMAT (.env):
|
|
882
|
+
TEAMCITY_URL=https://tc.example.com
|
|
883
|
+
TEAMCITY_TOKEN=tc_abc123
|
|
884
|
+
MCP_MODE=dev
|
|
885
|
+
|
|
886
|
+
For more information, visit: https://github.com/Daghis/teamcity-mcp
|
|
887
|
+
`;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// src/utils/env-file.ts
|
|
891
|
+
var import_dotenv2 = require("dotenv");
|
|
892
|
+
var import_fs2 = require("fs");
|
|
893
|
+
function loadEnvFile(filepath) {
|
|
894
|
+
try {
|
|
895
|
+
const content = (0, import_fs2.readFileSync)(filepath, "utf-8");
|
|
896
|
+
const values = (0, import_dotenv2.parse)(content);
|
|
897
|
+
return {
|
|
898
|
+
success: true,
|
|
899
|
+
values
|
|
900
|
+
};
|
|
901
|
+
} catch (err) {
|
|
902
|
+
const error3 = err instanceof Error ? err : new Error(String(err));
|
|
903
|
+
const errno = err;
|
|
904
|
+
if (errno.code === "ENOENT") {
|
|
905
|
+
return {
|
|
906
|
+
success: false,
|
|
907
|
+
error: `Config file not found: ${filepath}`
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
if (errno.code === "EACCES") {
|
|
911
|
+
return {
|
|
912
|
+
success: false,
|
|
913
|
+
error: `Permission denied reading config file: ${filepath}`
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
return {
|
|
917
|
+
success: false,
|
|
918
|
+
error: `Failed to read config file: ${error3.message}`
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
682
923
|
// src/server.ts
|
|
683
924
|
var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
684
925
|
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
@@ -954,7 +1195,7 @@ function debug2(message, meta) {
|
|
|
954
1195
|
// package.json
|
|
955
1196
|
var package_default = {
|
|
956
1197
|
name: "@daghis/teamcity-mcp",
|
|
957
|
-
version: "1.
|
|
1198
|
+
version: "1.13.0",
|
|
958
1199
|
description: "Model Control Protocol server for TeamCity CI/CD integration with AI coding assistants",
|
|
959
1200
|
mcpName: "io.github.Daghis/teamcity",
|
|
960
1201
|
main: "dist/index.js",
|
|
@@ -1040,7 +1281,7 @@ var package_default = {
|
|
|
1040
1281
|
"@types/jest": "^30.0.0",
|
|
1041
1282
|
"@types/js-yaml": "^4.0.9",
|
|
1042
1283
|
"@types/morgan": "^1.9.9",
|
|
1043
|
-
"@types/node": "^
|
|
1284
|
+
"@types/node": "^25.0.2",
|
|
1044
1285
|
"@typescript-eslint/eslint-plugin": "^8.46.3",
|
|
1045
1286
|
"@typescript-eslint/parser": "^8.46.3",
|
|
1046
1287
|
"axios-retry": "^4.5.0",
|
|
@@ -38578,6 +38819,7 @@ var TeamCityAPI = class _TeamCityAPI {
|
|
|
38578
38819
|
|
|
38579
38820
|
// src/tools.ts
|
|
38580
38821
|
var isReadableStream = (value) => typeof value === "object" && value !== null && typeof value.pipe === "function";
|
|
38822
|
+
var isAxios4042 = (error3) => (0, import_axios36.isAxiosError)(error3) && error3.response?.status === 404;
|
|
38581
38823
|
var sanitizeFileName = (artifactName) => {
|
|
38582
38824
|
const base = (0, import_node_path.basename)(artifactName || "artifact");
|
|
38583
38825
|
const safeBase = base.replace(/[^a-zA-Z0-9._-]/g, "_") || "artifact";
|
|
@@ -39001,7 +39243,7 @@ var DEV_TOOLS = [
|
|
|
39001
39243
|
},
|
|
39002
39244
|
{
|
|
39003
39245
|
name: "get_build",
|
|
39004
|
-
description: "Get details of a specific build",
|
|
39246
|
+
description: "Get details of a specific build (works for both queued and running/finished builds)",
|
|
39005
39247
|
inputSchema: {
|
|
39006
39248
|
type: "object",
|
|
39007
39249
|
properties: {
|
|
@@ -39016,6 +39258,18 @@ var DEV_TOOLS = [
|
|
|
39016
39258
|
schema,
|
|
39017
39259
|
async (typed) => {
|
|
39018
39260
|
const adapter = createAdapterFromTeamCityAPI(TeamCityAPI.getInstance());
|
|
39261
|
+
try {
|
|
39262
|
+
const build2 = await adapter.getBuild(typed.buildId);
|
|
39263
|
+
return json(build2);
|
|
39264
|
+
} catch (error3) {
|
|
39265
|
+
if (!isAxios4042(error3)) throw error3;
|
|
39266
|
+
}
|
|
39267
|
+
try {
|
|
39268
|
+
const qb = await adapter.modules.buildQueue.getQueuedBuild(`id:${typed.buildId}`);
|
|
39269
|
+
return json({ ...qb.data, state: "queued" });
|
|
39270
|
+
} catch (queueError) {
|
|
39271
|
+
if (!isAxios4042(queueError)) throw queueError;
|
|
39272
|
+
}
|
|
39019
39273
|
const build = await adapter.getBuild(typed.buildId);
|
|
39020
39274
|
return json(build);
|
|
39021
39275
|
},
|
|
@@ -39233,21 +39487,19 @@ var DEV_TOOLS = [
|
|
|
39233
39487
|
if (typeof result.queuePosition === "number") {
|
|
39234
39488
|
enrich.canMoveToTop = result.queuePosition > 1;
|
|
39235
39489
|
}
|
|
39236
|
-
|
|
39237
|
-
|
|
39238
|
-
|
|
39239
|
-
|
|
39240
|
-
|
|
39241
|
-
|
|
39242
|
-
|
|
39243
|
-
} catch {
|
|
39244
|
-
}
|
|
39490
|
+
try {
|
|
39491
|
+
const countResp = await adapter.modules.buildQueue.getAllQueuedBuilds(
|
|
39492
|
+
void 0,
|
|
39493
|
+
"count"
|
|
39494
|
+
);
|
|
39495
|
+
enrich.totalQueued = countResp.data.count;
|
|
39496
|
+
} catch {
|
|
39245
39497
|
}
|
|
39246
|
-
if (
|
|
39498
|
+
if (!result.waitReason) {
|
|
39247
39499
|
try {
|
|
39248
39500
|
const targetBuildId = typed.buildId ?? result.buildId;
|
|
39249
39501
|
if (targetBuildId) {
|
|
39250
|
-
const qb = await adapter.modules.buildQueue.getQueuedBuild(targetBuildId);
|
|
39502
|
+
const qb = await adapter.modules.buildQueue.getQueuedBuild(`id:${targetBuildId}`);
|
|
39251
39503
|
enrich.waitReason = qb.data.waitReason;
|
|
39252
39504
|
}
|
|
39253
39505
|
} catch {
|
|
@@ -43316,7 +43568,39 @@ function createSimpleServer() {
|
|
|
43316
43568
|
}
|
|
43317
43569
|
|
|
43318
43570
|
// src/index.ts
|
|
43571
|
+
var cliArgs = parseCliArgs(process.argv.slice(2));
|
|
43572
|
+
if (cliArgs.help) {
|
|
43573
|
+
process.stderr.write(getHelpText());
|
|
43574
|
+
process.exit(0);
|
|
43575
|
+
}
|
|
43576
|
+
if (cliArgs.version) {
|
|
43577
|
+
process.stderr.write(`teamcity-mcp v${getVersion()}
|
|
43578
|
+
`);
|
|
43579
|
+
process.exit(0);
|
|
43580
|
+
}
|
|
43581
|
+
if (cliArgs.config) {
|
|
43582
|
+
const configResult = loadEnvFile(cliArgs.config);
|
|
43583
|
+
if (!configResult.success) {
|
|
43584
|
+
process.stderr.write(`Error: ${configResult.error}
|
|
43585
|
+
`);
|
|
43586
|
+
process.exit(1);
|
|
43587
|
+
}
|
|
43588
|
+
if (configResult.values) {
|
|
43589
|
+
for (const [key, value] of Object.entries(configResult.values)) {
|
|
43590
|
+
process.env[key] ||= value;
|
|
43591
|
+
}
|
|
43592
|
+
}
|
|
43593
|
+
}
|
|
43319
43594
|
dotenv2.config({ quiet: true });
|
|
43595
|
+
if (cliArgs.url) {
|
|
43596
|
+
process.env["TEAMCITY_URL"] = cliArgs.url;
|
|
43597
|
+
}
|
|
43598
|
+
if (cliArgs.token) {
|
|
43599
|
+
process.env["TEAMCITY_TOKEN"] = cliArgs.token;
|
|
43600
|
+
}
|
|
43601
|
+
if (cliArgs.mode) {
|
|
43602
|
+
process.env["MCP_MODE"] = cliArgs.mode;
|
|
43603
|
+
}
|
|
43320
43604
|
var activeServer = null;
|
|
43321
43605
|
var lifecyclePromise = null;
|
|
43322
43606
|
var shuttingDown = false;
|
|
@@ -43355,7 +43639,7 @@ async function main() {
|
|
|
43355
43639
|
process.stderr.write(`${e.message}
|
|
43356
43640
|
`);
|
|
43357
43641
|
process.stderr.write(
|
|
43358
|
-
"Please
|
|
43642
|
+
"Please configure TEAMCITY_URL and TEAMCITY_TOKEN via:\n - CLI arguments: --url <url> --token <token>\n - Config file: --config <path>\n - Environment variables\n - .env file\nRun with --help for more information.\n"
|
|
43359
43643
|
);
|
|
43360
43644
|
process.exit(1);
|
|
43361
43645
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@daghis/teamcity-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
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",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"@types/jest": "^30.0.0",
|
|
87
87
|
"@types/js-yaml": "^4.0.9",
|
|
88
88
|
"@types/morgan": "^1.9.9",
|
|
89
|
-
"@types/node": "^
|
|
89
|
+
"@types/node": "^25.0.2",
|
|
90
90
|
"@typescript-eslint/eslint-plugin": "^8.46.3",
|
|
91
91
|
"@typescript-eslint/parser": "^8.46.3",
|
|
92
92
|
"axios-retry": "^4.5.0",
|
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": "1.
|
|
10
|
+
"version": "1.13.0",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
15
15
|
"identifier": "@daghis/teamcity-mcp",
|
|
16
|
-
"version": "1.
|
|
16
|
+
"version": "1.13.0",
|
|
17
17
|
"runtimeHint": "npx",
|
|
18
18
|
"runtimeArguments": [
|
|
19
19
|
{
|