bamboo-mcp-server 1.0.10 → 1.1.2
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 +26 -0
- package/dist/bamboo-client.js +80 -83
- package/dist/index.js +4 -6
- package/dist/tools/branches.js +5 -36
- package/dist/tools/builds.js +15 -126
- package/dist/tools/deployments.js +11 -90
- package/dist/tools/plans.js +11 -90
- package/dist/tools/projects.js +5 -36
- package/dist/tools/queue.js +5 -36
- package/dist/tools/server.js +5 -36
- package/dist/tools/utils.d.ts +24 -0
- package/dist/tools/utils.js +44 -0
- package/package.json +12 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
## [1.1.2](https://github.com/norus/atlassian-bamboo-mcp/compare/v1.1.1...v1.1.2) (2026-01-09)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **ci:** match original publish.yml setup for trusted publishers ([2ff9306](https://github.com/norus/atlassian-bamboo-mcp/commit/2ff930679ee15f91bd8e9b7de78428db3683ba29))
|
|
7
|
+
|
|
8
|
+
## [1.1.1](https://github.com/norus/atlassian-bamboo-mcp/compare/v1.1.0...v1.1.1) (2026-01-09)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **ci:** remove registry-url to fix OIDC auth ([af9ff11](https://github.com/norus/atlassian-bamboo-mcp/commit/af9ff111d95206a422c7bfa90f355750aaacd4a8))
|
|
14
|
+
|
|
15
|
+
# [1.1.0](https://github.com/norus/atlassian-bamboo-mcp/compare/v1.0.11...v1.1.0) (2026-01-09)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* **ci:** use native npm publish for trusted publishers ([a24ad47](https://github.com/norus/atlassian-bamboo-mcp/commit/a24ad4716b10284271a9e83b5a789acf6f140401))
|
|
21
|
+
* **ci:** use Node 22 for semantic-release ([8c9db06](https://github.com/norus/atlassian-bamboo-mcp/commit/8c9db06200ecd640b616cc4aaf3188c9159d49dd))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
* add automated releases with semantic-release ([9bcaa2d](https://github.com/norus/atlassian-bamboo-mcp/commit/9bcaa2d4e36cc8cccb171e068c709287bb5bf6ef))
|
package/dist/bamboo-client.js
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
import { ProxyAgent, fetch as undiciFetch } from 'undici';
|
|
2
|
+
/**
|
|
3
|
+
* Build a URL query string from optional parameters
|
|
4
|
+
*/
|
|
5
|
+
function buildQueryString(params) {
|
|
6
|
+
const searchParams = new URLSearchParams();
|
|
7
|
+
for (const [key, value] of Object.entries(params)) {
|
|
8
|
+
if (value !== undefined) {
|
|
9
|
+
searchParams.set(key, String(value));
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return searchParams.toString();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Append query string to endpoint if not empty
|
|
16
|
+
*/
|
|
17
|
+
function appendQuery(endpoint, query) {
|
|
18
|
+
return query ? `${endpoint}?${query}` : endpoint;
|
|
19
|
+
}
|
|
2
20
|
export class BambooClient {
|
|
3
21
|
baseUrl;
|
|
4
22
|
token;
|
|
@@ -47,46 +65,38 @@ export class BambooClient {
|
|
|
47
65
|
}
|
|
48
66
|
// Project endpoints
|
|
49
67
|
async listProjects(params) {
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
searchParams.set('max-result', String(params.maxResults));
|
|
57
|
-
const query = searchParams.toString();
|
|
58
|
-
return this.request(`/project${query ? `?${query}` : ''}`);
|
|
68
|
+
const query = buildQueryString({
|
|
69
|
+
'expand': params?.expand,
|
|
70
|
+
'start-index': params?.startIndex,
|
|
71
|
+
'max-result': params?.maxResults,
|
|
72
|
+
});
|
|
73
|
+
return this.request(appendQuery('/project', query));
|
|
59
74
|
}
|
|
60
75
|
async getProject(projectKey, expand) {
|
|
61
|
-
const query = expand
|
|
62
|
-
return this.request(`/project/${projectKey}
|
|
76
|
+
const query = buildQueryString({ expand });
|
|
77
|
+
return this.request(appendQuery(`/project/${projectKey}`, query));
|
|
63
78
|
}
|
|
64
79
|
// Plan endpoints
|
|
65
80
|
async listPlans(params) {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
searchParams.set('max-result', String(params.maxResults));
|
|
73
|
-
const query = searchParams.toString();
|
|
74
|
-
return this.request(`/plan${query ? `?${query}` : ''}`);
|
|
81
|
+
const query = buildQueryString({
|
|
82
|
+
'expand': params?.expand,
|
|
83
|
+
'start-index': params?.startIndex,
|
|
84
|
+
'max-result': params?.maxResults,
|
|
85
|
+
});
|
|
86
|
+
return this.request(appendQuery('/plan', query));
|
|
75
87
|
}
|
|
76
88
|
async getPlan(planKey, expand) {
|
|
77
|
-
const query = expand
|
|
78
|
-
return this.request(`/plan/${planKey}
|
|
89
|
+
const query = buildQueryString({ expand });
|
|
90
|
+
return this.request(appendQuery(`/plan/${planKey}`, query));
|
|
79
91
|
}
|
|
80
92
|
async searchPlans(name, params) {
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
searchParams.set('max-result', String(params.maxResults));
|
|
89
|
-
return this.request(`/search/plans?${searchParams.toString()}`);
|
|
93
|
+
const query = buildQueryString({
|
|
94
|
+
'searchTerm': name,
|
|
95
|
+
'fuzzy': params?.fuzzy,
|
|
96
|
+
'start-index': params?.startIndex,
|
|
97
|
+
'max-result': params?.maxResults,
|
|
98
|
+
});
|
|
99
|
+
return this.request(`/search/plans?${query}`);
|
|
90
100
|
}
|
|
91
101
|
async enablePlan(planKey) {
|
|
92
102
|
return this.request(`/plan/${planKey}/enable`, { method: 'POST' });
|
|
@@ -96,37 +106,31 @@ export class BambooClient {
|
|
|
96
106
|
}
|
|
97
107
|
// Branch endpoints
|
|
98
108
|
async listPlanBranches(planKey, params) {
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
searchParams.set('max-result', String(params.maxResults));
|
|
106
|
-
const query = searchParams.toString();
|
|
107
|
-
return this.request(`/plan/${planKey}/branch${query ? `?${query}` : ''}`);
|
|
109
|
+
const query = buildQueryString({
|
|
110
|
+
'enabledOnly': params?.enabledOnly,
|
|
111
|
+
'start-index': params?.startIndex,
|
|
112
|
+
'max-result': params?.maxResults,
|
|
113
|
+
});
|
|
114
|
+
return this.request(appendQuery(`/plan/${planKey}/branch`, query));
|
|
108
115
|
}
|
|
109
116
|
async getPlanBranch(planKey, branchName) {
|
|
110
117
|
return this.request(`/plan/${planKey}/branch/${encodeURIComponent(branchName)}`);
|
|
111
118
|
}
|
|
112
119
|
// Build endpoints
|
|
113
120
|
async triggerBuild(planKey, params) {
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (params?.customRevision)
|
|
121
|
-
searchParams.set('customRevision', params.customRevision);
|
|
122
|
-
// Add bamboo variables
|
|
121
|
+
const queryParams = {
|
|
122
|
+
'stage': params?.stage,
|
|
123
|
+
'executeAllStages': params?.executeAllStages,
|
|
124
|
+
'customRevision': params?.customRevision,
|
|
125
|
+
};
|
|
126
|
+
// Add bamboo variables with prefixed keys
|
|
123
127
|
if (params?.variables) {
|
|
124
128
|
for (const [key, value] of Object.entries(params.variables)) {
|
|
125
|
-
|
|
129
|
+
queryParams[`bamboo.variable.${key}`] = value;
|
|
126
130
|
}
|
|
127
131
|
}
|
|
128
|
-
const query =
|
|
129
|
-
return this.request(`/queue/${planKey}
|
|
132
|
+
const query = buildQueryString(queryParams);
|
|
133
|
+
return this.request(appendQuery(`/queue/${planKey}`, query), { method: 'POST' });
|
|
130
134
|
}
|
|
131
135
|
async stopBuild(planKey) {
|
|
132
136
|
// To stop a build, we need to DELETE the job keys (not the plan key)
|
|
@@ -181,25 +185,21 @@ export class BambooClient {
|
|
|
181
185
|
};
|
|
182
186
|
}
|
|
183
187
|
async getBuildResult(buildKey, expand) {
|
|
184
|
-
const query = expand
|
|
185
|
-
return this.request(`/result/${buildKey}
|
|
188
|
+
const query = buildQueryString({ expand });
|
|
189
|
+
return this.request(appendQuery(`/result/${buildKey}`, query));
|
|
186
190
|
}
|
|
187
191
|
async getLatestBuildResult(planKey, expand) {
|
|
188
|
-
const query = expand
|
|
189
|
-
return this.request(`/result/${planKey}/latest
|
|
192
|
+
const query = buildQueryString({ expand });
|
|
193
|
+
return this.request(appendQuery(`/result/${planKey}/latest`, query));
|
|
190
194
|
}
|
|
191
195
|
async listBuildResults(params) {
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (params?.expand)
|
|
200
|
-
searchParams.set('expand', params.expand);
|
|
201
|
-
if (params?.includeAllStates)
|
|
202
|
-
searchParams.set('includeAllStates', 'true');
|
|
196
|
+
const query = buildQueryString({
|
|
197
|
+
'buildstate': params?.buildState,
|
|
198
|
+
'start-index': params?.startIndex,
|
|
199
|
+
'max-result': params?.maxResults,
|
|
200
|
+
'expand': params?.expand,
|
|
201
|
+
'includeAllStates': params?.includeAllStates,
|
|
202
|
+
});
|
|
203
203
|
let endpoint = '/result';
|
|
204
204
|
if (params?.projectKey && params?.planKey) {
|
|
205
205
|
endpoint = `/result/${params.projectKey}-${params.planKey}`;
|
|
@@ -207,8 +207,7 @@ export class BambooClient {
|
|
|
207
207
|
else if (params?.projectKey) {
|
|
208
208
|
endpoint = `/result/${params.projectKey}`;
|
|
209
209
|
}
|
|
210
|
-
|
|
211
|
-
return this.request(`${endpoint}${query ? `?${query}` : ''}`);
|
|
210
|
+
return this.request(appendQuery(endpoint, query));
|
|
212
211
|
}
|
|
213
212
|
async getBuildLogs(buildKey, jobKey) {
|
|
214
213
|
// Build logs are obtained by getting the job result with logFiles expand
|
|
@@ -324,22 +323,20 @@ export class BambooClient {
|
|
|
324
323
|
return this.request(`/queue/deployment?versionId=${versionId}&environmentId=${environmentId}`, { method: 'POST' });
|
|
325
324
|
}
|
|
326
325
|
async getDeploymentResults(environmentId, params) {
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
const query = searchParams.toString();
|
|
333
|
-
return this.request(`/deploy/environment/${environmentId}/results${query ? `?${query}` : ''}`);
|
|
326
|
+
const query = buildQueryString({
|
|
327
|
+
'start-index': params?.startIndex,
|
|
328
|
+
'max-result': params?.maxResults,
|
|
329
|
+
});
|
|
330
|
+
return this.request(appendQuery(`/deploy/environment/${environmentId}/results`, query));
|
|
334
331
|
}
|
|
335
332
|
async getDeploymentResult(deploymentResultId, params) {
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
return this.request(`/deploy/result/${deploymentResultId}
|
|
333
|
+
const query = params?.includeLogs
|
|
334
|
+
? buildQueryString({
|
|
335
|
+
'includeLogs': true,
|
|
336
|
+
'max-result': params?.maxLogLines || 1000,
|
|
337
|
+
})
|
|
338
|
+
: '';
|
|
339
|
+
return this.request(appendQuery(`/deploy/result/${deploymentResultId}`, query));
|
|
343
340
|
}
|
|
344
341
|
}
|
|
345
342
|
// Factory function to create client from environment variables
|
package/dist/index.js
CHANGED
|
@@ -29,14 +29,12 @@ async function main() {
|
|
|
29
29
|
const transport = new StdioServerTransport();
|
|
30
30
|
await server.connect(transport);
|
|
31
31
|
// Handle graceful shutdown
|
|
32
|
-
|
|
32
|
+
async function shutdown() {
|
|
33
33
|
await server.close();
|
|
34
34
|
process.exit(0);
|
|
35
|
-
}
|
|
36
|
-
process.on('
|
|
37
|
-
|
|
38
|
-
process.exit(0);
|
|
39
|
-
});
|
|
35
|
+
}
|
|
36
|
+
process.on('SIGINT', shutdown);
|
|
37
|
+
process.on('SIGTERM', shutdown);
|
|
40
38
|
}
|
|
41
39
|
main().catch((error) => {
|
|
42
40
|
console.error('Fatal error:', error);
|
package/dist/tools/branches.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { formatError, jsonResponse } from './utils.js';
|
|
2
3
|
export function registerBranchTools(server, client) {
|
|
3
|
-
// List plan branches
|
|
4
4
|
server.tool('bamboo_list_plan_branches', 'List all branches for a Bamboo build plan', {
|
|
5
5
|
plan_key: z.string().describe('The plan key (e.g., "PROJ-PLAN")'),
|
|
6
6
|
enabled_only: z.boolean().optional().describe('Only return enabled branches'),
|
|
@@ -13,53 +13,22 @@ export function registerBranchTools(server, client) {
|
|
|
13
13
|
startIndex: start_index,
|
|
14
14
|
maxResults: max_results,
|
|
15
15
|
});
|
|
16
|
-
return
|
|
17
|
-
content: [
|
|
18
|
-
{
|
|
19
|
-
type: 'text',
|
|
20
|
-
text: JSON.stringify(branches, null, 2),
|
|
21
|
-
},
|
|
22
|
-
],
|
|
23
|
-
};
|
|
16
|
+
return jsonResponse(branches);
|
|
24
17
|
}
|
|
25
18
|
catch (error) {
|
|
26
|
-
return
|
|
27
|
-
content: [
|
|
28
|
-
{
|
|
29
|
-
type: 'text',
|
|
30
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
31
|
-
},
|
|
32
|
-
],
|
|
33
|
-
isError: true,
|
|
34
|
-
};
|
|
19
|
+
return formatError(error);
|
|
35
20
|
}
|
|
36
21
|
});
|
|
37
|
-
// Get plan branch
|
|
38
22
|
server.tool('bamboo_get_plan_branch', 'Get details of a specific plan branch', {
|
|
39
23
|
plan_key: z.string().describe('The plan key (e.g., "PROJ-PLAN")'),
|
|
40
24
|
branch_name: z.string().describe('The branch name'),
|
|
41
25
|
}, async ({ plan_key, branch_name }) => {
|
|
42
26
|
try {
|
|
43
27
|
const branch = await client.getPlanBranch(plan_key, branch_name);
|
|
44
|
-
return
|
|
45
|
-
content: [
|
|
46
|
-
{
|
|
47
|
-
type: 'text',
|
|
48
|
-
text: JSON.stringify(branch, null, 2),
|
|
49
|
-
},
|
|
50
|
-
],
|
|
51
|
-
};
|
|
28
|
+
return jsonResponse(branch);
|
|
52
29
|
}
|
|
53
30
|
catch (error) {
|
|
54
|
-
return
|
|
55
|
-
content: [
|
|
56
|
-
{
|
|
57
|
-
type: 'text',
|
|
58
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
59
|
-
},
|
|
60
|
-
],
|
|
61
|
-
isError: true,
|
|
62
|
-
};
|
|
31
|
+
return formatError(error);
|
|
63
32
|
}
|
|
64
33
|
});
|
|
65
34
|
}
|
package/dist/tools/builds.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { formatError, jsonResponse } from './utils.js';
|
|
2
3
|
export function registerBuildTools(server, client) {
|
|
3
|
-
// Trigger build
|
|
4
4
|
server.tool('bamboo_trigger_build', 'Trigger a build for a Bamboo plan', {
|
|
5
5
|
plan_key: z.string().describe('The plan key to build (e.g., "PROJ-PLAN")'),
|
|
6
6
|
stage: z.string().optional().describe('Specific stage to execute'),
|
|
@@ -15,111 +15,47 @@ export function registerBuildTools(server, client) {
|
|
|
15
15
|
customRevision: custom_revision,
|
|
16
16
|
variables,
|
|
17
17
|
});
|
|
18
|
-
return
|
|
19
|
-
content: [
|
|
20
|
-
{
|
|
21
|
-
type: 'text',
|
|
22
|
-
text: JSON.stringify(result, null, 2),
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
};
|
|
18
|
+
return jsonResponse(result);
|
|
26
19
|
}
|
|
27
20
|
catch (error) {
|
|
28
|
-
return
|
|
29
|
-
content: [
|
|
30
|
-
{
|
|
31
|
-
type: 'text',
|
|
32
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
33
|
-
},
|
|
34
|
-
],
|
|
35
|
-
isError: true,
|
|
36
|
-
};
|
|
21
|
+
return formatError(error);
|
|
37
22
|
}
|
|
38
23
|
});
|
|
39
|
-
// Stop build
|
|
40
24
|
server.tool('bamboo_stop_build', 'Stop a running build for a Bamboo plan', {
|
|
41
25
|
plan_key: z.string().describe('The plan key to stop (e.g., "PROJ-PLAN")'),
|
|
42
26
|
}, async ({ plan_key }) => {
|
|
43
27
|
try {
|
|
44
28
|
const result = await client.stopBuild(plan_key);
|
|
45
|
-
return
|
|
46
|
-
content: [
|
|
47
|
-
{
|
|
48
|
-
type: 'text',
|
|
49
|
-
text: JSON.stringify(result, null, 2),
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
};
|
|
29
|
+
return jsonResponse(result);
|
|
53
30
|
}
|
|
54
31
|
catch (error) {
|
|
55
|
-
return
|
|
56
|
-
content: [
|
|
57
|
-
{
|
|
58
|
-
type: 'text',
|
|
59
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
60
|
-
},
|
|
61
|
-
],
|
|
62
|
-
isError: true,
|
|
63
|
-
};
|
|
32
|
+
return formatError(error);
|
|
64
33
|
}
|
|
65
34
|
});
|
|
66
|
-
// Get build result
|
|
67
35
|
server.tool('bamboo_get_build_result', 'Get the result of a specific build', {
|
|
68
36
|
build_key: z.string().describe('The build result key (e.g., "PROJ-PLAN-123")'),
|
|
69
37
|
expand: z.string().optional().describe('Fields to expand (e.g., "changes,artifacts,testResults")'),
|
|
70
38
|
}, async ({ build_key, expand }) => {
|
|
71
39
|
try {
|
|
72
40
|
const result = await client.getBuildResult(build_key, expand);
|
|
73
|
-
return
|
|
74
|
-
content: [
|
|
75
|
-
{
|
|
76
|
-
type: 'text',
|
|
77
|
-
text: JSON.stringify(result, null, 2),
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
};
|
|
41
|
+
return jsonResponse(result);
|
|
81
42
|
}
|
|
82
43
|
catch (error) {
|
|
83
|
-
return
|
|
84
|
-
content: [
|
|
85
|
-
{
|
|
86
|
-
type: 'text',
|
|
87
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
isError: true,
|
|
91
|
-
};
|
|
44
|
+
return formatError(error);
|
|
92
45
|
}
|
|
93
46
|
});
|
|
94
|
-
// Get latest build result
|
|
95
47
|
server.tool('bamboo_get_latest_result', 'Get the latest build result for a plan', {
|
|
96
48
|
plan_key: z.string().describe('The plan key (e.g., "PROJ-PLAN")'),
|
|
97
49
|
expand: z.string().optional().describe('Fields to expand (e.g., "changes,artifacts,testResults")'),
|
|
98
50
|
}, async ({ plan_key, expand }) => {
|
|
99
51
|
try {
|
|
100
52
|
const result = await client.getLatestBuildResult(plan_key, expand);
|
|
101
|
-
return
|
|
102
|
-
content: [
|
|
103
|
-
{
|
|
104
|
-
type: 'text',
|
|
105
|
-
text: JSON.stringify(result, null, 2),
|
|
106
|
-
},
|
|
107
|
-
],
|
|
108
|
-
};
|
|
53
|
+
return jsonResponse(result);
|
|
109
54
|
}
|
|
110
55
|
catch (error) {
|
|
111
|
-
return
|
|
112
|
-
content: [
|
|
113
|
-
{
|
|
114
|
-
type: 'text',
|
|
115
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
116
|
-
},
|
|
117
|
-
],
|
|
118
|
-
isError: true,
|
|
119
|
-
};
|
|
56
|
+
return formatError(error);
|
|
120
57
|
}
|
|
121
58
|
});
|
|
122
|
-
// List build results
|
|
123
59
|
server.tool('bamboo_list_build_results', 'List build results with optional filters', {
|
|
124
60
|
project_key: z.string().optional().describe('Filter by project key'),
|
|
125
61
|
plan_key: z.string().optional().describe('Filter by plan key (requires project_key)'),
|
|
@@ -139,56 +75,24 @@ export function registerBuildTools(server, client) {
|
|
|
139
75
|
expand,
|
|
140
76
|
includeAllStates: include_all_states,
|
|
141
77
|
});
|
|
142
|
-
return
|
|
143
|
-
content: [
|
|
144
|
-
{
|
|
145
|
-
type: 'text',
|
|
146
|
-
text: JSON.stringify(results, null, 2),
|
|
147
|
-
},
|
|
148
|
-
],
|
|
149
|
-
};
|
|
78
|
+
return jsonResponse(results);
|
|
150
79
|
}
|
|
151
80
|
catch (error) {
|
|
152
|
-
return
|
|
153
|
-
content: [
|
|
154
|
-
{
|
|
155
|
-
type: 'text',
|
|
156
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
157
|
-
},
|
|
158
|
-
],
|
|
159
|
-
isError: true,
|
|
160
|
-
};
|
|
81
|
+
return formatError(error);
|
|
161
82
|
}
|
|
162
83
|
});
|
|
163
|
-
// Get build logs
|
|
164
84
|
server.tool('bamboo_get_build_logs', 'Get the build logs for a specific build. Returns log file URLs that can be accessed via browser.', {
|
|
165
85
|
build_key: z.string().describe('The build result key (e.g., "PROJ-PLAN-123")'),
|
|
166
86
|
job_key: z.string().optional().describe('Specific job key to get logs for'),
|
|
167
87
|
}, async ({ build_key, job_key }) => {
|
|
168
88
|
try {
|
|
169
89
|
const logs = await client.getBuildLogs(build_key, job_key);
|
|
170
|
-
return
|
|
171
|
-
content: [
|
|
172
|
-
{
|
|
173
|
-
type: 'text',
|
|
174
|
-
text: JSON.stringify(logs, null, 2),
|
|
175
|
-
},
|
|
176
|
-
],
|
|
177
|
-
};
|
|
90
|
+
return jsonResponse(logs);
|
|
178
91
|
}
|
|
179
92
|
catch (error) {
|
|
180
|
-
return
|
|
181
|
-
content: [
|
|
182
|
-
{
|
|
183
|
-
type: 'text',
|
|
184
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
185
|
-
},
|
|
186
|
-
],
|
|
187
|
-
isError: true,
|
|
188
|
-
};
|
|
93
|
+
return formatError(error);
|
|
189
94
|
}
|
|
190
95
|
});
|
|
191
|
-
// Get build result with log content
|
|
192
96
|
server.tool('bamboo_get_build_result_logs', 'Get build result with actual log content. For plan builds, fetches logs from all jobs. For job builds, returns logs directly.', {
|
|
193
97
|
build_key: z.string().describe('The build result key - can be plan level (e.g., "PROJ-PLAN-123") or job level (e.g., "PROJ-PLAN-JOB1-123")'),
|
|
194
98
|
max_log_lines: z.number().optional().describe('Maximum number of log lines per job (default: 1000)'),
|
|
@@ -197,25 +101,10 @@ export function registerBuildTools(server, client) {
|
|
|
197
101
|
const result = await client.getBuildResultWithLogs(build_key, {
|
|
198
102
|
maxLogLines: max_log_lines,
|
|
199
103
|
});
|
|
200
|
-
return
|
|
201
|
-
content: [
|
|
202
|
-
{
|
|
203
|
-
type: 'text',
|
|
204
|
-
text: JSON.stringify(result, null, 2),
|
|
205
|
-
},
|
|
206
|
-
],
|
|
207
|
-
};
|
|
104
|
+
return jsonResponse(result);
|
|
208
105
|
}
|
|
209
106
|
catch (error) {
|
|
210
|
-
return
|
|
211
|
-
content: [
|
|
212
|
-
{
|
|
213
|
-
type: 'text',
|
|
214
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
215
|
-
},
|
|
216
|
-
],
|
|
217
|
-
isError: true,
|
|
218
|
-
};
|
|
107
|
+
return formatError(error);
|
|
219
108
|
}
|
|
220
109
|
});
|
|
221
110
|
}
|
|
@@ -1,86 +1,38 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { formatError, jsonResponse } from './utils.js';
|
|
2
3
|
export function registerDeploymentTools(server, client) {
|
|
3
|
-
// List deployment projects
|
|
4
4
|
server.tool('bamboo_list_deployment_projects', 'List all Bamboo deployment projects', {}, async () => {
|
|
5
5
|
try {
|
|
6
6
|
const projects = await client.listDeploymentProjects();
|
|
7
|
-
return
|
|
8
|
-
content: [
|
|
9
|
-
{
|
|
10
|
-
type: 'text',
|
|
11
|
-
text: JSON.stringify(projects, null, 2),
|
|
12
|
-
},
|
|
13
|
-
],
|
|
14
|
-
};
|
|
7
|
+
return jsonResponse(projects);
|
|
15
8
|
}
|
|
16
9
|
catch (error) {
|
|
17
|
-
return
|
|
18
|
-
content: [
|
|
19
|
-
{
|
|
20
|
-
type: 'text',
|
|
21
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
22
|
-
},
|
|
23
|
-
],
|
|
24
|
-
isError: true,
|
|
25
|
-
};
|
|
10
|
+
return formatError(error);
|
|
26
11
|
}
|
|
27
12
|
});
|
|
28
|
-
// Get deployment project
|
|
29
13
|
server.tool('bamboo_get_deployment_project', 'Get details of a specific deployment project', {
|
|
30
14
|
project_id: z.string().describe('The deployment project ID'),
|
|
31
15
|
}, async ({ project_id }) => {
|
|
32
16
|
try {
|
|
33
17
|
const project = await client.getDeploymentProject(project_id);
|
|
34
|
-
return
|
|
35
|
-
content: [
|
|
36
|
-
{
|
|
37
|
-
type: 'text',
|
|
38
|
-
text: JSON.stringify(project, null, 2),
|
|
39
|
-
},
|
|
40
|
-
],
|
|
41
|
-
};
|
|
18
|
+
return jsonResponse(project);
|
|
42
19
|
}
|
|
43
20
|
catch (error) {
|
|
44
|
-
return
|
|
45
|
-
content: [
|
|
46
|
-
{
|
|
47
|
-
type: 'text',
|
|
48
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
49
|
-
},
|
|
50
|
-
],
|
|
51
|
-
isError: true,
|
|
52
|
-
};
|
|
21
|
+
return formatError(error);
|
|
53
22
|
}
|
|
54
23
|
});
|
|
55
|
-
// Trigger deployment
|
|
56
24
|
server.tool('bamboo_trigger_deployment', 'Trigger a deployment to an environment', {
|
|
57
25
|
version_id: z.string().describe('The release version ID to deploy'),
|
|
58
26
|
environment_id: z.string().describe('The target environment ID'),
|
|
59
27
|
}, async ({ version_id, environment_id }) => {
|
|
60
28
|
try {
|
|
61
29
|
const result = await client.triggerDeployment(version_id, environment_id);
|
|
62
|
-
return
|
|
63
|
-
content: [
|
|
64
|
-
{
|
|
65
|
-
type: 'text',
|
|
66
|
-
text: JSON.stringify(result, null, 2),
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
};
|
|
30
|
+
return jsonResponse(result);
|
|
70
31
|
}
|
|
71
32
|
catch (error) {
|
|
72
|
-
return
|
|
73
|
-
content: [
|
|
74
|
-
{
|
|
75
|
-
type: 'text',
|
|
76
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
77
|
-
},
|
|
78
|
-
],
|
|
79
|
-
isError: true,
|
|
80
|
-
};
|
|
33
|
+
return formatError(error);
|
|
81
34
|
}
|
|
82
35
|
});
|
|
83
|
-
// Get deployment results
|
|
84
36
|
server.tool('bamboo_get_deployment_results', 'Get deployment results for an environment', {
|
|
85
37
|
environment_id: z.string().describe('The environment ID'),
|
|
86
38
|
start_index: z.number().optional().describe('Starting index for pagination (default: 0)'),
|
|
@@ -91,28 +43,12 @@ export function registerDeploymentTools(server, client) {
|
|
|
91
43
|
startIndex: start_index,
|
|
92
44
|
maxResults: max_results,
|
|
93
45
|
});
|
|
94
|
-
return
|
|
95
|
-
content: [
|
|
96
|
-
{
|
|
97
|
-
type: 'text',
|
|
98
|
-
text: JSON.stringify(results, null, 2),
|
|
99
|
-
},
|
|
100
|
-
],
|
|
101
|
-
};
|
|
46
|
+
return jsonResponse(results);
|
|
102
47
|
}
|
|
103
48
|
catch (error) {
|
|
104
|
-
return
|
|
105
|
-
content: [
|
|
106
|
-
{
|
|
107
|
-
type: 'text',
|
|
108
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
109
|
-
},
|
|
110
|
-
],
|
|
111
|
-
isError: true,
|
|
112
|
-
};
|
|
49
|
+
return formatError(error);
|
|
113
50
|
}
|
|
114
51
|
});
|
|
115
|
-
// Get deployment result with logs
|
|
116
52
|
server.tool('bamboo_get_deployment_result', 'Get a specific deployment result with optional logs', {
|
|
117
53
|
deployment_result_id: z.string().describe('The deployment result ID'),
|
|
118
54
|
include_logs: z.boolean().optional().describe('Include log entries (default: false)'),
|
|
@@ -123,25 +59,10 @@ export function registerDeploymentTools(server, client) {
|
|
|
123
59
|
includeLogs: include_logs,
|
|
124
60
|
maxLogLines: max_log_lines,
|
|
125
61
|
});
|
|
126
|
-
return
|
|
127
|
-
content: [
|
|
128
|
-
{
|
|
129
|
-
type: 'text',
|
|
130
|
-
text: JSON.stringify(result, null, 2),
|
|
131
|
-
},
|
|
132
|
-
],
|
|
133
|
-
};
|
|
62
|
+
return jsonResponse(result);
|
|
134
63
|
}
|
|
135
64
|
catch (error) {
|
|
136
|
-
return
|
|
137
|
-
content: [
|
|
138
|
-
{
|
|
139
|
-
type: 'text',
|
|
140
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
141
|
-
},
|
|
142
|
-
],
|
|
143
|
-
isError: true,
|
|
144
|
-
};
|
|
65
|
+
return formatError(error);
|
|
145
66
|
}
|
|
146
67
|
});
|
|
147
68
|
}
|
package/dist/tools/plans.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { formatError, jsonResponse, textResponse } from './utils.js';
|
|
2
3
|
export function registerPlanTools(server, client) {
|
|
3
|
-
// List plans
|
|
4
4
|
server.tool('bamboo_list_plans', 'List all Bamboo build plans', {
|
|
5
5
|
expand: z.string().optional().describe('Fields to expand in the response (e.g., "plans.plan.stages")'),
|
|
6
6
|
start_index: z.number().optional().describe('Starting index for pagination (default: 0)'),
|
|
@@ -12,56 +12,24 @@ export function registerPlanTools(server, client) {
|
|
|
12
12
|
startIndex: start_index,
|
|
13
13
|
maxResults: max_results,
|
|
14
14
|
});
|
|
15
|
-
return
|
|
16
|
-
content: [
|
|
17
|
-
{
|
|
18
|
-
type: 'text',
|
|
19
|
-
text: JSON.stringify(plans, null, 2),
|
|
20
|
-
},
|
|
21
|
-
],
|
|
22
|
-
};
|
|
15
|
+
return jsonResponse(plans);
|
|
23
16
|
}
|
|
24
17
|
catch (error) {
|
|
25
|
-
return
|
|
26
|
-
content: [
|
|
27
|
-
{
|
|
28
|
-
type: 'text',
|
|
29
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
isError: true,
|
|
33
|
-
};
|
|
18
|
+
return formatError(error);
|
|
34
19
|
}
|
|
35
20
|
});
|
|
36
|
-
// Get plan
|
|
37
21
|
server.tool('bamboo_get_plan', 'Get details of a specific Bamboo build plan by key', {
|
|
38
22
|
plan_key: z.string().describe('The plan key (e.g., "PROJ-PLAN")'),
|
|
39
23
|
expand: z.string().optional().describe('Fields to expand in the response'),
|
|
40
24
|
}, async ({ plan_key, expand }) => {
|
|
41
25
|
try {
|
|
42
26
|
const plan = await client.getPlan(plan_key, expand);
|
|
43
|
-
return
|
|
44
|
-
content: [
|
|
45
|
-
{
|
|
46
|
-
type: 'text',
|
|
47
|
-
text: JSON.stringify(plan, null, 2),
|
|
48
|
-
},
|
|
49
|
-
],
|
|
50
|
-
};
|
|
27
|
+
return jsonResponse(plan);
|
|
51
28
|
}
|
|
52
29
|
catch (error) {
|
|
53
|
-
return
|
|
54
|
-
content: [
|
|
55
|
-
{
|
|
56
|
-
type: 'text',
|
|
57
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
58
|
-
},
|
|
59
|
-
],
|
|
60
|
-
isError: true,
|
|
61
|
-
};
|
|
30
|
+
return formatError(error);
|
|
62
31
|
}
|
|
63
32
|
});
|
|
64
|
-
// Search plans
|
|
65
33
|
server.tool('bamboo_search_plans', 'Search for Bamboo build plans by name', {
|
|
66
34
|
name: z.string().describe('The plan name to search for'),
|
|
67
35
|
fuzzy: z.boolean().optional().describe('Enable fuzzy matching (default: true)'),
|
|
@@ -74,79 +42,32 @@ export function registerPlanTools(server, client) {
|
|
|
74
42
|
startIndex: start_index,
|
|
75
43
|
maxResults: max_results,
|
|
76
44
|
});
|
|
77
|
-
return
|
|
78
|
-
content: [
|
|
79
|
-
{
|
|
80
|
-
type: 'text',
|
|
81
|
-
text: JSON.stringify(plans, null, 2),
|
|
82
|
-
},
|
|
83
|
-
],
|
|
84
|
-
};
|
|
45
|
+
return jsonResponse(plans);
|
|
85
46
|
}
|
|
86
47
|
catch (error) {
|
|
87
|
-
return
|
|
88
|
-
content: [
|
|
89
|
-
{
|
|
90
|
-
type: 'text',
|
|
91
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
92
|
-
},
|
|
93
|
-
],
|
|
94
|
-
isError: true,
|
|
95
|
-
};
|
|
48
|
+
return formatError(error);
|
|
96
49
|
}
|
|
97
50
|
});
|
|
98
|
-
// Enable plan
|
|
99
51
|
server.tool('bamboo_enable_plan', 'Enable a Bamboo build plan', {
|
|
100
52
|
plan_key: z.string().describe('The plan key to enable (e.g., "PROJ-PLAN")'),
|
|
101
53
|
}, async ({ plan_key }) => {
|
|
102
54
|
try {
|
|
103
55
|
await client.enablePlan(plan_key);
|
|
104
|
-
return {
|
|
105
|
-
content: [
|
|
106
|
-
{
|
|
107
|
-
type: 'text',
|
|
108
|
-
text: `Plan ${plan_key} has been enabled successfully.`,
|
|
109
|
-
},
|
|
110
|
-
],
|
|
111
|
-
};
|
|
56
|
+
return textResponse(`Plan ${plan_key} has been enabled successfully.`);
|
|
112
57
|
}
|
|
113
58
|
catch (error) {
|
|
114
|
-
return
|
|
115
|
-
content: [
|
|
116
|
-
{
|
|
117
|
-
type: 'text',
|
|
118
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
119
|
-
},
|
|
120
|
-
],
|
|
121
|
-
isError: true,
|
|
122
|
-
};
|
|
59
|
+
return formatError(error);
|
|
123
60
|
}
|
|
124
61
|
});
|
|
125
|
-
// Disable plan
|
|
126
62
|
server.tool('bamboo_disable_plan', 'Disable a Bamboo build plan', {
|
|
127
63
|
plan_key: z.string().describe('The plan key to disable (e.g., "PROJ-PLAN")'),
|
|
128
64
|
}, async ({ plan_key }) => {
|
|
129
65
|
try {
|
|
130
66
|
await client.disablePlan(plan_key);
|
|
131
|
-
return {
|
|
132
|
-
content: [
|
|
133
|
-
{
|
|
134
|
-
type: 'text',
|
|
135
|
-
text: `Plan ${plan_key} has been disabled successfully.`,
|
|
136
|
-
},
|
|
137
|
-
],
|
|
138
|
-
};
|
|
67
|
+
return textResponse(`Plan ${plan_key} has been disabled successfully.`);
|
|
139
68
|
}
|
|
140
69
|
catch (error) {
|
|
141
|
-
return
|
|
142
|
-
content: [
|
|
143
|
-
{
|
|
144
|
-
type: 'text',
|
|
145
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
146
|
-
},
|
|
147
|
-
],
|
|
148
|
-
isError: true,
|
|
149
|
-
};
|
|
70
|
+
return formatError(error);
|
|
150
71
|
}
|
|
151
72
|
});
|
|
152
73
|
}
|
package/dist/tools/projects.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { formatError, jsonResponse } from './utils.js';
|
|
2
3
|
export function registerProjectTools(server, client) {
|
|
3
|
-
// List projects
|
|
4
4
|
server.tool('bamboo_list_projects', 'List all Bamboo projects', {
|
|
5
5
|
expand: z.string().optional().describe('Fields to expand in the response (e.g., "projects.project.plans")'),
|
|
6
6
|
start_index: z.number().optional().describe('Starting index for pagination (default: 0)'),
|
|
@@ -12,53 +12,22 @@ export function registerProjectTools(server, client) {
|
|
|
12
12
|
startIndex: start_index,
|
|
13
13
|
maxResults: max_results,
|
|
14
14
|
});
|
|
15
|
-
return
|
|
16
|
-
content: [
|
|
17
|
-
{
|
|
18
|
-
type: 'text',
|
|
19
|
-
text: JSON.stringify(projects, null, 2),
|
|
20
|
-
},
|
|
21
|
-
],
|
|
22
|
-
};
|
|
15
|
+
return jsonResponse(projects);
|
|
23
16
|
}
|
|
24
17
|
catch (error) {
|
|
25
|
-
return
|
|
26
|
-
content: [
|
|
27
|
-
{
|
|
28
|
-
type: 'text',
|
|
29
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
isError: true,
|
|
33
|
-
};
|
|
18
|
+
return formatError(error);
|
|
34
19
|
}
|
|
35
20
|
});
|
|
36
|
-
// Get project
|
|
37
21
|
server.tool('bamboo_get_project', 'Get details of a specific Bamboo project by key', {
|
|
38
22
|
project_key: z.string().describe('The project key (e.g., "PROJ")'),
|
|
39
23
|
expand: z.string().optional().describe('Fields to expand in the response'),
|
|
40
24
|
}, async ({ project_key, expand }) => {
|
|
41
25
|
try {
|
|
42
26
|
const project = await client.getProject(project_key, expand);
|
|
43
|
-
return
|
|
44
|
-
content: [
|
|
45
|
-
{
|
|
46
|
-
type: 'text',
|
|
47
|
-
text: JSON.stringify(project, null, 2),
|
|
48
|
-
},
|
|
49
|
-
],
|
|
50
|
-
};
|
|
27
|
+
return jsonResponse(project);
|
|
51
28
|
}
|
|
52
29
|
catch (error) {
|
|
53
|
-
return
|
|
54
|
-
content: [
|
|
55
|
-
{
|
|
56
|
-
type: 'text',
|
|
57
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
58
|
-
},
|
|
59
|
-
],
|
|
60
|
-
isError: true,
|
|
61
|
-
};
|
|
30
|
+
return formatError(error);
|
|
62
31
|
}
|
|
63
32
|
});
|
|
64
33
|
}
|
package/dist/tools/queue.js
CHANGED
|
@@ -1,55 +1,24 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { formatError, jsonResponse } from './utils.js';
|
|
2
3
|
export function registerQueueTools(server, client) {
|
|
3
|
-
// Get build queue
|
|
4
4
|
server.tool('bamboo_get_build_queue', 'Get the current Bamboo build queue', {
|
|
5
5
|
expand: z.string().optional().describe('Fields to expand (default: "queuedBuilds")'),
|
|
6
6
|
}, async ({ expand }) => {
|
|
7
7
|
try {
|
|
8
8
|
const queue = await client.getBuildQueue(expand);
|
|
9
|
-
return
|
|
10
|
-
content: [
|
|
11
|
-
{
|
|
12
|
-
type: 'text',
|
|
13
|
-
text: JSON.stringify(queue, null, 2),
|
|
14
|
-
},
|
|
15
|
-
],
|
|
16
|
-
};
|
|
9
|
+
return jsonResponse(queue);
|
|
17
10
|
}
|
|
18
11
|
catch (error) {
|
|
19
|
-
return
|
|
20
|
-
content: [
|
|
21
|
-
{
|
|
22
|
-
type: 'text',
|
|
23
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
isError: true,
|
|
27
|
-
};
|
|
12
|
+
return formatError(error);
|
|
28
13
|
}
|
|
29
14
|
});
|
|
30
|
-
// Get deployment queue
|
|
31
15
|
server.tool('bamboo_get_deployment_queue', 'Get the current Bamboo deployment queue', {}, async () => {
|
|
32
16
|
try {
|
|
33
17
|
const queue = await client.getDeploymentQueue();
|
|
34
|
-
return
|
|
35
|
-
content: [
|
|
36
|
-
{
|
|
37
|
-
type: 'text',
|
|
38
|
-
text: JSON.stringify(queue, null, 2),
|
|
39
|
-
},
|
|
40
|
-
],
|
|
41
|
-
};
|
|
18
|
+
return jsonResponse(queue);
|
|
42
19
|
}
|
|
43
20
|
catch (error) {
|
|
44
|
-
return
|
|
45
|
-
content: [
|
|
46
|
-
{
|
|
47
|
-
type: 'text',
|
|
48
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
49
|
-
},
|
|
50
|
-
],
|
|
51
|
-
isError: true,
|
|
52
|
-
};
|
|
21
|
+
return formatError(error);
|
|
53
22
|
}
|
|
54
23
|
});
|
|
55
24
|
}
|
package/dist/tools/server.js
CHANGED
|
@@ -1,52 +1,21 @@
|
|
|
1
|
+
import { formatError, jsonResponse } from './utils.js';
|
|
1
2
|
export function registerServerTools(server, client) {
|
|
2
|
-
// Get server info
|
|
3
3
|
server.tool('bamboo_server_info', 'Get Bamboo server information including version, edition, and state', {}, async () => {
|
|
4
4
|
try {
|
|
5
5
|
const info = await client.getServerInfo();
|
|
6
|
-
return
|
|
7
|
-
content: [
|
|
8
|
-
{
|
|
9
|
-
type: 'text',
|
|
10
|
-
text: JSON.stringify(info, null, 2),
|
|
11
|
-
},
|
|
12
|
-
],
|
|
13
|
-
};
|
|
6
|
+
return jsonResponse(info);
|
|
14
7
|
}
|
|
15
8
|
catch (error) {
|
|
16
|
-
return
|
|
17
|
-
content: [
|
|
18
|
-
{
|
|
19
|
-
type: 'text',
|
|
20
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
21
|
-
},
|
|
22
|
-
],
|
|
23
|
-
isError: true,
|
|
24
|
-
};
|
|
9
|
+
return formatError(error);
|
|
25
10
|
}
|
|
26
11
|
});
|
|
27
|
-
// Health check
|
|
28
12
|
server.tool('bamboo_health_check', 'Check Bamboo server health status', {}, async () => {
|
|
29
13
|
try {
|
|
30
14
|
const health = await client.healthCheck();
|
|
31
|
-
return
|
|
32
|
-
content: [
|
|
33
|
-
{
|
|
34
|
-
type: 'text',
|
|
35
|
-
text: JSON.stringify(health, null, 2),
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
};
|
|
15
|
+
return jsonResponse(health);
|
|
39
16
|
}
|
|
40
17
|
catch (error) {
|
|
41
|
-
return
|
|
42
|
-
content: [
|
|
43
|
-
{
|
|
44
|
-
type: 'text',
|
|
45
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
46
|
-
},
|
|
47
|
-
],
|
|
48
|
-
isError: true,
|
|
49
|
-
};
|
|
18
|
+
return formatError(error);
|
|
50
19
|
}
|
|
51
20
|
});
|
|
52
21
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for MCP tool handlers
|
|
3
|
+
*/
|
|
4
|
+
interface ToolResponse {
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
content: Array<{
|
|
7
|
+
type: 'text';
|
|
8
|
+
text: string;
|
|
9
|
+
}>;
|
|
10
|
+
isError?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Format a successful JSON response for MCP tools
|
|
14
|
+
*/
|
|
15
|
+
export declare function jsonResponse(data: unknown): ToolResponse;
|
|
16
|
+
/**
|
|
17
|
+
* Format a text response for MCP tools
|
|
18
|
+
*/
|
|
19
|
+
export declare function textResponse(message: string): ToolResponse;
|
|
20
|
+
/**
|
|
21
|
+
* Format an error response for MCP tools
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatError(error: unknown): ToolResponse;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for MCP tool handlers
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Format a successful JSON response for MCP tools
|
|
6
|
+
*/
|
|
7
|
+
export function jsonResponse(data) {
|
|
8
|
+
return {
|
|
9
|
+
content: [
|
|
10
|
+
{
|
|
11
|
+
type: 'text',
|
|
12
|
+
text: JSON.stringify(data, null, 2),
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Format a text response for MCP tools
|
|
19
|
+
*/
|
|
20
|
+
export function textResponse(message) {
|
|
21
|
+
return {
|
|
22
|
+
content: [
|
|
23
|
+
{
|
|
24
|
+
type: 'text',
|
|
25
|
+
text: message,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Format an error response for MCP tools
|
|
32
|
+
*/
|
|
33
|
+
export function formatError(error) {
|
|
34
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
35
|
+
return {
|
|
36
|
+
content: [
|
|
37
|
+
{
|
|
38
|
+
type: 'text',
|
|
39
|
+
text: `Error: ${message}`,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
isError: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bamboo-mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "MCP server for Atlassian Bamboo",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
"build": "tsc",
|
|
12
12
|
"start": "node dist/index.js",
|
|
13
13
|
"dev": "tsc --watch",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"test:watch": "vitest",
|
|
16
|
+
"test:coverage": "vitest run --coverage",
|
|
14
17
|
"prepublishOnly": "npm run build"
|
|
15
18
|
},
|
|
16
19
|
"keywords": [
|
|
@@ -35,6 +38,7 @@
|
|
|
35
38
|
"files": [
|
|
36
39
|
"dist",
|
|
37
40
|
"README.md",
|
|
41
|
+
"CHANGELOG.md",
|
|
38
42
|
"LICENSE"
|
|
39
43
|
],
|
|
40
44
|
"dependencies": {
|
|
@@ -43,8 +47,14 @@
|
|
|
43
47
|
"zod": "^3.22.0"
|
|
44
48
|
},
|
|
45
49
|
"devDependencies": {
|
|
50
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
51
|
+
"@semantic-release/git": "^10.0.1",
|
|
46
52
|
"@types/node": "^20.0.0",
|
|
47
|
-
"
|
|
53
|
+
"@vitest/coverage-v8": "^4.0.16",
|
|
54
|
+
"msw": "^2.12.7",
|
|
55
|
+
"semantic-release": "^24.2.9",
|
|
56
|
+
"typescript": "^5.3.0",
|
|
57
|
+
"vitest": "^4.0.16"
|
|
48
58
|
},
|
|
49
59
|
"engines": {
|
|
50
60
|
"node": ">=18.0.0"
|