@stubbedev/atlassian-mcp 0.0.5 → 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,7 +219,7 @@ 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: {
@@ -234,39 +231,70 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
234
231
  },
235
232
  {
236
233
  name: 'bitbucket_get_pull_request',
237
- 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.',
235
+ inputSchema: {
236
+ type: 'object',
237
+ properties: {
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.',
238
250
  inputSchema: {
239
251
  type: 'object',
240
252
  properties: {
241
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
242
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
243
- prId: { type: 'number', description: 'Pull request ID' },
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 },
244
268
  },
245
269
  required: ['prId'],
246
270
  },
247
271
  },
248
272
  {
249
273
  name: 'bitbucket_get_pr_diff',
250
- 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.',
251
275
  inputSchema: {
252
276
  type: 'object',
253
277
  properties: {
254
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
255
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
256
- 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)' },
257
283
  },
258
284
  required: ['prId'],
259
285
  },
260
286
  },
261
287
  {
262
288
  name: 'bitbucket_get_pr_commits',
263
- 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.',
264
290
  inputSchema: {
265
291
  type: 'object',
266
292
  properties: {
267
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
268
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
269
- 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)' },
270
298
  limit: { type: 'number', description: 'Max commits (default 25)', default: 25 },
271
299
  start: { type: 'number', description: 'Offset for pagination (default 0)', default: 0 },
272
300
  },
@@ -275,56 +303,64 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
275
303
  },
276
304
  {
277
305
  name: 'bitbucket_create_pull_request',
278
- 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.',
279
307
  inputSchema: {
280
308
  type: 'object',
281
309
  properties: {
282
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
283
- 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' },
284
314
  title: { type: 'string', description: 'PR title' },
285
315
  description: { type: 'string', description: 'PR description (optional)' },
286
- fromBranch: { type: 'string', description: 'Source branch name' },
316
+ fromBranch: { type: 'string', description: 'Source branch name (defaults to current branch)' },
287
317
  toBranch: { type: 'string', description: 'Target branch name (default: master)' },
288
318
  reviewers: { type: 'array', items: { type: 'string' }, description: 'Reviewer usernames (optional)' },
289
319
  },
290
- required: ['title', 'fromBranch'],
320
+ required: ['title'],
291
321
  },
292
322
  },
293
323
  {
294
324
  name: 'bitbucket_approve_pr',
295
- description: 'Approve a pull request',
325
+ description: 'Use when you want to approve a PR. You can pass projectKey/repoSlug or project/repo.',
296
326
  inputSchema: {
297
327
  type: 'object',
298
328
  properties: {
299
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
300
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
301
- 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)' },
302
334
  },
303
335
  required: ['prId'],
304
336
  },
305
337
  },
306
338
  {
307
339
  name: 'bitbucket_unapprove_pr',
308
- 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.',
309
341
  inputSchema: {
310
342
  type: 'object',
311
343
  properties: {
312
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
313
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
314
- 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)' },
315
349
  },
316
350
  required: ['prId'],
317
351
  },
318
352
  },
319
353
  {
320
354
  name: 'bitbucket_decline_pr',
321
- 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.',
322
356
  inputSchema: {
323
357
  type: 'object',
324
358
  properties: {
325
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
326
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
327
- 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)' },
328
364
  message: { type: 'string', description: 'Optional decline message' },
329
365
  },
330
366
  required: ['prId'],
@@ -332,13 +368,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
332
368
  },
333
369
  {
334
370
  name: 'bitbucket_merge_pr',
335
- 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.',
336
372
  inputSchema: {
337
373
  type: 'object',
338
374
  properties: {
339
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
340
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
341
- 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)' },
342
380
  mergeStrategy: { type: 'string', enum: ['MERGE_COMMIT', 'SQUASH', 'FAST_FORWARD'], description: 'Merge strategy (uses repo default if omitted)' },
343
381
  message: { type: 'string', description: 'Custom merge commit message (optional)' },
344
382
  },
@@ -347,59 +385,36 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
347
385
  },
348
386
  {
349
387
  name: 'bitbucket_get_pr_comments',
350
- description: 'Get pull request comment threads with comment IDs and states (uses activities feed unless a path filter is provided)',
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.',
351
389
  inputSchema: {
352
390
  type: 'object',
353
391
  properties: {
354
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
355
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
356
- prId: { type: 'number', description: 'Pull request ID' },
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)' },
357
397
  path: { type: 'string', description: 'Optional file path filter, e.g. "src/index.ts"' },
358
- state: { type: 'string', enum: ['OPEN', 'RESOLVED', 'PENDING'], description: 'Filter comment state (default OPEN)', default: 'OPEN' },
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 },
359
401
  limit: { type: 'number', description: 'Max items per page (default 50)', default: 50 },
360
402
  start: { type: 'number', description: 'Offset for pagination (default 0)', default: 0 },
361
403
  },
