UNPKG

bitbucket-mcp

Version:

Model Context Protocol (MCP) server for Bitbucket Cloud and Server API integration

1,246 lines 54.4 kB
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from "@modelcontextprotocol/sdk/types.js";
import axios from "axios";
import winston from "winston";
// =========== LOGGER SETUP ===========
// Simple logger that only writes to a file (no stdout pollution)
const logger = winston.createLogger({
    level: "info",
    format: winston.format.json(),
    transports: [new winston.transports.File({ filename: "bitbucket.log" })],
});
// =========== MCP SERVER ===========
class BitbucketServer {
    constructor() {
        // Initialize with the older Server class pattern
        this.server = new Server({
            name: "bitbucket-mcp-server",
            version: "1.0.0",
        }, {
            capabilities: {
                tools: {},
            },
        });
        // Configuration from environment variables
        this.config = {
            baseUrl: process.env.BITBUCKET_URL ?? "https://api.bitbucket.org/2.0",
            token: process.env.BITBUCKET_TOKEN,
            username: process.env.BITBUCKET_USERNAME,
            password: process.env.BITBUCKET_PASSWORD,
            defaultWorkspace: process.env.BITBUCKET_WORKSPACE,
        };
        // Validate required config
        if (!this.config.baseUrl) {
            throw new Error("BITBUCKET_URL is required");
        }
        if (!this.config.token && !(this.config.username && this.config.password)) {
            throw new Error("Either BITBUCKET_TOKEN or BITBUCKET_USERNAME/PASSWORD is required");
        }
        // Setup Axios instance
        this.api = axios.create({
            baseURL: this.config.baseUrl,
            headers: this.config.token
                ? { Authorization: `Bearer ${this.config.token}` }
                : { "Content-Type": "application/json" },
            auth: this.config.username && this.config.password
                ? { username: this.config.username, password: this.config.password }
                : undefined,
        });
        // Setup tool handlers using the request handler pattern
        this.setupToolHandlers();
        // Add error handler - CRITICAL for stability
        this.server.onerror = (error) => logger.error("[MCP Error]", error);
    }
    setupToolHandlers() {
        // Register the list tools handler
        this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
            tools: [
                {
                    name: "listRepositories",
                    description: "List Bitbucket repositories",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            limit: {
                                type: "number",
                                description: "Maximum number of repositories to return",
                            },
                        },
                    },
                },
                {
                    name: "getRepository",
                    description: "Get repository details",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                        },
                        required: ["workspace", "repo_slug"],
                    },
                },
                {
                    name: "getPullRequests",
                    description: "Get pull requests for a repository",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                            state: {
                                type: "string",
                                enum: ["OPEN", "MERGED", "DECLINED", "SUPERSEDED"],
                                description: "Pull request state",
                            },
                            limit: {
                                type: "number",
                                description: "Maximum number of pull requests to return",
                            },
                        },
                        required: ["workspace", "repo_slug"],
                    },
                },
                {
                    name: "createPullRequest",
                    description: "Create a new pull request",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                            title: { type: "string", description: "Pull request title" },
                            description: {
                                type: "string",
                                description: "Pull request description",
                            },
                            sourceBranch: {
                                type: "string",
                                description: "Source branch name",
                            },
                            targetBranch: {
                                type: "string",
                                description: "Target branch name",
                            },
                            reviewers: {
                                type: "array",
                                items: { type: "string" },
                                description: "List of reviewer usernames",
                            },
                        },
                        required: [
                            "workspace",
                            "repo_slug",
                            "title",
                            "description",
                            "sourceBranch",
                            "targetBranch",
                        ],
                    },
                },
                {
                    name: "getPullRequest",
                    description: "Get details for a specific pull request",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                            pull_request_id: {
                                type: "string",
                                description: "Pull request ID",
                            },
                        },
                        required: ["workspace", "repo_slug", "pull_request_id"],
                    },
                },
                {
                    name: "updatePullRequest",
                    description: "Update a pull request",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                            pull_request_id: {
                                type: "string",
                                description: "Pull request ID",
                            },
                            title: { type: "string", description: "New pull request title" },
                            description: {
                                type: "string",
                                description: "New pull request description",
                            },
                        },
                        required: ["workspace", "repo_slug", "pull_request_id"],
                    },
                },
                {
                    name: "getPullRequestActivity",
                    description: "Get activity log for a pull request",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                            pull_request_id: {
                                type: "string",
                                description: "Pull request ID",
                            },
                        },
                        required: ["workspace", "repo_slug", "pull_request_id"],
                    },
                },
                {
                    name: "approvePullRequest",
                    description: "Approve a pull request",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                            pull_request_id: {
                                type: "string",
                                description: "Pull request ID",
                            },
                        },
                        required: ["workspace", "repo_slug", "pull_request_id"],
                    },
                },
                {
                    name: "unapprovePullRequest",
                    description: "Remove approval from a pull request",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                            pull_request_id: {
                                type: "string",
                                description: "Pull request ID",
                            },
                        },
                        required: ["workspace", "repo_slug", "pull_request_id"],
                    },
                },
                {
                    name: "declinePullRequest",
                    description: "Decline a pull request",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                            pull_request_id: {
                                type: "string",
                                description: "Pull request ID",
                            },
                            message: { type: "string", description: "Reason for declining" },
                        },
                        required: ["workspace", "repo_slug", "pull_request_id"],
                    },
                },
                {
                    name: "mergePullRequest",
                    description: "Merge a pull request",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                            pull_request_id: {
                                type: "string",
                                description: "Pull request ID",
                            },
                            message: { type: "string", description: "Merge commit message" },
                            strategy: {
                                type: "string",
                                enum: ["merge-commit", "squash", "fast-forward"],
                                description: "Merge strategy",
                            },
                        },
                        required: ["workspace", "repo_slug", "pull_request_id"],
                    },
                },
                {
                    name: "getPullRequestComments",
                    description: "List comments on a pull request",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                            pull_request_id: {
                                type: "string",
                                description: "Pull request ID",
                            },
                        },
                        required: ["workspace", "repo_slug", "pull_request_id"],
                    },
                },
                {
                    name: "getPullRequestDiff",
                    description: "Get diff for a pull request",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                            pull_request_id: {
                                type: "string",
                                description: "Pull request ID",
                            },
                        },
                        required: ["workspace", "repo_slug", "pull_request_id"],
                    },
                },
                {
                    name: "getPullRequestCommits",
                    description: "Get commits on a pull request",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                            pull_request_id: {
                                type: "string",
                                description: "Pull request ID",
                            },
                        },
                        required: ["workspace", "repo_slug", "pull_request_id"],
                    },
                },
                {
                    name: "getRepositoryBranchingModel",
                    description: "Get the branching model for a repository",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                        },
                        required: ["workspace", "repo_slug"],
                    },
                },
                {
                    name: "getRepositoryBranchingModelSettings",
                    description: "Get the branching model config for a repository",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                        },
                        required: ["workspace", "repo_slug"],
                    },
                },
                {
                    name: "updateRepositoryBranchingModelSettings",
                    description: "Update the branching model config for a repository",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                            development: {
                                type: "object",
                                description: "Development branch settings",
                                properties: {
                                    name: { type: "string", description: "Branch name" },
                                    use_mainbranch: {
                                        type: "boolean",
                                        description: "Use main branch",
                                    },
                                },
                            },
                            production: {
                                type: "object",
                                description: "Production branch settings",
                                properties: {
                                    name: { type: "string", description: "Branch name" },
                                    use_mainbranch: {
                                        type: "boolean",
                                        description: "Use main branch",
                                    },
                                    enabled: {
                                        type: "boolean",
                                        description: "Enable production branch",
                                    },
                                },
                            },
                            branch_types: {
                                type: "array",
                                description: "Branch types configuration",
                                items: {
                                    type: "object",
                                    properties: {
                                        kind: {
                                            type: "string",
                                            description: "Branch type kind (e.g., bugfix, feature)",
                                        },
                                        prefix: { type: "string", description: "Branch prefix" },
                                        enabled: {
                                            type: "boolean",
                                            description: "Enable this branch type",
                                        },
                                    },
                                    required: ["kind"],
                                },
                            },
                        },
                        required: ["workspace", "repo_slug"],
                    },
                },
                {
                    name: "getEffectiveRepositoryBranchingModel",
                    description: "Get the effective branching model for a repository",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            repo_slug: { type: "string", description: "Repository slug" },
                        },
                        required: ["workspace", "repo_slug"],
                    },
                },
                {
                    name: "getProjectBranchingModel",
                    description: "Get the branching model for a project",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            project_key: { type: "string", description: "Project key" },
                        },
                        required: ["workspace", "project_key"],
                    },
                },
                {
                    name: "getProjectBranchingModelSettings",
                    description: "Get the branching model config for a project",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            project_key: { type: "string", description: "Project key" },
                        },
                        required: ["workspace", "project_key"],
                    },
                },
                {
                    name: "updateProjectBranchingModelSettings",
                    description: "Update the branching model config for a project",
                    inputSchema: {
                        type: "object",
                        properties: {
                            workspace: {
                                type: "string",
                                description: "Bitbucket workspace name",
                            },
                            project_key: { type: "string", description: "Project key" },
                            development: {
                                type: "object",
                                description: "Development branch settings",
                                properties: {
                                    name: { type: "string", description: "Branch name" },
                                    use_mainbranch: {
                                        type: "boolean",
                                        description: "Use main branch",
                                    },
                                },
                            },
                            production: {
                                type: "object",
                                description: "Production branch settings",
                                properties: {
                                    name: { type: "string", description: "Branch name" },
                                    use_mainbranch: {
                                        type: "boolean",
                                        description: "Use main branch",
                                    },
                                    enabled: {
                                        type: "boolean",
                                        description: "Enable production branch",
                                    },
                                },
                            },
                            branch_types: {
                                type: "array",
                                description: "Branch types configuration",
                                items: {
                                    type: "object",
                                    properties: {
                                        kind: {
                                            type: "string",
                                            description: "Branch type kind (e.g., bugfix, feature)",
                                        },
                                        prefix: { type: "string", description: "Branch prefix" },
                                        enabled: {
                                            type: "boolean",
                                            description: "Enable this branch type",
                                        },
                                    },
                                    required: ["kind"],
                                },
                            },
                        },
                        required: ["workspace", "project_key"],
                    },
                },
            ],
        }));
        // Register the call tool handler
        this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
            try {
                logger.info(`Called tool: ${request.params.name}`, {
                    arguments: request.params.arguments,
                });
                const args = request.params.arguments ?? {};
                switch (request.params.name) {
                    case "listRepositories":
                        return await this.listRepositories(args.workspace, args.limit);
                    case "getRepository":
                        return await this.getRepository(args.workspace, args.repo_slug);
                    case "getPullRequests":
                        return await this.getPullRequests(args.workspace, args.repo_slug, args.state, args.limit);
                    case "createPullRequest":
                        return await this.createPullRequest(args.workspace, args.repo_slug, args.title, args.description, args.sourceBranch, args.targetBranch, args.reviewers);
                    case "getPullRequest":
                        return await this.getPullRequest(args.workspace, args.repo_slug, args.pull_request_id);
                    case "updatePullRequest":
                        return await this.updatePullRequest(args.workspace, args.repo_slug, args.pull_request_id, args.title, args.description);
                    case "getPullRequestActivity":
                        return await this.getPullRequestActivity(args.workspace, args.repo_slug, args.pull_request_id);
                    case "approvePullRequest":
                        return await this.approvePullRequest(args.workspace, args.repo_slug, args.pull_request_id);
                    case "unapprovePullRequest":
                        return await this.unapprovePullRequest(args.workspace, args.repo_slug, args.pull_request_id);
                    case "declinePullRequest":
                        return await this.declinePullRequest(args.workspace, args.repo_slug, args.pull_request_id, args.message);
                    case "mergePullRequest":
                        return await this.mergePullRequest(args.workspace, args.repo_slug, args.pull_request_id, args.message, args.strategy);
                    case "getPullRequestComments":
                        return await this.getPullRequestComments(args.workspace, args.repo_slug, args.pull_request_id);
                    case "getPullRequestDiff":
                        return await this.getPullRequestDiff(args.workspace, args.repo_slug, args.pull_request_id);
                    case "getPullRequestCommits":
                        return await this.getPullRequestCommits(args.workspace, args.repo_slug, args.pull_request_id);
                    case "getRepositoryBranchingModel":
                        return await this.getRepositoryBranchingModel(args.workspace, args.repo_slug);
                    case "getRepositoryBranchingModelSettings":
                        return await this.getRepositoryBranchingModelSettings(args.workspace, args.repo_slug);
                    case "updateRepositoryBranchingModelSettings":
                        return await this.updateRepositoryBranchingModelSettings(args.workspace, args.repo_slug, args.development, args.production, args.branch_types);
                    case "getEffectiveRepositoryBranchingModel":
                        return await this.getEffectiveRepositoryBranchingModel(args.workspace, args.repo_slug);
                    case "getProjectBranchingModel":
                        return await this.getProjectBranchingModel(args.workspace, args.project_key);
                    case "getProjectBranchingModelSettings":
                        return await this.getProjectBranchingModelSettings(args.workspace, args.project_key);
                    case "updateProjectBranchingModelSettings":
                        return await this.updateProjectBranchingModelSettings(args.workspace, args.project_key, args.development, args.production, args.branch_types);
                    default:
                        throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
                }
            }
            catch (error) {
                logger.error("Tool execution error", { error });
                if (axios.isAxiosError(error)) {
                    throw new McpError(ErrorCode.InternalError, `Bitbucket API error: ${error.response?.data.message ?? error.message}`);
                }
                throw error;
            }
        });
    }
    async listRepositories(workspace, limit = 10) {
        try {
            // Use default workspace if not provided
            const wsName = workspace || this.config.defaultWorkspace;
            if (!wsName) {
                throw new McpError(ErrorCode.InvalidParams, "Workspace must be provided either as a parameter or through BITBUCKET_WORKSPACE environment variable");
            }
            logger.info("Listing Bitbucket repositories", {
                workspace: wsName,
                limit,
            });
            const response = await this.api.get(`/repositories/${wsName}`, {
                params: { limit },
            });
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data.values, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error listing repositories", { error, workspace });
            throw new McpError(ErrorCode.InternalError, `Failed to list repositories: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async getRepository(workspace, repo_slug) {
        try {
            logger.info("Getting Bitbucket repository info", {
                workspace,
                repo_slug,
            });
            const response = await this.api.get(`/repositories/${workspace}/${repo_slug}`);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error getting repository", { error, workspace, repo_slug });
            throw new McpError(ErrorCode.InternalError, `Failed to get repository: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async getPullRequests(workspace, repo_slug, state, limit = 10) {
        try {
            logger.info("Getting Bitbucket pull requests", {
                workspace,
                repo_slug,
                state,
                limit,
            });
            const response = await this.api.get(`/repositories/${workspace}/${repo_slug}/pullrequests`, {
                params: {
                    state: state,
                    limit,
                },
            });
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data.values, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error getting pull requests", {
                error,
                workspace,
                repo_slug,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to get pull requests: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async createPullRequest(workspace, repo_slug, title, description, sourceBranch, targetBranch, reviewers) {
        try {
            logger.info("Creating Bitbucket pull request", {
                workspace,
                repo_slug,
                title,
                sourceBranch,
                targetBranch,
            });
            // Prepare reviewers format if provided
            const reviewersArray = reviewers?.map((username) => ({
                username,
            })) || [];
            // Create the pull request
            const response = await this.api.post(`/repositories/${workspace}/${repo_slug}/pullrequests`, {
                title,
                description,
                source: {
                    branch: {
                        name: sourceBranch,
                    },
                },
                destination: {
                    branch: {
                        name: targetBranch,
                    },
                },
                reviewers: reviewersArray,
                close_source_branch: true,
            });
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error creating pull request", {
                error,
                workspace,
                repo_slug,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to create pull request: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async getPullRequest(workspace, repo_slug, pull_request_id) {
        try {
            logger.info("Getting Bitbucket pull request details", {
                workspace,
                repo_slug,
                pull_request_id,
            });
            const response = await this.api.get(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}`);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error getting pull request details", {
                error,
                workspace,
                repo_slug,
                pull_request_id,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to get pull request details: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async updatePullRequest(workspace, repo_slug, pull_request_id, title, description) {
        try {
            logger.info("Updating Bitbucket pull request", {
                workspace,
                repo_slug,
                pull_request_id,
            });
            // Only include fields that are provided
            const updateData = {};
            if (title !== undefined)
                updateData.title = title;
            if (description !== undefined)
                updateData.description = description;
            const response = await this.api.put(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}`, updateData);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error updating pull request", {
                error,
                workspace,
                repo_slug,
                pull_request_id,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to update pull request: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async getPullRequestActivity(workspace, repo_slug, pull_request_id) {
        try {
            logger.info("Getting Bitbucket pull request activity", {
                workspace,
                repo_slug,
                pull_request_id,
            });
            const response = await this.api.get(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}/activity`);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data.values, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error getting pull request activity", {
                error,
                workspace,
                repo_slug,
                pull_request_id,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to get pull request activity: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async approvePullRequest(workspace, repo_slug, pull_request_id) {
        try {
            logger.info("Approving Bitbucket pull request", {
                workspace,
                repo_slug,
                pull_request_id,
            });
            const response = await this.api.post(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}/approve`);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error approving pull request", {
                error,
                workspace,
                repo_slug,
                pull_request_id,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to approve pull request: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async unapprovePullRequest(workspace, repo_slug, pull_request_id) {
        try {
            logger.info("Unapproving Bitbucket pull request", {
                workspace,
                repo_slug,
                pull_request_id,
            });
            const response = await this.api.delete(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}/approve`);
            return {
                content: [
                    {
                        type: "text",
                        text: "Pull request approval removed successfully.",
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error unapproving pull request", {
                error,
                workspace,
                repo_slug,
                pull_request_id,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to unapprove pull request: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async declinePullRequest(workspace, repo_slug, pull_request_id, message) {
        try {
            logger.info("Declining Bitbucket pull request", {
                workspace,
                repo_slug,
                pull_request_id,
            });
            // Include message if provided
            const data = message ? { message } : {};
            const response = await this.api.post(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}/decline`, data);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error declining pull request", {
                error,
                workspace,
                repo_slug,
                pull_request_id,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to decline pull request: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async mergePullRequest(workspace, repo_slug, pull_request_id, message, strategy) {
        try {
            logger.info("Merging Bitbucket pull request", {
                workspace,
                repo_slug,
                pull_request_id,
                strategy,
            });
            // Build request data
            const data = {};
            if (message)
                data.message = message;
            if (strategy)
                data.merge_strategy = strategy;
            const response = await this.api.post(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}/merge`, data);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error merging pull request", {
                error,
                workspace,
                repo_slug,
                pull_request_id,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to merge pull request: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async getPullRequestComments(workspace, repo_slug, pull_request_id) {
        try {
            logger.info("Getting Bitbucket pull request comments", {
                workspace,
                repo_slug,
                pull_request_id,
            });
            const response = await this.api.get(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}/comments`);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data.values, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error getting pull request comments", {
                error,
                workspace,
                repo_slug,
                pull_request_id,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to get pull request comments: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async getPullRequestDiff(workspace, repo_slug, pull_request_id) {
        try {
            logger.info("Getting Bitbucket pull request diff", {
                workspace,
                repo_slug,
                pull_request_id,
            });
            const response = await this.api.get(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}/diff`, {
                headers: {
                    Accept: "text/plain",
                },
                responseType: "text",
            });
            return {
                content: [
                    {
                        type: "text",
                        text: response.data,
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error getting pull request diff", {
                error,
                workspace,
                repo_slug,
                pull_request_id,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to get pull request diff: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async getPullRequestCommits(workspace, repo_slug, pull_request_id) {
        try {
            logger.info("Getting Bitbucket pull request commits", {
                workspace,
                repo_slug,
                pull_request_id,
            });
            const response = await this.api.get(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}/commits`);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data.values, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error getting pull request commits", {
                error,
                workspace,
                repo_slug,
                pull_request_id,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to get pull request commits: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async getRepositoryBranchingModel(workspace, repo_slug) {
        try {
            logger.info("Getting repository branching model", {
                workspace,
                repo_slug,
            });
            const response = await this.api.get(`/repositories/${workspace}/${repo_slug}/branching-model`);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error getting repository branching model", {
                error,
                workspace,
                repo_slug,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to get repository branching model: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async getRepositoryBranchingModelSettings(workspace, repo_slug) {
        try {
            logger.info("Getting repository branching model settings", {
                workspace,
                repo_slug,
            });
            const response = await this.api.get(`/repositories/${workspace}/${repo_slug}/branching-model/settings`);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error getting repository branching model settings", {
                error,
                workspace,
                repo_slug,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to get repository branching model settings: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async updateRepositoryBranchingModelSettings(workspace, repo_slug, development, production, branch_types) {
        try {
            logger.info("Updating repository branching model settings", {
                workspace,
                repo_slug,
                development,
                production,
                branch_types,
            });
            // Build request data with only the fields that are provided
            const updateData = {};
            if (development)
                updateData.development = development;
            if (production)
                updateData.production = production;
            if (branch_types)
                updateData.branch_types = branch_types;
            const response = await this.api.put(`/repositories/${workspace}/${repo_slug}/branching-model/settings`, updateData);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error updating repository branching model settings", {
                error,
                workspace,
                repo_slug,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to update repository branching model settings: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async getEffectiveRepositoryBranchingModel(workspace, repo_slug) {
        try {
            logger.info("Getting effective repository branching model", {
                workspace,
                repo_slug,
            });
            const response = await this.api.get(`/repositories/${workspace}/${repo_slug}/effective-branching-model`);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error getting effective repository branching model", {
                error,
                workspace,
                repo_slug,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to get effective repository branching model: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async getProjectBranchingModel(workspace, project_key) {
        try {
            logger.info("Getting project branching model", {
                workspace,
                project_key,
            });
            const response = await this.api.get(`/workspaces/${workspace}/projects/${project_key}/branching-model`);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error getting project branching model", {
                error,
                workspace,
                project_key,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to get project branching model: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async getProjectBranchingModelSettings(workspace, project_key) {
        try {
            logger.info("Getting project branching model settings", {
                workspace,
                project_key,
            });
            const response = await this.api.get(`/workspaces/${workspace}/projects/${project_key}/branching-model/settings`);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error getting project branching model settings", {
                error,
                workspace,
                project_key,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to get project branching model settings: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async updateProjectBranchingModelSettings(workspace, project_key, development, production, branch_types) {
        try {
            logger.info("Updating project branching model settings", {
                workspace,
                project_key,
                development,
                production,
                branch_types,
            });
            // Build request data with only the fields that are provided
            const updateData = {};
            if (development)
                updateData.development = development;
            if (production)
                updateData.production = production;
            if (branch_types)
                updateData.branch_types = branch_types;
            const response = await this.api.put(`/workspaces/${workspace}/projects/${project_key}/branching-model/settings`, updateData);
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response.data, null, 2),
                    },
                ],
            };
        }
        catch (error) {
            logger.error("Error updating project branching model settings", {
                error,
                workspace,
                project_key,
            });
            throw new McpError(ErrorCode.InternalError, `Failed to update project branching model settings: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async run() {
        const transport = new StdioServerTransport();
        await this.server.connect(transport);
        logger.info("Bitbucket MCP server running on stdio");
    }
}
// Create and start the server
const server = new BitbucketServer();
server.run().catch((error) => {
    logger.error("Server error", error);
    process.exit(1);
});
//# sourceMappingURL=index.js.map