You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

bitbucket-mcp

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bitbucket-mcp - npm Package Compare versions

Comparing version

to
2.0.0

dist/services/bitbucket.d.ts

637

dist/index.js
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ErrorCode, McpError, } from "@modelcontextprotocol/sdk/types.js";
import axios from "axios";
import winston from "winston";
// Constants
const LOG_FILE = "bitbucket.log";
const API_VERSION = "1.1.0";
const API_PATH = "/rest/api/1.0";
// Enums
var MergeStrategy;
(function (MergeStrategy) {
MergeStrategy["MERGE_COMMIT"] = "merge-commit";
MergeStrategy["SQUASH"] = "squash";
MergeStrategy["FAST_FORWARD"] = "fast-forward";
})(MergeStrategy || (MergeStrategy = {}));
var ReviewAction;
(function (ReviewAction) {
ReviewAction["APPROVED"] = "APPROVED";
ReviewAction["REVIEWED"] = "REVIEWED";
})(ReviewAction || (ReviewAction = {}));
// Configuration for logger
const logger = winston.createLogger({
level: "info",
format: winston.format.json(),
transports: [new winston.transports.File({ filename: LOG_FILE })],
});
class BitbucketServer {
import { z } from "zod";
import { randomUUID } from "crypto";
import { setupLogger } from "./utils/logger.js";
import { getBitbucketAPI } from "./services/bitbucket.js";
// Setup logger
const logger = setupLogger();
// Bitbucket MCP Server class
class BitbucketMcpServer {
server;
api;
config;
api = null;
constructor() {
this.server = new Server({
name: "bitbucket-server-mcp-server",
version: API_VERSION,
}, {
capabilities: {
tools: {
create_pull_request: {
description: "Create a new pull request",
inputSchema: {
type: "object",
properties: {
project: {
type: "string",
description: "Bitbucket project key",
},
repository: {
type: "string",
description: "Repository slug",
},
title: { type: "string", description: "PR title" },
description: {
type: "string",
description: "PR 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: [
"repository",
"title",
"sourceBranch",
"targetBranch",
],
// Initialize the MCP server
this.server = new McpServer({
name: "bitbucket-mcp",
version: "1.0.0",
});
// Add server error handling
logger.on("error", (error) => {
logger.error("Server error", { error });
});
this.setupTools();
}
setupTools() {
// Register bitbucket repository tools
this.server.tool("listRepositories", {
workspace: z.string().optional().describe("Bitbucket workspace name"),
limit: z
.number()
.optional()
.describe("Maximum number of repositories to return"),
}, async ({ workspace, limit }, extra) => {
logger.info("Listing Bitbucket repositories", { workspace, limit });
try {
const bitbucketAPI = await getBitbucketAPI();
const repositories = await bitbucketAPI.listRepositories(workspace, limit);
return {
content: [
{
type: "text",
text: `Found ${repositories.length} repositories${workspace ? ` in workspace ${workspace}` : ""}`,
},
},
get_pull_request: {
description: "Get pull request details",
inputSchema: {
type: "object",
properties: {
project: {
type: "string",
description: "Bitbucket project key",
},
repository: {
type: "string",
description: "Repository slug",
},
prId: { type: "number", description: "Pull request ID" },
},
required: ["repository", "prId"],
{
type: "text",
text: JSON.stringify(repositories, null, 2),
},
},
merge_pull_request: {
description: "Merge a pull request",
inputSchema: {
type: "object",
properties: {
project: {
type: "string",
description: "Bitbucket project key",
},
repository: {
type: "string",
description: "Repository slug",
},
prId: { type: "number", description: "Pull request ID" },
message: {
type: "string",
description: "Merge commit message",
},
strategy: {
type: "string",
enum: Object.values(MergeStrategy),
description: "Merge strategy to use",
},
},
required: ["repository", "prId"],
],
};
}
catch (error) {
logger.error("Error listing repositories", { error });
return {
content: [
{
type: "text",
text: `Error listing repositories: ${error instanceof Error ? error.message : String(error)}`,
},
},
decline_pull_request: {
description: "Decline a pull request",
inputSchema: {
type: "object",
properties: {
project: {
type: "string",
description: "Bitbucket project key",
},
repository: {
type: "string",
description: "Repository slug",
},
prId: { type: "number", description: "Pull request ID" },
message: {
type: "string",
description: "Reason for declining",
},
},
required: ["repository", "prId"],
],
};
}
});
this.server.tool("getRepository", {
workspace: z.string().describe("Bitbucket workspace name"),
repo_slug: z.string().describe("Repository slug"),
}, async ({ workspace, repo_slug }, extra) => {
logger.info("Getting Bitbucket repository info", {
workspace,
repo_slug,
});
try {
const bitbucketAPI = await getBitbucketAPI();
const repository = await bitbucketAPI.getRepository(workspace, repo_slug);
return {
content: [
{
type: "text",
text: `Repository: ${repository.name}`,
},
},
add_comment: {
description: "Add a comment to a pull request",
inputSchema: {
type: "object",
properties: {
project: {
type: "string",
description: "Bitbucket project key",
},
repository: {
type: "string",
description: "Repository slug",
},
prId: { type: "number", description: "Pull request ID" },
text: { type: "string", description: "Comment text" },
parentId: {
type: "number",
description: "Parent comment ID for replies",
},
},
required: ["repository", "prId", "text"],
{
type: "text",
text: JSON.stringify(repository, null, 2),
},
},
get_diff: {
description: "Get pull request diff",
inputSchema: {
type: "object",
properties: {
project: {
type: "string",
description: "Bitbucket project key",
},
repository: {
type: "string",
description: "Repository slug",
},
prId: { type: "number", description: "Pull request ID" },
contextLines: {
type: "number",
description: "Number of context lines",
},
},
required: ["repository", "prId"],
],
};
}
catch (error) {
logger.error("Error getting repository", {
error,
workspace,
repo_slug,
});
return {
content: [
{
type: "text",
text: `Error getting repository: ${error instanceof Error ? error.message : String(error)}`,
},
},
get_reviews: {
description: "Get pull request reviews",
inputSchema: {
type: "object",
properties: {
project: {
type: "string",
description: "Bitbucket project key",
},
repository: {
type: "string",
description: "Repository slug",
},
prId: { type: "number", description: "Pull request ID" },
},
required: ["repository", "prId"],
},
},
},
},
],
};
}
});
// Configuration from environment variables
this.config = this.loadConfig();
// Configuration of Axios instance
this.api = axios.create({
baseURL: `${this.config.baseUrl}${API_PATH}`,
headers: this.config.token
? { Authorization: `Bearer ${this.config.token}` }
: {},
auth: this.config.username && this.config.password
? { username: this.config.username, password: this.config.password }
: undefined,
});
this.setupToolHandlers();
this.server.onerror = (error) => {
logger.error("[MCP Error]", error);
};
}
/**
* Loads configuration from environment variables
* @returns BitbucketConfig configuration object
* @throws Error if required environment variables are not set
*/
loadConfig() {
const config = {
baseUrl: process.env.BITBUCKET_URL ?? "",
token: process.env.BITBUCKET_TOKEN,
username: process.env.BITBUCKET_USERNAME,
password: process.env.BITBUCKET_PASSWORD,
defaultProject: process.env.BITBUCKET_DEFAULT_PROJECT,
};
if (!config.baseUrl) {
throw new Error("BITBUCKET_URL is required");
}
if (!config.token && !(config.username && config.password)) {
throw new Error("Either BITBUCKET_TOKEN or BITBUCKET_USERNAME/PASSWORD is required");
}
return config;
}
/**
* Type guard for PullRequestInput
*/
isPullRequestInput(args) {
const input = args;
return (typeof args === "object" &&
args !== null &&
typeof input.project === "string" &&
typeof input.repository === "string" &&
typeof input.title === "string" &&
typeof input.sourceBranch === "string" &&
typeof input.targetBranch === "string" &&
(input.description === undefined ||
typeof input.description === "string") &&
(input.reviewers === undefined || Array.isArray(input.reviewers)));
}
/**
* Sets up tool handlers for the MCP server
*/
setupToolHandlers() {
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
this.server.tool("getPullRequests", {
workspace: z.string().describe("Bitbucket workspace name"),
repo_slug: z.string().describe("Repository slug"),
state: z
.enum(["OPEN", "MERGED", "DECLINED", "SUPERSEDED"])
.optional()
.describe("Pull request state"),
limit: z
.number()
.optional()
.describe("Maximum number of pull requests to return"),
}, async ({ workspace, repo_slug, state, limit }, extra) => {
logger.info("Getting Bitbucket pull requests", {
workspace,
repo_slug,
state,
limit,
});
try {
logger.info(`Called tool: ${request.params.name}`, {
arguments: request.params.arguments,
});
const args = request.params.arguments ?? {};
const pullRequestParams = this.extractPullRequestParams(args);
switch (request.params.name) {
case "create_pull_request":
if (!this.isPullRequestInput(args)) {
throw new McpError(ErrorCode.InvalidParams, "Invalid pull request input parameters");
}
return await this.createPullRequest(args);
case "get_pull_request":
return await this.getPullRequest(pullRequestParams);
case "merge_pull_request":
return await this.mergePullRequest(pullRequestParams, {
message: args.message,
strategy: args.strategy,
});
case "decline_pull_request":
return await this.declinePullRequest(pullRequestParams, args.message);
case "add_comment":
return await this.addComment(pullRequestParams, {
text: args.text,
parentId: args.parentId,
});
case "get_diff":
return await this.getDiff(pullRequestParams, args.contextLines);
case "get_reviews":
return await this.getReviews(pullRequestParams);
default:
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
}
const bitbucketAPI = await getBitbucketAPI();
const pullRequests = await bitbucketAPI.getPullRequests(workspace, repo_slug, state, limit);
return {
content: [
{
type: "text",
text: `Found ${pullRequests.length} pull requests${state ? ` with state ${state}` : ""}`,
},
{
type: "text",
text: JSON.stringify(pullRequests, null, 2),
},
],
};
}
catch (error) {
logger.error("Tool execution error", { error });
return this.handleError(error);
logger.error("Error getting pull requests", {
error,
workspace,
repo_slug,
});
return {
content: [
{
type: "text",
text: `Error getting pull requests: ${error instanceof Error ? error.message : String(error)}`,
},
],
};
}
});
}
/**
* Extracts pull request parameters from the arguments
*/
extractPullRequestParams(args) {
const pullRequestParams = {
project: args.project ?? this.config.defaultProject ?? "",
repository: args.repository,
prId: args.prId,
};
if (!pullRequestParams.project) {
throw new McpError(ErrorCode.InvalidParams, "Project must be provided either as a parameter or through BITBUCKET_DEFAULT_PROJECT environment variable");
}
return pullRequestParams;
// Method to get the McpServer instance
getServer() {
return this.server;
}
/**
* Handles errors and converts them to McpError format
*/
handleError(error) {
if (error instanceof McpError) {
throw error;
}
// Create Bitbucket MCP Server instance
const bitbucketMcpServer = new BitbucketMcpServer();
const server = bitbucketMcpServer.getServer();
// Express server setup
const app = express();
app.use(express.json());
// Initialize standalone mode if requested
if (process.env.STANDALONE === "true") {
logger.info("Running in standalone mode with stdio transport");
const stdioTransport = new StdioServerTransport();
server.connect(stdioTransport).catch((error) => {
logger.error("Error connecting stdio transport", { error });
process.exit(1);
});
}
else {
// HTTP server mode
// MCP endpoint
app.all("/mcp", (req, res) => {
logger.info("Received MCP request", {
method: req.method,
path: req.path,
accept: req.headers.accept,
contentType: req.headers["content-type"],
});
try {
// Create transport with a session ID generator
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID(),
});
// Connect the transport to the server (must be done before handling requests)
server.connect(transport);
// Handle the request (this passes it to the connected server)
transport.handleRequest(req, res, req.body);
logger.info("Transport connected to server");
}
if (axios.isAxiosError(error)) {
const axiosError = error;
const statusCode = axiosError.response?.status ?? 500;
const errorMessage = axiosError.response?.data?.message ?? axiosError.message;
throw new McpError(ErrorCode.InternalError, `Bitbucket API error (${statusCode}): ${errorMessage}`);
catch (error) {
logger.error("Error handling MCP request", { error });
// Only send response if headers haven't been sent yet
if (!res.headersSent) {
res.status(500).json({
error: "Internal server error",
message: error instanceof Error ? error.message : String(error),
});
}
}
throw new McpError(ErrorCode.InternalError, `Unknown error: ${error instanceof Error ? error.message : String(error)}`);
}
/**
* Creates a new pull request
*/
async createPullRequest(input) {
const payload = {
title: input.title,
description: input.description,
fromRef: {
id: `refs/heads/${input.sourceBranch}`,
repository: {
slug: input.repository,
project: { key: input.project },
},
},
toRef: {
id: `refs/heads/${input.targetBranch}`,
repository: {
slug: input.repository,
project: { key: input.project },
},
},
reviewers: input.reviewers?.map((username) => ({
user: { name: username },
})),
};
const response = await this.api.post(`/projects/${input.project}/repos/${input.repository}/pull-requests`, payload);
return {
content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }],
};
}
/**
* Gets pull request details
*/
async getPullRequest(params) {
const { project, repository, prId } = params;
const response = await this.api.get(`/projects/${project}/repos/${repository}/pull-requests/${prId}`);
return {
content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }],
};
}
/**
* Merges a pull request
*/
async mergePullRequest(params, options = {}) {
const { project, repository, prId } = params;
const { message, strategy = MergeStrategy.MERGE_COMMIT } = options;
const response = await this.api.post(`/projects/${project}/repos/${repository}/pull-requests/${prId}/merge`, {
version: -1,
message,
strategy,
});
return {
content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }],
};
}
/**
* Declines a pull request
*/
async declinePullRequest(params, message) {
const { project, repository, prId } = params;
const response = await this.api.post(`/projects/${project}/repos/${repository}/pull-requests/${prId}/decline`, {
version: -1,
message,
});
return {
content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }],
};
}
/**
* Adds a comment to a pull request
*/
async addComment(params, options) {
const { project, repository, prId } = params;
const { text, parentId } = options;
const response = await this.api.post(`/projects/${project}/repos/${repository}/pull-requests/${prId}/comments`, {
text,
parent: parentId ? { id: parentId } : undefined,
});
return {
content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }],
};
}
/**
* Gets the diff for a pull request
*/
async getDiff(params, contextLines = 10) {
const { project, repository, prId } = params;
const response = await this.api.get(`/projects/${project}/repos/${repository}/pull-requests/${prId}/diff`, {
params: { contextLines },
headers: { Accept: "text/plain" },
});
return {
content: [{ type: "text", text: response.data }],
};
}
/**
* Gets the reviews for a pull request
*/
async getReviews(params) {
const { project, repository, prId } = params;
const response = await this.api.get(`/projects/${project}/repos/${repository}/pull-requests/${prId}/activities`);
const reviews = response.data.values.filter((activity) => activity.action === ReviewAction.APPROVED ||
activity.action === ReviewAction.REVIEWED);
return {
content: [{ type: "text", text: JSON.stringify(reviews, null, 2) }],
};
}
/**
* Starts the server
*/
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
logger.info("Bitbucket MCP server running on stdio");
}
});
// Health endpoint
app.get("/health", (req, res) => {
res.status(200).json({ status: "ok" });
});
// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
logger.info(`Bitbucket MCP server listening on port ${PORT}`);
});
}
const server = new BitbucketServer();
server.run().catch((error) => {
logger.error("Server error", error);
process.exit(1);
});
//# sourceMappingURL=index.js.map
{
"name": "bitbucket-mcp",
"version": "1.2.0",
"version": "2.0.0",
"description": "Model Context Protocol (MCP) server for Bitbucket Cloud and Server API integration",

@@ -19,4 +19,10 @@ "type": "module",

"standalone": "STANDALONE=true node dist/index.js",
"dev": "tsc -w",
"dev": "tsx watch src/index.ts",
"prepublishOnly": "npm run build",
"version": "git add -A src",
"postversion": "git push && git push --tags",
"publish:patch": "npm version patch && npm publish",
"publish:minor": "npm version minor && npm publish",
"publish:major": "npm version major && npm publish",
"release": "npm run publish:patch",
"test": "jest",

@@ -33,8 +39,3 @@ "lint": "eslint src/**/*.ts",

"ai",
"llm",
"claude",
"anthropic",
"gpt",
"openai",
"mistral"
"llm"
],