362
404
  required: ['prId'],
363
405
  },
364
406
  },
365
- {
366
- name: 'bitbucket_get_pr_tasks',
367
- description: 'List blocker comments (tasks) on a pull request',
368
- inputSchema: {
369
- type: 'object',
370
- properties: {
371
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
372
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
373
- prId: { type: 'number', description: 'Pull request ID' },
374
- state: { type: 'string', enum: ['OPEN', 'RESOLVED'], description: 'Task state filter (default OPEN)', default: 'OPEN' },
375
- limit: { type: 'number', description: 'Max tasks per page (default 50)', default: 50 },
376
- start: { type: 'number', description: 'Offset for pagination (default 0)', default: 0 },
377
- },
378
- required: ['prId'],
379
- },
380
- },
381
- {
382
- name: 'bitbucket_get_pr_task_count',
383
- description: 'Get total OPEN and RESOLVED task counts for a pull request',
384
- inputSchema: {
385
- type: 'object',
386
- properties: {
387
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
388
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
389
- prId: { type: 'number', description: 'Pull request ID' },
390
- },
391
- required: ['prId'],
392
- },
393
- },
394
407
  {
395
408
  name: 'bitbucket_add_pr_comment',
396
- 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.',
397
410
  inputSchema: {
398
411
  type: 'object',
399
412
  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' },
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)' },
403
418
  parentCommentId: { type: 'number', description: 'Parent comment ID for reply mode (optional)' },
404
419
  text: { type: 'string', description: 'Comment text' },
405
420
  },
@@ -408,30 +423,34 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
408
423
  },
409
424
  {
410
425
  name: 'bitbucket_update_pr_comment',
411
- 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.',
412
427
  inputSchema: {
413
428
  type: 'object',
414
429
  properties: {
415
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
416
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
417
- 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)' },
418
435
  commentId: { type: 'number', description: 'Comment ID to update' },
419
436
  text: { type: 'string', description: 'New comment text (optional)' },
420
437
  state: { type: 'string', enum: ['OPEN', 'RESOLVED'], description: 'Comment state (optional)' },
421
- 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)' },
422
439
  },
423
440
  required: ['prId', 'commentId'],
424
441
  },
425
442
  },
426
443
  {
427
444
  name: 'bitbucket_delete_pr_comment',
428
- 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.',
429
446
  inputSchema: {
430
447
  type: 'object',
431
448
  properties: {
432
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
433
- repoSlug: { type: 'string', description: 'Repository slug (auto-detected from git remote if omitted)' },
434
- 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)' },
435
454
  commentId: { type: 'number', description: 'Comment ID to delete' },
436
455
  },
437
456
  required: ['prId', 'commentId'],
@@ -439,12 +458,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
439
458
  },
