cli / mcp for bitbucket
at main 167 lines 5.5 kB view raw
1import { 2 addComment, 3 createPullRequest, 4 declinePullRequest, 5 getPullRequest, 6 getPullRequestComments, 7 getPullRequestDiff, 8 listPullRequests, 9 updatePullRequest, 10} from '@bitbucket-tool/core'; 11import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; 12import { 13 addPullRequestCommentSchema, 14 createPullRequestSchema, 15 declinePullRequestSchema, 16 getPullRequestCommentsSchema, 17 getPullRequestDiffSchema, 18 getPullRequestSchema, 19 listPullRequestsSchema, 20 updatePullRequestSchema, 21} from '../schemas/pr.schemas'; 22import { resolveWorkspace, resultToResponse } from './helpers'; 23 24export const registerPrTools = (server: McpServer): void => { 25 // @ts-expect-error TS2589: MCP SDK overload resolution + transitive generated types exceed TypeScript recursion limit 26 server.tool( 27 'list_pull_requests', 28 'List pull requests for a repository. Use state to filter by OPEN, MERGED, DECLINED, or SUPERSEDED. Returns PR IDs needed by other PR tools.', 29 listPullRequestsSchema, 30 { readOnlyHint: true }, 31 async ({ workspace, repo_slug, state, page, pagelen }) => { 32 const w = resolveWorkspace(workspace); 33 return resultToResponse( 34 await listPullRequests({ workspace: w, repoSlug: repo_slug, state, page, pagelen }) 35 ); 36 } 37 ); 38 39 // @ts-expect-error TS2589: MCP SDK overload resolution + transitive generated types exceed TypeScript recursion limit 40 server.tool( 41 'get_pull_request', 42 'Get details of a specific pull request including title, description, source/destination branches, author, and status. Use list_pull_requests to find PR IDs.', 43 getPullRequestSchema, 44 { readOnlyHint: true }, 45 async ({ workspace, repo_slug, pull_request_id }) => { 46 const w = resolveWorkspace(workspace); 47 return resultToResponse( 48 await getPullRequest({ workspace: w, repoSlug: repo_slug, prId: pull_request_id }) 49 ); 50 } 51 ); 52 53 server.tool( 54 'create_pull_request', 55 'Create a new pull request. Requires source branch and title. Destination defaults to main.', 56 createPullRequestSchema, 57 { readOnlyHint: false }, 58 async ({ workspace, repo_slug, source_branch, destination_branch, title, description }) => { 59 const w = resolveWorkspace(workspace); 60 return resultToResponse( 61 await createPullRequest({ 62 workspace: w, 63 repoSlug: repo_slug, 64 sourceBranch: source_branch, 65 destinationBranch: destination_branch ?? 'main', 66 title, 67 description, 68 }) 69 ); 70 } 71 ); 72 73 server.tool( 74 'update_pull_request', 75 'Update an existing pull request. Can change title, description, or destination branch. Use get_pull_request to see current values first.', 76 updatePullRequestSchema, 77 { readOnlyHint: false, idempotentHint: true }, 78 async ({ workspace, repo_slug, pull_request_id, title, description, destination_branch }) => { 79 const w = resolveWorkspace(workspace); 80 const updates = { 81 ...(title !== undefined && { title }), 82 ...(description !== undefined && { description }), 83 ...(destination_branch !== undefined && { 84 destination: { branch: { name: destination_branch } }, 85 }), 86 }; 87 88 return resultToResponse( 89 await updatePullRequest({ 90 workspace: w, 91 repoSlug: repo_slug, 92 prId: pull_request_id, 93 updates, 94 }) 95 ); 96 } 97 ); 98 99 server.tool( 100 'decline_pull_request', 101 'Decline (close) a pull request. This is irreversible.', 102 declinePullRequestSchema, 103 { readOnlyHint: false, destructiveHint: true }, 104 async ({ workspace, repo_slug, pull_request_id }) => { 105 const w = resolveWorkspace(workspace); 106 return resultToResponse( 107 await declinePullRequest({ workspace: w, repoSlug: repo_slug, prId: pull_request_id }), 108 () => 'Pull request declined.' 109 ); 110 } 111 ); 112 113 server.tool( 114 'get_pull_request_comments', 115 'Get all comments on a pull request, including inline code review comments with file/line information.', 116 getPullRequestCommentsSchema, 117 { readOnlyHint: true }, 118 async ({ workspace, repo_slug, pull_request_id, page, pagelen }) => { 119 const w = resolveWorkspace(workspace); 120 return resultToResponse( 121 await getPullRequestComments({ 122 workspace: w, 123 repoSlug: repo_slug, 124 prId: pull_request_id, 125 page, 126 pagelen, 127 }) 128 ); 129 } 130 ); 131 132 server.tool( 133 'add_pull_request_comment', 134 'Add a comment to a pull request. Supports Markdown formatting.', 135 addPullRequestCommentSchema, 136 { readOnlyHint: false }, 137 async ({ workspace, repo_slug, pull_request_id, content }) => { 138 const w = resolveWorkspace(workspace); 139 return resultToResponse( 140 await addComment({ 141 workspace: w, 142 repoSlug: repo_slug, 143 prId: pull_request_id, 144 content, 145 }), 146 () => 'Comment added.' 147 ); 148 } 149 ); 150 151 server.tool( 152 'get_pull_request_diff', 153 'Get the diff for a pull request. Returns raw unified diff text. Use get_pull_request for metadata.', 154 getPullRequestDiffSchema, 155 { readOnlyHint: true }, 156 async ({ workspace, repo_slug, pull_request_id }) => { 157 const w = resolveWorkspace(workspace); 158 const result = await getPullRequestDiff({ 159 workspace: w, 160 repoSlug: repo_slug, 161 prId: pull_request_id, 162 }); 163 164 return resultToResponse(result, (diff) => diff); 165 } 166 ); 167};