We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/jlromano/bitbucket-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
Tool,
} from '@modelcontextprotocol/sdk/types.js';
import { BitbucketClient, BitbucketConfig } from './BitbucketClient.js';
import dotenv from 'dotenv';
dotenv.config();
const BITBUCKET_USERNAME = process.env.BITBUCKET_USERNAME;
const BITBUCKET_APP_PASSWORD = process.env.BITBUCKET_APP_PASSWORD;
const BITBUCKET_WORKSPACE = process.env.BITBUCKET_WORKSPACE;
if (!BITBUCKET_USERNAME || !BITBUCKET_APP_PASSWORD) {
console.error('Missing required environment variables: BITBUCKET_USERNAME and BITBUCKET_APP_PASSWORD');
process.exit(1);
}
const config: BitbucketConfig = {
username: BITBUCKET_USERNAME,
appPassword: BITBUCKET_APP_PASSWORD,
workspace: BITBUCKET_WORKSPACE,
};
const client = new BitbucketClient(config);
const server = new Server(
{
name: 'bitbucket-mcp',
version: '0.1.0',
},
{
capabilities: {
tools: {},
},
}
);
const tools: Tool[] = [
{
name: 'list_workspaces',
description: 'List all available Bitbucket workspaces',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'list_repositories',
description: 'List all repositories in a workspace',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug (optional, uses default if not provided)',
},
},
},
},
{
name: 'get_repository',
description: 'Get details of a specific repository',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug',
},
repo_slug: {
type: 'string',
description: 'The repository slug',
},
},
required: ['workspace', 'repo_slug'],
},
},
{
name: 'list_branches',
description: 'List all branches in a repository',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug',
},
repo_slug: {
type: 'string',
description: 'The repository slug',
},
},
required: ['workspace', 'repo_slug'],
},
},
{
name: 'get_branch',
description: 'Get details of a specific branch',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug',
},
repo_slug: {
type: 'string',
description: 'The repository slug',
},
branch_name: {
type: 'string',
description: 'The branch name',
},
},
required: ['workspace', 'repo_slug', 'branch_name'],
},
},
{
name: 'list_pull_requests',
description: 'List pull requests in a repository',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug',
},
repo_slug: {
type: 'string',
description: 'The repository slug',
},
state: {
type: 'string',
description: 'Filter by PR state (OPEN, MERGED, DECLINED)',
enum: ['OPEN', 'MERGED', 'DECLINED'],
},
},
required: ['workspace', 'repo_slug'],
},
},
{
name: 'get_pull_request',
description: 'Get details of a specific pull request',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug',
},
repo_slug: {
type: 'string',
description: 'The repository slug',
},
pr_id: {
type: 'number',
description: 'The pull request ID',
},
},
required: ['workspace', 'repo_slug', 'pr_id'],
},
},
{
name: 'create_pull_request',
description: 'Create a new pull request',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug',
},
repo_slug: {
type: 'string',
description: 'The repository slug',
},
title: {
type: 'string',
description: 'The pull request title',
},
source_branch: {
type: 'string',
description: 'The source branch name',
},
destination_branch: {
type: 'string',
description: 'The destination branch name',
},
description: {
type: 'string',
description: 'The pull request description (optional)',
},
},
required: ['workspace', 'repo_slug', 'title', 'source_branch', 'destination_branch'],
},
},
{
name: 'approve_pull_request',
description: 'Approve a pull request',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug',
},
repo_slug: {
type: 'string',
description: 'The repository slug',
},
pr_id: {
type: 'number',
description: 'The pull request ID',
},
},
required: ['workspace', 'repo_slug', 'pr_id'],
},
},
{
name: 'merge_pull_request',
description: 'Merge a pull request',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug',
},
repo_slug: {
type: 'string',
description: 'The repository slug',
},
pr_id: {
type: 'number',
description: 'The pull request ID',
},
},
required: ['workspace', 'repo_slug', 'pr_id'],
},
},
{
name: 'add_pull_request_comment',
description: 'Add a comment to a pull request',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug',
},
repo_slug: {
type: 'string',
description: 'The repository slug',
},
pr_id: {
type: 'number',
description: 'The pull request ID',
},
content: {
type: 'string',
description: 'The comment content',
},
},
required: ['workspace', 'repo_slug', 'pr_id', 'content'],
},
},
{
name: 'list_commits',
description: 'List commits in a repository',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug',
},
repo_slug: {
type: 'string',
description: 'The repository slug',
},
branch: {
type: 'string',
description: 'Filter commits by branch (optional)',
},
},
required: ['workspace', 'repo_slug'],
},
},
{
name: 'get_commit',
description: 'Get details of a specific commit',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug',
},
repo_slug: {
type: 'string',
description: 'The repository slug',
},
commit_hash: {
type: 'string',
description: 'The commit hash',
},
},
required: ['workspace', 'repo_slug', 'commit_hash'],
},
},
{
name: 'get_file_content',
description: 'Get the content of a file from a repository',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug',
},
repo_slug: {
type: 'string',
description: 'The repository slug',
},
path: {
type: 'string',
description: 'The file path',
},
ref: {
type: 'string',
description: 'The reference (branch, tag, or commit hash) - defaults to HEAD',
},
},
required: ['workspace', 'repo_slug', 'path'],
},
},
{
name: 'search_code',
description: 'Search for code in a workspace',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug',
},
query: {
type: 'string',
description: 'The search query',
},
},
required: ['workspace', 'query'],
},
},
{
name: 'compare_branches',
description: 'Compare two branches',
inputSchema: {
type: 'object',
properties: {
workspace: {
type: 'string',
description: 'The workspace slug',
},
repo_slug: {
type: 'string',
description: 'The repository slug',
},
source_branch: {
type: 'string',
description: 'The source branch',
},
destination_branch: {
type: 'string',
description: 'The destination branch',
},
},
required: ['workspace', 'repo_slug', 'source_branch', 'destination_branch'],
},
},
];
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools,
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'list_workspaces': {
const workspaces = await client.listWorkspaces();
return {
content: [
{
type: 'text',
text: JSON.stringify(workspaces, null, 2),
},
],
};
}
case 'list_repositories': {
const workspace = args?.workspace as string | undefined;
const repositories = await client.listRepositories(workspace);
return {
content: [
{
type: 'text',
text: JSON.stringify(repositories, null, 2),
},
],
};
}
case 'get_repository': {
const { workspace, repo_slug } = args as { workspace: string; repo_slug: string };
const repository = await client.getRepository(workspace, repo_slug);
return {
content: [
{
type: 'text',
text: JSON.stringify(repository, null, 2),
},
],
};
}
case 'list_branches': {
const { workspace, repo_slug } = args as { workspace: string; repo_slug: string };
const branches = await client.listBranches(workspace, repo_slug);
return {
content: [
{
type: 'text',
text: JSON.stringify(branches, null, 2),
},
],
};
}
case 'get_branch': {
const { workspace, repo_slug, branch_name } = args as {
workspace: string;
repo_slug: string;
branch_name: string;
};
const branch = await client.getBranch(workspace, repo_slug, branch_name);
return {
content: [
{
type: 'text',
text: JSON.stringify(branch, null, 2),
},
],
};
}
case 'list_pull_requests': {
const { workspace, repo_slug, state } = args as {
workspace: string;
repo_slug: string;
state?: string;
};
const pullRequests = await client.listPullRequests(workspace, repo_slug, state);
return {
content: [
{
type: 'text',
text: JSON.stringify(pullRequests, null, 2),
},
],
};
}
case 'get_pull_request': {
const { workspace, repo_slug, pr_id } = args as {
workspace: string;
repo_slug: string;
pr_id: number;
};
const pullRequest = await client.getPullRequest(workspace, repo_slug, pr_id);
return {
content: [
{
type: 'text',
text: JSON.stringify(pullRequest, null, 2),
},
],
};
}
case 'create_pull_request': {
const { workspace, repo_slug, title, source_branch, destination_branch, description } = args as {
workspace: string;
repo_slug: string;
title: string;
source_branch: string;
destination_branch: string;
description?: string;
};
const pullRequest = await client.createPullRequest(
workspace,
repo_slug,
title,
source_branch,
destination_branch,
description
);
return {
content: [
{
type: 'text',
text: JSON.stringify(pullRequest, null, 2),
},
],
};
}
case 'approve_pull_request': {
const { workspace, repo_slug, pr_id } = args as {
workspace: string;
repo_slug: string;
pr_id: number;
};
await client.approvePullRequest(workspace, repo_slug, pr_id);
return {
content: [
{
type: 'text',
text: `Pull request #${pr_id} approved successfully`,
},
],
};
}
case 'merge_pull_request': {
const { workspace, repo_slug, pr_id } = args as {
workspace: string;
repo_slug: string;
pr_id: number;
};
await client.mergePullRequest(workspace, repo_slug, pr_id);
return {
content: [
{
type: 'text',
text: `Pull request #${pr_id} merged successfully`,
},
],
};
}
case 'add_pull_request_comment': {
const { workspace, repo_slug, pr_id, content } = args as {
workspace: string;
repo_slug: string;
pr_id: number;
content: string;
};
await client.addPullRequestComment(workspace, repo_slug, pr_id, content);
return {
content: [
{
type: 'text',
text: `Comment added to pull request #${pr_id}`,
},
],
};
}
case 'list_commits': {
const { workspace, repo_slug, branch } = args as {
workspace: string;
repo_slug: string;
branch?: string;
};
const commits = await client.listCommits(workspace, repo_slug, branch);
return {
content: [
{
type: 'text',
text: JSON.stringify(commits, null, 2),
},
],
};
}
case 'get_commit': {
const { workspace, repo_slug, commit_hash } = args as {
workspace: string;
repo_slug: string;
commit_hash: string;
};
const commit = await client.getCommit(workspace, repo_slug, commit_hash);
return {
content: [
{
type: 'text',
text: JSON.stringify(commit, null, 2),
},
],
};
}
case 'get_file_content': {
const { workspace, repo_slug, path, ref } = args as {
workspace: string;
repo_slug: string;
path: string;
ref?: string;
};
const content = await client.getFileContent(workspace, repo_slug, path, ref);
return {
content: [
{
type: 'text',
text: content,
},
],
};
}
case 'search_code': {
const { workspace, query } = args as {
workspace: string;
query: string;
};
const results = await client.searchCode(workspace, query);
return {
content: [
{
type: 'text',
text: JSON.stringify(results, null, 2),
},
],
};
}
case 'compare_branches': {
const { workspace, repo_slug, source_branch, destination_branch } = args as {
workspace: string;
repo_slug: string;
source_branch: string;
destination_branch: string;
};
const diff = await client.compareBranches(workspace, repo_slug, source_branch, destination_branch);
return {
content: [
{
type: 'text',
text: JSON.stringify(diff, null, 2),
},
],
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error: any) {
return {
content: [
{
type: 'text',
text: `Error: ${error.message}`,
},
],
isError: true,
};
}
});
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('Bitbucket MCP server running...');
}
main().catch((error) => {
console.error('Fatal error:', error);
process.exit(1);
});