440
459
  {
441
460
  name: 'bitbucket_get_branches',
442
- 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.',
443
462
  inputSchema: {
444
463
  type: 'object',
445
464
  properties: {
446
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
447
- 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' },
448
469
  filter: { type: 'string', description: 'Filter branches by name (optional)' },
449
470
  limit: { type: 'number', description: 'Max branches per page (default 25)', default: 25 },
450
471
  start: { type: 'number', description: 'Offset for pagination (default 0)', default: 0 },
@@ -453,12 +474,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
453
474
  },
454
475
  {
455
476
  name: 'bitbucket_get_file',
456
- 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.',
457
478
  inputSchema: {
458
479
  type: 'object',
459
480
  properties: {
460
- projectKey: { type: 'string', description: 'Bitbucket project key (auto-detected from git remote if omitted)' },
461
- 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' },
462
485
  path: { type: 'string', description: 'File path, e.g. "src/index.ts"' },
463
486
  ref: { type: 'string', description: 'Branch, tag, or commit hash (defaults to default branch)' },
464
487
  },
@@ -468,7 +491,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
468
491
  // ── Git ───────────────────────────────────────────────────────────────
469
492
  {
470
493
  name: 'git_get_context',
471
- 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.',
472
495
  inputSchema: {
473
496
  type: 'object',
474
497
  properties: {
@@ -479,7 +502,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
479
502
  },
480
503
  {
481
504
  name: 'git_get_commits',
482
- 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.',
483
506
  inputSchema: {
484
507
  type: 'object',
485
508
  properties: {
@@ -491,7 +514,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
491
514
  },
492
515
  {
493
516
  name: 'git_get_diff',
494
- 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.',
495
518
  inputSchema: {
496
519
  type: 'object',
497
520
  properties: {
@@ -518,64 +541,58 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
518
541
  case 'jira_get_projects':
519
542
  return await jira.getProjects(args);
520
543
  case 'jira_get_issue_types':
521
- return await jira.getIssueTypes(args);
544
+ return await jira.getIssueTypes(normalizeJiraProjectArgs(args));
522
545
  case 'jira_search_users':
523
546
  return await jira.searchUsers(args);
524
547
  case 'jira_get_issue':
525
548
  return await jira.getIssue(args);
526
549
  case 'jira_create_issue':
527
- return await jira.createIssue(args);
550
+ return await jira.createIssue(normalizeJiraProjectArgs(args));
528
551
  case 'jira_update_issue':
529
552
  return await jira.updateIssue(args);
530
553
  case 'jira_get_comments':
531
554
  return await jira.getComments(args);
532
555
  case 'jira_add_comment':
533
556
  return await jira.addComment(args);
534
- case 'jira_get_transitions':
535
- return await jira.getTransitions(args);
536
557
  case 'jira_transition_issue':
537
558
  return await jira.transitionIssue(args);
538
559
  // Bitbucket
539
- case 'bitbucket_create_pr_from_context':
540
- return await createPrFromContext(args, bitbucket);
541
560
  case 'bitbucket_list_repos':
542
- return await bitbucket.listRepos(args);
561
+ return await bitbucket.listRepos(normalizeBitbucketArgs(args));
543
562
  case 'bitbucket_list_pull_requests':
544
- return await bitbucket.listPullRequests(args);
563
+ return await bitbucket.listPullRequests(normalizeBitbucketArgs(args));
545
564
  case 'bitbucket_my_prs':
546
565
  return await bitbucket.myPrs(args);
547
566
  case 'bitbucket_get_pull_request':
548
- 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));
549
570
  case 'bitbucket_get_pr_diff':
550
- return await bitbucket.getPrDiff(args);
571
+ return await bitbucket.getPrDiff(normalizeBitbucketArgs(args));
551
572
  case 'bitbucket_get_pr_commits':
552
- return await bitbucket.getPrCommits(args);
573
+ return await bitbucket.getPrCommits(normalizeBitbucketArgs(args));
553
574
  case 'bitbucket_create_pull_request':
554
- return await bitbucket.createPullRequest(args);
575
+ return await bitbucket.createPullRequest(normalizeBitbucketArgs(args));
555
576
  case 'bitbucket_approve_pr':
556
- return await bitbucket.approvePr(args);
577
+ return await bitbucket.approvePr(normalizeBitbucketArgs(args));
557
578
  case 'bitbucket_unapprove_pr':
558
- return await bitbucket.unapprovePr(args);
579
+ return await bitbucket.unapprovePr(normalizeBitbucketArgs(args));
559
580
  case 'bitbucket_decline_pr':
560
- return await bitbucket.declinePr(args);
581
+ return await bitbucket.declinePr(normalizeBitbucketArgs(args));
561
582
  case 'bitbucket_merge_pr':
562
- return await bitbucket.mergePr(args);
583
+ return await bitbucket.mergePr(normalizeBitbucketArgs(args));
563
584
  case 'bitbucket_get_pr_comments':
564
- return await bitbucket.getPrComments(args);
565
- case 'bitbucket_get_pr_tasks':
566
- return await bitbucket.getPrTasks(args);
567
- case 'bitbucket_get_pr_task_count':
568
- return await bitbucket.getPrTaskCount(args);
585
+ return await bitbucket.getPrComments(normalizeBitbucketArgs(args));
569
586
  case 'bitbucket_add_pr_comment':
570
- return await bitbucket.addPrComment(args);
587
+ return await bitbucket.addPrComment(normalizeBitbucketArgs(args));
571
588
  case 'bitbucket_update_pr_comment':
572
- return await bitbucket.updatePrComment(args);
589
+ return await bitbucket.updatePrComment(normalizeBitbucketArgs(args));
573
590
  case 'bitbucket_delete_pr_comment':
574
- return await bitbucket.deletePrComment(args);
591
+ return await bitbucket.deletePrComment(normalizeBitbucketArgs(args));
575
592
  case 'bitbucket_get_branches':
576
- return await bitbucket.getBranches(args);
593
+ return await bitbucket.getBranches(normalizeBitbucketArgs(args));
577
594
  case 'bitbucket_get_file':
578
- return await bitbucket.getFile(args);
595
+ return await bitbucket.getFile(normalizeBitbucketArgs(args));
579
596
  // Git
580
597
  case 'git_get_context':
581
598
  return getContext(args);