@stubbedev/atlassian-mcp 0.2.4 → 0.2.5
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/dist/bitbucket.js +55 -2
- package/dist/index.js +16 -0
- package/package.json +1 -1
package/dist/bitbucket.js
CHANGED
|
@@ -321,6 +321,19 @@ export class BitbucketClient {
|
|
|
321
321
|
start = data.nextPageStart;
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
|
+
// Fallback: search branches matching filterText and check each for an open PR.
|
|
325
|
+
// Used when exact branch name lookup yields no result (e.g. LLM provides a partial branch name).
|
|
326
|
+
async findOpenPrByBranchFilter(projectKey, repoSlug, filterText) {
|
|
327
|
+
const branches = await this.request('GET', `/projects/${projectKey}/repos/${repoSlug}/branches?limit=25&filterText=${encodeURIComponent(filterText)}`);
|
|
328
|
+
if (!branches?.values?.length)
|
|
329
|
+
return null;
|
|
330
|
+
for (const b of branches.values) {
|
|
331
|
+
const pr = await this.findOpenPrForBranch(projectKey, repoSlug, b.displayId);
|
|
332
|
+
if (pr)
|
|
333
|
+
return pr;
|
|
334
|
+
}
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
324
337
|
async listRepos(args) {
|
|
325
338
|
const { limit = 50, start = 0 } = args;
|
|
326
339
|
const qs = `?limit=${limit}&start=${start}`;
|
|
@@ -396,7 +409,11 @@ export class BitbucketClient {
|
|
|
396
409
|
if (!branch || branch === 'HEAD') {
|
|
397
410
|
throw new Error('Provide prId or fromBranch, or run from a checked-out branch.');
|
|
398
411
|
}
|
|
399
|
-
|
|
412
|
+
let found = await this.findOpenPrForBranch(projectKey, repoSlug, branch);
|
|
413
|
+
if (!found) {
|
|
414
|
+
// Fallback: search branches matching the input text, then check those for open PRs
|
|
415
|
+
found = await this.findOpenPrByBranchFilter(projectKey, repoSlug, branchDisplayId(branch));
|
|
416
|
+
}
|
|
400
417
|
if (!found)
|
|
401
418
|
throw new Error(`No open PR found for branch "${branchDisplayId(branch)}".`);
|
|
402
419
|
prId = found.id;
|
|
@@ -441,7 +458,8 @@ export class BitbucketClient {
|
|
|
441
458
|
if (statuses?.values?.length) {
|
|
442
459
|
const statusLines = statuses.values.map((s) => {
|
|
443
460
|
const icon = s.state === 'SUCCESSFUL' ? '✓' : s.state === 'FAILED' ? '✗' : '…';
|
|
444
|
-
|
|
461
|
+
const urlPart = s.url ? `\n URL: ${s.url}` : '';
|
|
462
|
+
return `${icon} [${s.state}] ${s.name ?? s.key}${s.description ? ` — ${s.description}` : ''}${urlPart}`;
|
|
445
463
|
});
|
|
446
464
|
sections.push(`Build status (${pr.fromRef.latestCommit.slice(0, 8)}):\n${statusLines.join('\n')}`);
|
|
447
465
|
}
|
|
@@ -1010,6 +1028,41 @@ export class BitbucketClient {
|
|
|
1010
1028
|
return text(`Task #${args.taskId} ${newState}.`);
|
|
1011
1029
|
return text(`Task #${updated.id} is now ${updated.state}: "${updated.text}"`);
|
|
1012
1030
|
}
|
|
1031
|
+
async getBuildLog(args) {
|
|
1032
|
+
const { url, maxLines = 150 } = args;
|
|
1033
|
+
const baseUrl = url.replace(/\/+$/, '');
|
|
1034
|
+
// Confirm the URL is Jenkins before doing anything else
|
|
1035
|
+
let probe;
|
|
1036
|
+
try {
|
|
1037
|
+
probe = await fetch(baseUrl, { method: 'HEAD' });
|
|
1038
|
+
}
|
|
1039
|
+
catch (e) {
|
|
1040
|
+
return text(`Network error reaching ${baseUrl}: ${e}`);
|
|
1041
|
+
}
|
|
1042
|
+
const jenkinsVersion = probe.headers.get('X-Jenkins');
|
|
1043
|
+
const fetchUrl = jenkinsVersion ? `${baseUrl}/consoleText` : baseUrl;
|
|
1044
|
+
const label = jenkinsVersion ? `Jenkins ${jenkinsVersion}` : 'CI';
|
|
1045
|
+
let res;
|
|
1046
|
+
try {
|
|
1047
|
+
res = await fetch(fetchUrl);
|
|
1048
|
+
}
|
|
1049
|
+
catch (e) {
|
|
1050
|
+
return text(`Network error fetching build log from ${fetchUrl}: ${e}`);
|
|
1051
|
+
}
|
|
1052
|
+
if (res.status === 401 || res.status === 403) {
|
|
1053
|
+
return text(`${label} returned HTTP ${res.status} for ${fetchUrl}.\n` +
|
|
1054
|
+
`The build log requires authentication. View it directly in your browser.`);
|
|
1055
|
+
}
|
|
1056
|
+
if (!res.ok) {
|
|
1057
|
+
return text(`Failed to fetch build log (HTTP ${res.status}) from ${fetchUrl}.`);
|
|
1058
|
+
}
|
|
1059
|
+
const raw = await res.text();
|
|
1060
|
+
const lines = raw.split('\n');
|
|
1061
|
+
const truncated = lines.length > maxLines;
|
|
1062
|
+
const shown = truncated ? lines.slice(-maxLines) : lines;
|
|
1063
|
+
const prefix = truncated ? `(showing last ${maxLines} of ${lines.length} lines)\n\n` : '';
|
|
1064
|
+
return text(`Build log from ${label} — ${fetchUrl}:\n${prefix}${shown.join('\n')}`);
|
|
1065
|
+
}
|
|
1013
1066
|
async getBuildStatuses(args) {
|
|
1014
1067
|
const data = await this.requestBuildStatus('GET', `/commits/${args.commitSha}`);
|
|
1015
1068
|
if (!data?.values?.length)
|
package/dist/index.js
CHANGED
|
@@ -405,6 +405,18 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
405
405
|
},
|
|
406
406
|
required: ['prId'],
|
|
407
407
|
},
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
name: 'bitbucket_get_build_log',
|
|
411
|
+
description: 'Fetch CI build console output. Jenkins is detected via the X-Jenkins response header. Use after seeing a failed build URL in bitbucket_get_pr output — pass the URL exactly as shown. Returns the last N lines of the log (default 150).',
|
|
412
|
+
inputSchema: {
|
|
413
|
+
type: 'object',
|
|
414
|
+
properties: {
|
|
415
|
+
url: { type: 'string', description: 'Build URL from CI status, e.g. https://jenkins.example.com/job/my-job/123/' },
|
|
416
|
+
maxLines: { type: 'number', description: 'Max lines to return from the end of the log (default 150)', default: 150 },
|
|
417
|
+
},
|
|
418
|
+
required: ['url'],
|
|
419
|
+
},
|
|
408
420
|
}] : []),
|
|
409
421
|
// ── Combined workflow ─────────────────────────────────────────────────
|
|
410
422
|
...(jira && bitbucket ? [{
|
|
@@ -646,6 +658,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
646
658
|
return await bitbucket.getPrTasks(a);
|
|
647
659
|
return await bitbucket.mutatePrTask({ ...a, action: action });
|
|
648
660
|
}
|
|
661
|
+
case 'bitbucket_get_build_log':
|
|
662
|
+
if (!bitbucket)
|
|
663
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
664
|
+
return await bitbucket.getBuildLog(args);
|
|
649
665
|
case 'complete_work': {
|
|
650
666
|
if (!jira || !bitbucket)
|
|
651
667
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|