@@ -52,14 +53,18 @@ "author": "Bitbucket MCP Team",

"dependencies": {
"@modelcontextprotocol/sdk": "^1.1.1",
"@modelcontextprotocol/sdk": "^1.10.2",
"axios": "^1.6.5",
"winston": "^3.11.0"
"express": "^4.19.2",
"winston": "^3.11.0",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/jest": "^29.5.11",
"@types/node": "^22.10.7",
"@typescript-eslint/eslint-plugin": "^6.19.0",
"@typescript-eslint/parser": "^6.19.0",
"@types/node": "^20.11.24",
"@typescript-eslint/eslint-plugin": "^7.0.2",
"@typescript-eslint/parser": "^7.0.2",
"eslint": "^8.56.0",
"jest": "^29.7.0",
"ts-jest": "^29.1.1",
"tsx": "^4.7.1",
"typescript": "^5.3.3"

@@ -66,0 +71,0 @@ },

# Bitbucket MCP
Model Context Protocol (MCP) server for Bitbucket Cloud and Server API integration. This package enables AI assistants to interact with Bitbucket repositories, pull requests, and other features through the MCP protocol.
A Model Context Protocol (MCP) server for integrating with Bitbucket Cloud and Server APIs. This MCP server allows AI assistants to interact with Bitbucket repositories, pull requests, and other resources.
## Features
## Overview
- **Bitbucket Cloud API Integration**: Access the full Bitbucket Cloud REST API
- **Bitbucket Server Support**: Compatible with Bitbucket Server instances
- **Repository Management**: List, view, and manage repositories
- **Pull Request Operations**: Create, view, merge, and comment on PRs
- **Permission Management**: Query and manage repository permissions
- **Webhook Management**: List and manage webhooks
This server implements the [Model Context Protocol](https://modelcontextprotocol.io/) standard to provide AI assistants with access to Bitbucket data and operations. It includes tools for:
## Installation
- Listing and retrieving repositories
- Managing pull requests
- Working with repository content
```bash
# Install globally
npm install -g bitbucket-mcp
## Getting Started
# Or run directly with npx
npx bitbucket-mcp
```
### Prerequisites
## Quick Start
- Node.js 18 or higher
- A Bitbucket Cloud account or Bitbucket Server instance
- Optional: Bitbucket API token for authenticated requests
1. Set up your environment variables:
### Installation
```bash
# Required for all operations
export BITBUCKET_URL="https://your-bitbucket-server-url" # For Server API
export BITBUCKET_CLOUD_URL="https://api.bitbucket.org/2.0" # For Cloud API
# Clone the repository
git clone https://github.com/yourusername/bitbucket-mcp.git
cd bitbucket-mcp
# Authentication (choose one method)
export BITBUCKET_TOKEN="your_access_token"
# OR
export BITBUCKET_USERNAME="your_username"
export BITBUCKET_APP_PASSWORD="your_app_password"
# Install dependencies
npm install
# Optional
export BITBUCKET_DEFAULT_PROJECT="your_default_project" # For Server API
# Build the project
npm run build
```
2. Run the MCP server:
### Configuration
Configure the server using environment variables:
```bash
npx bitbucket-mcp
# Bitbucket API token (optional, but recommended)
export BITBUCKET_TOKEN=your_token_here
# For custom Bitbucket Server installations
export BITBUCKET_API_URL=https://your-bitbucket-server.com/api
```
## Supported API Operations
### Running the Server
### Bitbucket Cloud Repository API
```bash
# Start the server
npm start
- `list_public_repositories` - List all public repositories
- `list_workspace_repositories` - List repositories in a workspace
- `get_repository` - Get a specific repository
- `list_repository_forks` - List forks of a repository
- `list_repository_webhooks` - List webhooks for a repository
- `get_repository_webhook` - Get a specific webhook
- `get_repository_settings_inheritance` - Get repository settings inheritance
- `list_repository_group_permissions` - List group permissions
- `get_repository_group_permission` - Get specific group permission
- `list_repository_user_permissions` - List user permissions
- `get_repository_user_permission` - Get specific user permission
- `list_repository_watchers` - List repository watchers
- `list_user_repository_permissions` - List permissions for the current user
# Or run in development mode
npm run dev
### Bitbucket Server Pull Request API
# Use standalone mode for direct stdio communication
npm run standalone
```
- `create_pull_request` - Create a new pull request
- `get_pull_request` - Get pull request details
- `merge_pull_request` - Merge a pull request
- `decline_pull_request` - Decline a pull request
- `add_comment` - Add a comment to a pull request
- `get_diff` - Get pull request diff
- `get_reviews` - Get pull request reviews
## Available Tools
## Integration with AI Assistants
This MCP server provides tools for interacting with Bitbucket repositories and pull requests. For a comprehensive list of all available tools with detailed documentation, please see [TOOLS.md](TOOLS.md).
This MCP server is designed to be used with AI assistants that support the Model Context Protocol:
Some of the available tools include:
### Using with Claude
- **listRepositories**: List repositories in a workspace
- **getRepository**: Get details for a specific repository
- **getPullRequests**: Get pull requests for a repository
1. Install the Claude desktop app
2. Add this MCP server to Claude:
## Integration with MCP Clients
```json
{
"mcpServers": {
"bitbucket": {
"command": "npx",
"args": ["-y", "bitbucket-mcp"],
"env": {
"BITBUCKET_URL": "https://your-bitbucket-server.com",
"BITBUCKET_CLOUD_URL": "https://api.bitbucket.org/2.0",
"BITBUCKET_TOKEN": "your-access-token"
}
}
}
}
```
This server can be integrated with any MCP client by connecting to the server endpoint:
### Using with other MCP clients
- HTTP endpoint: `http://localhost:3000/mcp`
- When running in standalone mode, communication happens over stdio
Any client that supports the MCP protocol can communicate with this server over standard input/output.
## Development
## API Examples
### Project Structure
### List repositories in a workspace
```javascript
// Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "mcp.call_tool",
"params": {
"name": "list_workspace_repositories",
"arguments": {
"workspace": "your_workspace"
}
}
}
// Response
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{ \"values\": [...], \"pagelen\": 10, ... }"
}
]
}
}
```
### Create a pull request
```javascript
// Request
{
"jsonrpc": "2.0",
"id": 2,
"method": "mcp.call_tool",
"params": {
"name": "create_pull_request",
"arguments": {
"project": "PROJECT",
"repository": "repo-name",
"title": "Feature: Add new functionality",
"description": "This PR adds the new feature X",
"sourceBranch": "feature/new-feature",
"targetBranch": "main"
}
}
}
bitbucket-mcp/
├── src/
│ ├── api/ # API-related code
│ ├── services/ # Service implementations
│ ├── types/ # TypeScript type definitions
│ ├── utils/ # Utility functions
│ └── index.ts # Entry point
├── package.json
└── tsconfig.json
```
## Development
### Adding New Tools
```bash
# Clone the repository
git clone https://github.com/yourusername/bitbucket-mcp.git
cd bitbucket-mcp
To add a new tool, modify the `src/index.ts` file and add your tool definition:
# Install dependencies
npm install
# Build
npm run build
# Run locally
npm start
```typescript
const newTool = server.tool(
"newToolName",
{
param1: z.string(),
param2: z.number().optional(),
},
async ({ param1, param2 }) => {
// Implementation goes here
return {
content: [{ type: "text", text: "Result" }],
};
}
);
```
## Logging
The server logs all operations to `bitbucket.log` using Winston for debugging and monitoring purposes.
## License
MIT
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet