@stubbedev/atlassian-mcp 0.0.4 → 0.1.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/dist/index.js CHANGED
@@ -7,38 +7,54 @@ import { loadConfig } from './config.js';
7
7
  import { JiraClient } from './jira.js';
8
8
  import { BitbucketClient } from './bitbucket.js';
9
9
  import { getContext, getCommits, getDiff } from './git.js';
10
- import { getDevContext, createPrFromContext } from './context.js';
10
+ import { getDevContext } from './context.js';
11
11
  const config = loadConfig();
12
12
  const jira = new JiraClient(config.jira.url, config.jira.token);
13
13
  const bitbucket = new BitbucketClient(config.bitbucket.url, config.bitbucket.token);
14
14
  const server = new Server({ name: 'atlassian-mcp', version: '1.0.0' }, { capabilities: { tools: {} } });
15
15
  server.onerror = (error) => console.error('[MCP Error]', error);
16
+ function normalizeBitbucketArgs(args) {
17
+ const src = (args && typeof args === 'object') ? args : {};
18
+ const out = { ...src };
19
+ if (typeof out.project === 'string' && typeof out.projectKey !== 'string')
20
+ out.projectKey = out.project;
21
+ if (typeof out.repo === 'string' && typeof out.repoSlug !== 'string')
22
+ out.repoSlug = out.repo;
23
+ return out;
24
+ }
25
+ function normalizeJiraProjectArgs(args) {
26
+ const src = (args && typeof args === 'object') ? args : {};
27
+ const out = { ...src };
28
+ if (typeof out.project === 'string' && typeof out.projectKey !== 'string')
29
+ out.projectKey = out.project;
30
+ return out;
31
+ }
16
32
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
17
33
  tools: [
18
34
  // ── Context ───────────────────────────────────────────────────────────
19
35
  {
20
36
  name: 'get_dev_context',
21
- description: 'One-shot developer context: reads the current git branch, fetches any linked Jira tickets detected in the branch name, and finds the open Bitbucket PR for the branch — all in a single call.',
37
+ description: 'Use when you want one quick snapshot before coding or reviewing: current git branch/status, Jira tickets detected from branch name, and the open Bitbucket PR for that branch.',
22
38
  inputSchema: {
23
39
  type: 'object',
24
40
  properties: {
25
- repoPath: { type: 'string', description: 'Path to the git repository (defaults to cwd)' },
41
+ repoPath: { type: 'string', description: 'Local path to the git repo (defaults to current working directory)' },
26
42
  },
27
43
  },
28
44
  },
29
45
  // ── Jira ──────────────────────────────────────────────────────────────
30
46
  {
31
47
  name: 'jira_search_issues',
32
- description: 'Search Jira issues. Use `query` for plain-text search (searches summary, description, and comments using Lucene full-text). Use `jql` for advanced queries. Combine `query` with `project`, `status`, `assignee`, or `issueType` to narrow results without writing JQL.',
48
+ description: 'Use when you want to find Jira tickets by natural language, keywords, or filters. Supports plain text search and advanced JQL.',
33
49
  inputSchema: {
34
50
  type: 'object',
35
51
  properties: {
36
- query: { type: 'string', description: 'Plain-text search across summary, description, and comments (fuzzy, stemmed)' },
37
- jql: { type: 'string', description: 'Raw JQL query overrides all other filters when provided' },
38
- project: { type: 'string', description: 'Filter by project key, e.g. "FOO"' },
39
- status: { type: 'string', description: 'Filter by status name, e.g. "In Progress"' },
40
- assignee: { type: 'string', description: 'Filter by assignee username' },
41
- issueType: { type: 'string', description: 'Filter by issue type, e.g. "Bug", "Story"' },
52
+ query: { type: 'string', description: 'Plain-text ticket search across summary, description, and comments' },
53
+ jql: { type: 'string', description: 'Raw JQL query (overrides other filters when provided)' },
54
+ project: { type: 'string', description: 'Project key filter, for example "FOO"' },
55
+ status: { type: 'string', description: 'Status filter, for example "In Progress"' },
56
+ assignee: { type: 'string', description: 'Assignee username filter' },
57
+ issueType: { type: 'string', description: 'Issue type filter, for example "Bug" or "Story"' },
42
58
  maxResults: { type: 'number', description: 'Max results per page (default 20)', default: 20 },
43
59
  startAt: { type: 'number', description: 'Offset for pagination (default 0)', default: 0 },
44
60
  },
@@ -46,7 +62,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
46
62
  },
47
63
  {
48
64
  name: 'jira_my_issues',
49
- description: 'List issues assigned to the current user, ordered by last updated',
65
+ description: 'Use when you want your Jira work queue: tickets assigned to you, newest updates first.',
50
66
  inputSchema: {
51
67
  type: 'object',
52
68
  properties: {
@@ -57,7 +73,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
57
73
  },
58
74
  {
59
75
  name: 'jira_get_projects',
60
- description: 'List all accessible Jira projects',
76
+ description: 'Use when you need available Jira projects and project codes before creating or searching tickets.',
61
77
  inputSchema: {
62
78
  type: 'object',
63
79
  properties: {
@@ -67,18 +83,18 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
67
83
  },
68
84
  {
69
85
  name: 'jira_get_issue_types',
70
- description: 'List issue types and their available statuses for a project use before jira_create_issue to see valid options',
86
+ description: 'Use when preparing to create tickets and you need valid issue types and statuses. If projectKey/project is omitted, the server auto-picks from branch context or asks you to choose.',
71
87
  inputSchema: {
72
88
  type: 'object',
73
89
  properties: {
74
- projectKey: { type: 'string', description: 'Jira project key' },
90
+ projectKey: { type: 'string', description: 'Jira project code, e.g. "PAY" from PAY-123 (optional)' },
91
+ project: { type: 'string', description: 'Alias for projectKey' },
75
92
  },
76
- required: ['projectKey'],
77
93
  },
78
94
  },
79
95
  {
80
96
  name: 'jira_search_users',
81
- description: 'Search for Jira users by name or username — use to find the correct username before assigning an issue',
97
+ description: 'Use when assigning tickets and you need to find the correct Jira username by name or email.',
82
98
  inputSchema: {
83
99
  type: 'object',
84
100
  properties: {
@@ -90,7 +106,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
90
106
  },
91
107
  {
92
108
  name: 'jira_get_issue',
93
- description: 'Get details of a Jira issue by key',
109
+ description: 'Use when you want full details for a specific Jira ticket by key (for example FOO-123).',
94
110
  inputSchema: {
95
111
  type: 'object',
96
112
  properties: {
@@ -101,23 +117,24 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
101
117
  },
102
118
  {
103
119
  name: 'jira_create_issue',
104
- description: 'Create a new Jira issue',
120
+ description: 'Use when you want to create a new Jira ticket (bug, story, task, etc.). If projectKey/project is omitted, the server auto-picks from branch context or asks you to choose.',
105
121
  inputSchema: {
106
122
  type: 'object',
107
123
  properties: {
108
- projectKey: { type: 'string', description: 'Jira project key' },
109
- issueType: { type: 'string', description: 'Issue type name, e.g. "Bug", "Story", "Task"' },
124
+ projectKey: { type: 'string', description: 'Jira project code, e.g. "PAY" from PAY-123 (optional)' },
125
+ project: { type: 'string', description: 'Alias for projectKey' },
126
+ issueType: { type: 'string', description: 'Issue type name, for example "Bug", "Story", or "Task"' },
110
127
  summary: { type: 'string', description: 'Issue title' },
111
128
  description: { type: 'string', description: 'Issue description (optional)' },
112
129
  assignee: { type: 'string', description: 'Username to assign to (optional)' },
113
130
  priority: { type: 'string', description: 'Priority name, e.g. "High" (optional)' },
114
131
  },
115
- required: ['projectKey', 'issueType', 'summary'],
132
+ required: ['issueType', 'summary'],
116
133
  },
117
134
  },
118
135
  {
119
136
  name: 'jira_update_issue',
120
- description: 'Update fields on an existing Jira issue (summary, description, assignee, priority)',
137
+ description: 'Use when you want to edit an existing Jira ticket: title, description, assignee, or priority.',
121
138
  inputSchema: {
122
139
  type: 'object',
123
140
  properties: {
@@ -132,7 +149,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
132
149
  },
133
150
  {
134
151
  name: 'jira_get_comments',
135
- description: 'Get comments on a Jira issue',
152
+ description: 'Use when you want the discussion thread on a Jira ticket, with pagination for long threads.',
136
153
  inputSchema: {
137
154
  type: 'object',
138
155
  properties: {
@@ -145,7 +162,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
145
162
  },
146
163
  {
147
164
  name: 'jira_add_comment',
148
- description: 'Add a comment to a Jira issue',
165
+ description: 'Use when you want to leave a comment on a Jira ticket.',
149
166
  inputSchema: {
150
167
  type: 'object',
151
168
  properties: {
@@ -155,52 +172,28 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
155
172
  required: ['issueKey', 'body'],
156
173
  },
157
174
  },
158
- {
159
- name: 'jira_get_transitions',
160
- description: 'List available status transitions for a Jira issue',
161
- inputSchema: {
162
- type: 'object',
163
- properties: {
164
- issueKey: { type: 'string', description: 'Jira issue key' },
165
- },
166
- required: ['issueKey'],
167
- },
168
- },
169
175
  {
170
176
  name: 'jira_transition_issue',
171
- description: 'Change the status of a Jira issue (get transition IDs from jira_get_transitions)',
177
+ description: 'Use when you want to move a Jira ticket to another status. Provide a transition name (for example "In Progress") or a transition ID.',
172
178
  inputSchema: {
173
179
  type: 'object',
174
180
  properties: {
175
- issueKey: { type: 'string', description: 'Jira issue key' },
176
- transitionId: { type: 'string', description: 'Transition ID from jira_get_transitions' },
181
+ issueKey: { type: 'string', description: 'Jira issue key, for example "FOO-123"' },
182
+ transitionId: { type: 'string', description: 'Transition ID (optional if transitionName is provided)' },
183
+ transitionName: { type: 'string', description: 'Transition name, for example "In Progress" (optional if transitionId is provided)' },
177
184
  },
178
- required: ['issueKey', 'transitionId'],
185
+ required: ['issueKey'],
179
186
  },
180
187
  },
181
188
  // ── Bitbucket ─────────────────────────────────────────────────────────
182
- {
183
- name: 'bitbucket_create_pr_from_context',
184
- description: 'Create a Bitbucket pull request using the current git repo — auto-detects project, repo, and branch from the git remote. Only requires a title.',
185
- inputSchema: {
186
- type: 'object',
187
- properties: {
188
- title: { type: 'string', description: 'PR title' },
189
- description: { type: 'string', description: 'PR description (optional)' },
190
- toBranch: { type: 'string', description: 'Target branch (default: master)' },
191
- reviewers: { type: 'array', items: { type: 'string' }, description: 'Reviewer usernames (optional)' },
192
- repoPath: { type: 'string', description: 'Path to the git repository (defaults to cwd)' },
193
- },
194
- required: ['title'],
195
- },
196
- },
197
189
  {
198
190
  name: 'bitbucket_list_repos',
199
- description: 'List Bitbucket repositories, optionally filtered by project key',
191
+ description: 'Use when you want to browse repositories in Bitbucket, optionally scoped to a project code. You can pass projectKey or project.',
200
192
  inputSchema: {
201
193
  type: 'object',
202
194
  properties: {
203
- projectKey: { type: 'string', description: 'Bitbucket project key (optional)' },
195
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (optional)' },
196
+ project: { type: 'string', description: 'Alias for projectKey' },
204
197
  limit: { type: 'number', description: 'Max repos per page (default 50)', default: 50 },
205
198
  start: { type: 'number', description: 'Offset for pagination (default 0)', default: 0 },
206
199
  },
@@ -208,13 +201,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
208
201
  },
209
202
  {
210
203
  name: 'bitbucket_list_pull_requests',
211
- description: 'List pull requests for a repository',
204
+ description: 'Use when you want pull requests for a repo (open, merged, or declined) with pagination. You can pass projectKey/repoSlug or project/repo.',
212
205
  inputSchema: {
213
206
  type: 'object',
214
207
  properties: {
215
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
216
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
217
- state: { type: 'string', enum: ['OPEN', 'MERGED', 'DECLINED', 'ALL'], description: 'PR state filter (default OPEN)', default: 'OPEN' },
208
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
209
+ project: { type: 'string', description: 'Alias for projectKey' },
210
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
211
+ repo: { type: 'string', description: 'Alias for repoSlug' },
212
+ state: { type: 'string', enum: ['OPEN', 'MERGED', 'DECLINED'], description: 'PR state filter (default OPEN)', default: 'OPEN' },
213
+ fromBranch: { type: 'string', description: 'Filter to PRs from this source branch (optional)' },
214
+ text: { type: 'string', description: 'Filter PRs where title or description contains this text (optional)' },
218
215
  limit: { type: 'number', description: 'Max PRs per page (default 25)', default: 25 },
219
216
  start: { type: 'number', description: 'Offset for pagination (default 0)', default: 0 },
220
217
  },
@@ -222,107 +219,148 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
222
219
  },
223
220
  {
224
221
  name: 'bitbucket_my_prs',
225
- description: 'List pull requests in your inbox (authored by you or awaiting your review)',
222
+ description: 'Use when you want your personal PR inbox (reviews requested, authored by you, or participated PRs).',
226
223
  inputSchema: {
227
224
  type: 'object',
228
225
  properties: {
229
226
  limit: { type: 'number', description: 'Max PRs per page (default 25)', default: 25 },
230
227
  start: { type: 'number', description: 'Offset for pagination (default 0)', default: 0 },
228
+ role: { type: 'string', enum: ['author', 'reviewer', 'participant'], description: 'Inbox role filter (default server behavior)' },
231
229
  },
232
230
  },
233
231
  },
234
232
  {
235
233
  name: 'bitbucket_get_pull_request',
236
- description: 'Get details of a specific pull request',
234
+ description: 'Use when you want metadata for one PR: title, branches, author, reviewers, and description. You can pass projectKey/repoSlug or project/repo.',
237
235
  inputSchema: {
238
236
  type: 'object',
239
237
  properties: {
240
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
241
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
242
- prId: { type: 'number', description: 'Pull request ID' },
238
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
239
+ project: { type: 'string', description: 'Alias for projectKey' },
240
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
241
+ repo: { type: 'string', description: 'Alias for repoSlug' },
242
+ prId: { type: 'number', description: 'Pull request number (PR ID)' },
243
+ },
244
+ required: ['prId'],
245
+ },
246
+ },
247
+ {
248
+ name: 'bitbucket_get_pr_overview',
249
+ description: 'Use when you want one bulk PR snapshot in a single call: metadata, commits, comments/blockers, and optional diff.',
250
+ inputSchema: {
251
+ type: 'object',
252
+ properties: {
253
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
254
+ project: { type: 'string', description: 'Alias for projectKey' },
255
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
256
+ repo: { type: 'string', description: 'Alias for repoSlug' },
257
+ prId: { type: 'number', description: 'Pull request number (PR ID)' },
258
+ includeCommits: { type: 'boolean', description: 'Include commit list (default true)', default: true },
259
+ includeComments: { type: 'boolean', description: 'Include review comments/blockers (default true)', default: true },
260
+ includeDiff: { type: 'boolean', description: 'Include diff text (default false)', default: false },
261
+ commentsState: { type: 'string', enum: ['OPEN', 'RESOLVED', 'PENDING'], description: 'Comment state filter (default OPEN)', default: 'OPEN' },
262
+ commentsSeverity: { type: 'string', enum: ['ALL', 'NORMAL', 'BLOCKER'], description: 'Comment severity filter (default ALL)', default: 'ALL' },
263
+ commentsLimit: { type: 'number', description: 'Max comments per page (default 50)', default: 50 },
264
+ commentsStart: { type: 'number', description: 'Comment pagination offset (default 0)', default: 0 },
265
+ commitsLimit: { type: 'number', description: 'Max commits per page (default 25)', default: 25 },
266
+ commitsStart: { type: 'number', description: 'Commit pagination offset (default 0)', default: 0 },
267
+ diffMaxChars: { type: 'number', description: 'Max diff characters when includeDiff=true (default 8000)', default: 8000 },
243
268
  },
244
269
  required: ['prId'],
245
270
  },
246
271
  },
247
272
  {
248
273
  name: 'bitbucket_get_pr_diff',
249
- description: 'Get the code diff for a pull request',
274
+ description: 'Use when you want the code changes for one PR as a unified diff. You can pass projectKey/repoSlug or project/repo.',
250
275
  inputSchema: {
251
276
  type: 'object',
252
277
  properties: {
253
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
254
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
255
- prId: { type: 'number', description: 'Pull request ID' },
278
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
279
+ project: { type: 'string', description: 'Alias for projectKey' },
280
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
281
+ repo: { type: 'string', description: 'Alias for repoSlug' },
282
+ prId: { type: 'number', description: 'Pull request number (PR ID)' },
256
283
  },
257
284
  required: ['prId'],
258
285
  },
259
286
  },
260
287
  {
261
288
  name: 'bitbucket_get_pr_commits',
262
- description: 'List commits included in a pull request',
289
+ description: 'Use when you want commit history included in a PR. You can pass projectKey/repoSlug or project/repo.',
263
290
  inputSchema: {
264
291
  type: 'object',
265
292
  properties: {
266
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
267
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
268
- prId: { type: 'number', description: 'Pull request ID' },
293
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
294
+ project: { type: 'string', description: 'Alias for projectKey' },
295
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
296
+ repo: { type: 'string', description: 'Alias for repoSlug' },
297
+ prId: { type: 'number', description: 'Pull request number (PR ID)' },
269
298
  limit: { type: 'number', description: 'Max commits (default 25)', default: 25 },
299
+ start: { type: 'number', description: 'Offset for pagination (default 0)', default: 0 },
270
300
  },
271
301
  required: ['prId'],
272
302
  },
273
303
  },
274
304
  {
275
305
  name: 'bitbucket_create_pull_request',
276
- description: 'Create a new pull request (project and repo can be auto-detected from git remote)',
306
+ description: 'Use when you want to open a new PR. Project/repo auto-detect from git remote, source branch auto-detects from current branch if omitted, and you can pass projectKey/repoSlug or project/repo.',
277
307
  inputSchema: {
278
308
  type: 'object',
279
309
  properties: {
280
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
281
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
310
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
311
+ project: { type: 'string', description: 'Alias for projectKey' },
312
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
313
+ repo: { type: 'string', description: 'Alias for repoSlug' },
282
314
  title: { type: 'string', description: 'PR title' },
283
315
  description: { type: 'string', description: 'PR description (optional)' },
284
- fromBranch: { type: 'string', description: 'Source branch name' },
316
+ fromBranch: { type: 'string', description: 'Source branch name (defaults to current branch)' },
285
317
  toBranch: { type: 'string', description: 'Target branch name (default: master)' },
286
318
  reviewers: { type: 'array', items: { type: 'string' }, description: 'Reviewer usernames (optional)' },
287
319
  },
288
- required: ['title', 'fromBranch'],
320
+ required: ['title'],
289
321
  },
290
322
  },
291
323
  {
292
324
  name: 'bitbucket_approve_pr',
293
- description: 'Approve a pull request',
325
+ description: 'Use when you want to approve a PR. You can pass projectKey/repoSlug or project/repo.',
294
326
  inputSchema: {
295
327
  type: 'object',
296
328
  properties: {
297
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
298
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
299
- prId: { type: 'number', description: 'Pull request ID' },
329
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
330
+ project: { type: 'string', description: 'Alias for projectKey' },
331
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
332
+ repo: { type: 'string', description: 'Alias for repoSlug' },
333
+ prId: { type: 'number', description: 'Pull request number (PR ID)' },
300
334
  },
301
335
  required: ['prId'],
302
336
  },
303
337
  },
304
338
  {
305
339
  name: 'bitbucket_unapprove_pr',
306
- description: 'Retract your approval from a pull request',
340
+ description: 'Use when you want to remove your PR approval. You can pass projectKey/repoSlug or project/repo.',
307
341
  inputSchema: {
308
342
  type: 'object',
309
343
  properties: {
310
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
311
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
312
- prId: { type: 'number', description: 'Pull request ID' },
344
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
345
+ project: { type: 'string', description: 'Alias for projectKey' },
346
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
347
+ repo: { type: 'string', description: 'Alias for repoSlug' },
348
+ prId: { type: 'number', description: 'Pull request number (PR ID)' },
313
349
  },
314
350
  required: ['prId'],
315
351
  },
316
352
  },
317
353
  {
318
354
  name: 'bitbucket_decline_pr',
319
- description: 'Decline a pull request',
355
+ description: 'Use when you want to decline/close a PR without merging. You can pass projectKey/repoSlug or project/repo.',
320
356
  inputSchema: {
321
357
  type: 'object',
322
358
  properties: {
323
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
324
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
325
- prId: { type: 'number', description: 'Pull request ID' },
359
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
360
+ project: { type: 'string', description: 'Alias for projectKey' },
361
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
362
+ repo: { type: 'string', description: 'Alias for repoSlug' },
363
+ prId: { type: 'number', description: 'Pull request number (PR ID)' },
326
364
  message: { type: 'string', description: 'Optional decline message' },
327
365
  },
328
366
  required: ['prId'],
@@ -330,13 +368,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
330
368
  },
331
369
  {
332
370
  name: 'bitbucket_merge_pr',
333
- description: 'Merge a pull request',
371
+ description: 'Use when you want to merge/land/ship a PR. You can pass projectKey/repoSlug or project/repo.',
334
372
  inputSchema: {
335
373
  type: 'object',
336
374
  properties: {
337
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
338
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
339
- prId: { type: 'number', description: 'Pull request ID' },
375
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
376
+ project: { type: 'string', description: 'Alias for projectKey' },
377
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
378
+ repo: { type: 'string', description: 'Alias for repoSlug' },
379
+ prId: { type: 'number', description: 'Pull request number (PR ID)' },
340
380
  mergeStrategy: { type: 'string', enum: ['MERGE_COMMIT', 'SQUASH', 'FAST_FORWARD'], description: 'Merge strategy (uses repo default if omitted)' },
341
381
  message: { type: 'string', description: 'Custom merge commit message (optional)' },
342
382
  },
@@ -345,14 +385,19 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
345
385
  },
346
386
  {
347
387
  name: 'bitbucket_get_pr_comments',
348
- description: 'Get pull request comment threads with comment IDs and states (needed for replies and resolving)',
388
+ description: 'Use when you want PR review discussion in bulk: comment threads, blocker comments, and blocker counts with pagination. You can pass projectKey/repoSlug or project/repo.',
349
389
  inputSchema: {
350
390
  type: 'object',
351
391
  properties: {
352
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
353
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
354
- prId: { type: 'number', description: 'Pull request ID' },
355
- state: { type: 'string', enum: ['OPEN', 'RESOLVED', 'PENDING'], description: 'Filter comment state (default OPEN)', default: 'OPEN' },
392
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
393
+ project: { type: 'string', description: 'Alias for projectKey' },
394
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
395
+ repo: { type: 'string', description: 'Alias for repoSlug' },
396
+ prId: { type: 'number', description: 'Pull request number (PR ID)' },
397
+ path: { type: 'string', description: 'Optional file path filter, e.g. "src/index.ts"' },
398
+ state: { type: 'string', enum: ['OPEN', 'RESOLVED', 'PENDING'], description: 'Comment state filter (default OPEN; BLOCKER mode supports OPEN/RESOLVED)', default: 'OPEN' },
399
+ severity: { type: 'string', enum: ['ALL', 'NORMAL', 'BLOCKER'], description: 'Comment severity filter. Use BLOCKER for blocker comments.', default: 'ALL' },
400
+ countOnly: { type: 'boolean', description: 'When true with severity=BLOCKER, returns counts instead of comment bodies', default: false },
356
401
  limit: { type: 'number', description: 'Max items per page (default 50)', default: 50 },
357
402
  start: { type: 'number', description: 'Offset for pagination (default 0)', default: 0 },
358
403
  },
@@ -361,13 +406,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
361
406
  },
362
407
  {
363
408
  name: 'bitbucket_add_pr_comment',
364
- description: 'Add a top-level comment or reply to an existing comment in a pull request',
409
+ description: 'Use when you want to add a PR review comment or reply to an existing thread. You can pass projectKey/repoSlug or project/repo.',
365
410
  inputSchema: {
366
411
  type: 'object',
367
412
  properties: {
368
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
369
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
370
- prId: { type: 'number', description: 'Pull request ID' },
413
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
414
+ project: { type: 'string', description: 'Alias for projectKey' },
415
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
416
+ repo: { type: 'string', description: 'Alias for repoSlug' },
417
+ prId: { type: 'number', description: 'Pull request number (PR ID)' },
371
418
  parentCommentId: { type: 'number', description: 'Parent comment ID for reply mode (optional)' },
372
419
  text: { type: 'string', description: 'Comment text' },
373
420
  },
@@ -376,30 +423,34 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
376
423
  },
377
424
  {
378
425
  name: 'bitbucket_update_pr_comment',
379
- description: 'Update comment text, state, and/or severity (convert comment <-> task)',
426
+ description: 'Use when you want to edit PR comments, resolve/reopen them, or set severity to BLOCKER. You can pass projectKey/repoSlug or project/repo.',
380
427
  inputSchema: {
381
428
  type: 'object',
382
429
  properties: {
383
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
384
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
385
- prId: { type: 'number', description: 'Pull request ID' },
430
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
431
+ project: { type: 'string', description: 'Alias for projectKey' },
432
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
433
+ repo: { type: 'string', description: 'Alias for repoSlug' },
434
+ prId: { type: 'number', description: 'Pull request number (PR ID)' },
386
435
  commentId: { type: 'number', description: 'Comment ID to update' },
387
436
  text: { type: 'string', description: 'New comment text (optional)' },
388
437
  state: { type: 'string', enum: ['OPEN', 'RESOLVED'], description: 'Comment state (optional)' },
389
- severity: { type: 'string', enum: ['NORMAL', 'BLOCKER'], description: 'Comment severity (optional, BLOCKER creates a task)' },
438
+ severity: { type: 'string', enum: ['NORMAL', 'BLOCKER'], description: 'Comment severity (optional)' },
390
439
  },
391
440
  required: ['prId', 'commentId'],
392
441
  },
393
442
  },
394
443
  {
395
444
  name: 'bitbucket_delete_pr_comment',
396
- description: 'Delete a pull request comment by ID',
445
+ description: 'Use when you want to delete a PR comment by comment ID. You can pass projectKey/repoSlug or project/repo.',
397
446
  inputSchema: {
398
447
  type: 'object',
399
448
  properties: {
400
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
401
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
402
- prId: { type: 'number', description: 'Pull request ID' },
449
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
450
+ project: { type: 'string', description: 'Alias for projectKey' },
451
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
452
+ repo: { type: 'string', description: 'Alias for repoSlug' },
453
+ prId: { type: 'number', description: 'Pull request number (PR ID)' },
403
454
  commentId: { type: 'number', description: 'Comment ID to delete' },
404
455
  },
405
456
  required: ['prId', 'commentId'],
@@ -407,12 +458,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
407
458
  },
408
459
  {
409
460
  name: 'bitbucket_get_branches',
410
- description: 'List branches in a repository',
461
+ description: 'Use when you want to browse repository branches or find a branch by name. You can pass projectKey/repoSlug or project/repo.',
411
462
  inputSchema: {
412
463
  type: 'object',
413
464
  properties: {
414
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
415
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
465
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
466
+ project: { type: 'string', description: 'Alias for projectKey' },
467
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
468
+ repo: { type: 'string', description: 'Alias for repoSlug' },
416
469
  filter: { type: 'string', description: 'Filter branches by name (optional)' },
417
470
  limit: { type: 'number', description: 'Max branches per page (default 25)', default: 25 },
418
471
  start: { type: 'number', description: 'Offset for pagination (default 0)', default: 0 },
@@ -421,12 +474,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
421
474
  },
422
475
  {
423
476
  name: 'bitbucket_get_file',
424
- description: 'Get the raw content of a file from a repository',
477
+ description: 'Use when you want raw file content from Bitbucket at a branch, tag, or commit. You can pass projectKey/repoSlug or project/repo.',
425
478
  inputSchema: {
426
479
  type: 'object',
427
480
  properties: {
428
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
429
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
481
+ projectKey: { type: 'string', description: 'Bitbucket project code, e.g. "ENG" (usually auto-detected)' },
482
+ project: { type: 'string', description: 'Alias for projectKey' },
483
+ repoSlug: { type: 'string', description: 'Repository slug, e.g. "payments-service" (usually auto-detected)' },
484
+ repo: { type: 'string', description: 'Alias for repoSlug' },
430
485
  path: { type: 'string', description: 'File path, e.g. "src/index.ts"' },
431
486
  ref: { type: 'string', description: 'Branch, tag, or commit hash (defaults to default branch)' },
432
487
  },
@@ -436,7 +491,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
436
491
  // ── Git ───────────────────────────────────────────────────────────────
437
492
  {
438
493
  name: 'git_get_context',
439
- description: 'Get git context for a local repo: current branch, remote URL, recent commits, working tree status, and any Jira keys detected in the branch name',
494
+ description: 'Use when you want a quick local git snapshot: branch, remote, recent commits, working tree status, and Jira keys in branch names.',
440
495
  inputSchema: {
441
496
  type: 'object',
442
497
  properties: {
@@ -447,7 +502,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
447
502
  },
448
503
  {
449
504
  name: 'git_get_commits',
450
- description: 'Get commit history for a branch with author and message details',
505
+ description: 'Use when you want commit history for a branch with author, date, and message.',
451
506
  inputSchema: {
452
507
  type: 'object',
453
508
  properties: {
@@ -459,7 +514,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
459
514
  },
460
515
  {
461
516
  name: 'git_get_diff',
462
- description: 'Get git diff uncommitted changes (vs HEAD) or between two refs',
517
+ description: 'Use when you want uncommitted changes or a diff between two refs/commits.',
463
518
  inputSchema: {
464
519
  type: 'object',
465
520
  properties: {
@@ -486,60 +541,58 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
486
541
  case 'jira_get_projects':
487
542
  return await jira.getProjects(args);
488
543
  case 'jira_get_issue_types':
489
- return await jira.getIssueTypes(args);
544
+ return await jira.getIssueTypes(normalizeJiraProjectArgs(args));
490
545
  case 'jira_search_users':
491
546
  return await jira.searchUsers(args);
492
547
  case 'jira_get_issue':
493
548
  return await jira.getIssue(args);
494
549
  case 'jira_create_issue':
495
- return await jira.createIssue(args);
550
+ return await jira.createIssue(normalizeJiraProjectArgs(args));
496
551
  case 'jira_update_issue':
497
552
  return await jira.updateIssue(args);
498
553
  case 'jira_get_comments':
499
554
  return await jira.getComments(args);
500
555
  case 'jira_add_comment':
501
556
  return await jira.addComment(args);
502
- case 'jira_get_transitions':
503
- return await jira.getTransitions(args);
504
557
  case 'jira_transition_issue':
505
558
  return await jira.transitionIssue(args);
506
559
  // Bitbucket
507
- case 'bitbucket_create_pr_from_context':
508
- return await createPrFromContext(args, bitbucket);
509
560
  case 'bitbucket_list_repos':
510
- return await bitbucket.listRepos(args);
561
+ return await bitbucket.listRepos(normalizeBitbucketArgs(args));
511
562
  case 'bitbucket_list_pull_requests':
512
- return await bitbucket.listPullRequests(args);
563
+ return await bitbucket.listPullRequests(normalizeBitbucketArgs(args));
513
564
  case 'bitbucket_my_prs':
514
565
  return await bitbucket.myPrs(args);
515
566
  case 'bitbucket_get_pull_request':
516
- return await bitbucket.getPullRequest(args);
567
+ return await bitbucket.getPullRequest(normalizeBitbucketArgs(args));
568
+ case 'bitbucket_get_pr_overview':
569
+ return await bitbucket.getPrOverview(normalizeBitbucketArgs(args));
517
570
  case 'bitbucket_get_pr_diff':
518
- return await bitbucket.getPrDiff(args);
571
+ return await bitbucket.getPrDiff(normalizeBitbucketArgs(args));
519
572
  case 'bitbucket_get_pr_commits':
520
- return await bitbucket.getPrCommits(args);
573
+ return await bitbucket.getPrCommits(normalizeBitbucketArgs(args));
521
574
  case 'bitbucket_create_pull_request':
522
- return await bitbucket.createPullRequest(args);
575
+ return await bitbucket.createPullRequest(normalizeBitbucketArgs(args));
523
576
  case 'bitbucket_approve_pr':
524
- return await bitbucket.approvePr(args);
577
+ return await bitbucket.approvePr(normalizeBitbucketArgs(args));
525
578
  case 'bitbucket_unapprove_pr':
526
- return await bitbucket.unapprovePr(args);
579
+ return await bitbucket.unapprovePr(normalizeBitbucketArgs(args));
527
580
  case 'bitbucket_decline_pr':
528
- return await bitbucket.declinePr(args);
581
+ return await bitbucket.declinePr(normalizeBitbucketArgs(args));
529
582
  case 'bitbucket_merge_pr':
530
- return await bitbucket.mergePr(args);
583
+ return await bitbucket.mergePr(normalizeBitbucketArgs(args));
531
584
  case 'bitbucket_get_pr_comments':
532
- return await bitbucket.getPrComments(args);
585
+ return await bitbucket.getPrComments(normalizeBitbucketArgs(args));
533
586
  case 'bitbucket_add_pr_comment':
534
- return await bitbucket.addPrComment(args);
587
+ return await bitbucket.addPrComment(normalizeBitbucketArgs(args));
535
588
  case 'bitbucket_update_pr_comment':
536
- return await bitbucket.updatePrComment(args);
589
+ return await bitbucket.updatePrComment(normalizeBitbucketArgs(args));
537
590
  case 'bitbucket_delete_pr_comment':
538
- return await bitbucket.deletePrComment(args);
591
+ return await bitbucket.deletePrComment(normalizeBitbucketArgs(args));
539
592
  case 'bitbucket_get_branches':
540
- return await bitbucket.getBranches(args);
593
+ return await bitbucket.getBranches(normalizeBitbucketArgs(args));
541
594
  case 'bitbucket_get_file':
542
- return await bitbucket.getFile(args);
595
+ return await bitbucket.getFile(normalizeBitbucketArgs(args));
543
596
  // Git
544
597
  case 'git_get_context':
545
598
  return getContext(args);