bitbucket-standalone-mcp
# bitbucket-standalone-mcp
A standalone [Model Context Protocol](https://modelcontextprotocol.io) (MCP)
server that exposes the REST v1.0 API of a **Bitbucket Server / Data Center**
(standalone) instance as MCP tools. Built for the local VCS at
`http://vcs.tiddev.com` (Bitbucket Server 7.12.1).
- **Runtime**: Node.js 18+ (ESM, TypeScript)
- **Transport**: stdio MCP
- **Auth**: HTTP Basic (`BITBUCKET_USERNAME` / `BITBUCKET_PASSWORD`)
- **API base**: `/rest/api/1.0` (Bitbucket Server 7.x)
## Why standalone
Bitbucket Server / Data Center (the "standalone" on-prem product, formerly
Bitbucket Server) speaks `REST /rest/api/1.0` with Basic auth — not the
`/rest/api/2.0` + HTTP-API-token flow of Bitbucket Cloud. This server targets
the Server product only.
## Build
```bash
npm install
npm run build
```
Output lands in `dist/`. The entrypoint is `dist/index.js`.
## Run
```bash
BITBUCKET_URL=http://vcs.tiddev.com \
BITBUCKET_USERNAME=<user> \
BITBUCKET_PASSWORD=<app-password> \
node dist/index.js
```
`BITBUCKET_URL` defaults to `http://vcs.tiddev.com` when unset.
### Smoke test (no credentials required)
`tools/list` needs no auth, so the server can be verified offline:
```bash
node scripts/smoke.mjs
```
Prints `OK: 40 tools` and lists every tool name. Tool *invocations* (e.g.
`bb_list_projects`) do require valid credentials.
### Inspector (interactive)
```bash
npm run inspect
```
## Registering with opencode
The server is registered in `D:\Work\.opencode\opencode.json`:
```json
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"bitbucket-standalone-mcp": {
"type": "local",
"command": ["node", "D:\\Work\\bitbucket-standalone-mcp\\dist\\index.js"],
"enabled": true,
"environment": {
"BITBUCKET_URL": "http://vcs.tiddev.com",
"BITBUCKET_USERNAME": "<user>",
"BITBUCKET_PASSWORD": "<app-password>"
}
}
}
}
```
> Replace `REPLACE_WITH_USERNAME` / `REPLACE_WITH_PASSWORD` in the real config
> with actual credentials before use. After editing `opencode.json`, **quit and
> restart opencode** — config is loaded once at startup and not hot-reloaded.
## Catalog
~30 tools, namespaced `bb_*`. Replies are JSON or raw diff/file text.
### Projects & repositories
| Tool | Purpose |
| --- | --- |
| `bb_list_projects` | List projects (filter, paginated) |
| `bb_list_repositories` | List repos (per-project or server-wide, filter, paginated) |
| `bb_get_repository` | Full repo details: state, default branch, clone URLs, web link |
| `bb_create_repository` | Create repo under a project (fork support) |
### Branches
`bb_list_branches`, `bb_get_branch`, `bb_create_branch`, `bb_delete_branch`
### Pull requests
`bb_list_pull_requests` (state/author/reviewer/text filters),
`bb_get_pull_request`, `bb_create_pull_request`, `bb_update_pull_request`
(title/description/reviewers), `bb_merge_pull_request` (noFF / fastForward /
squash / rebase / squashAndRebase / mergeAndLog / rebaseMessageMerge),
`bb_decline_pull_request`, `bb_approve_pull_request`,
`bb_unapprove_pull_request`
### Comments
`bb_list_pull_request_comments`, `bb_create_pull_request_comment` (inline
anchors via `anchoredTo` or replies via `parentCommentId`),
`bb_update_comment`, `bb_delete_comment`, `bb_resolve_comment`
### Diffs
`bb_get_diff(from, until)`, `bb_get_diff_summary`, `bb_get_pull_request_diff`,
`bb_get_pull_request_diff_summary`
### Commits
`bb_get_commit`, `bb_list_commits` (per-branch), `bb_get_commit_diff`,
`bb_get_commit_parents`
### Files (in-repo read/write)
`bb_list_directory`, `bb_get_file`, `bb_raw_file` (full content),
`bb_get_file_metadata`, `bb_create_file`, `bb_update_file`, `bb_delete_file`
### Search
`bb_search_repositories`, `bb_search_code` (text + project/repo/branch/path/date filters)
### Builds / pipeline
`bb_list_commit_builds` (CI status per commit)
### Admin
`bb_application_properties` (server version / connectivity check)
## Pagination
List tools accept `limit` (default 25, max 100) and `start` (zero-based
offset). The first page is returned in one call; fetch the next page by
passing `start = values.length`.
## Repository layout
```
bitbucket-standalone-mcp/
├─ src/
│ ├─ index.ts # McpServer wiring: registers every tool
│ ├─ client.ts # REST client (Basic auth, pagination, paths helper)
│ └─ tools/
│ ├─ types.ts # AnyToolDefinition contract + repoKeys helper
│ ├─ admin.ts branches.ts commits.ts comments.ts diffs.ts
│ ├─ files.ts pipelines.ts pull-requests.ts repos.ts search.ts
├─ dist/ # compiled JS (output of `npm run build`)
└─ scripts/smoke.mjs # offline tools/list smoke test
```
## Cloud vs. Server: what's *not* here
This targets Server/Data Center only. Bitbucket **Cloud** features
(`.rest/api/2.0` HTTP-token auth, branch status, pullrequest-task, GSSO) are
out of scope. `npm run inspect` + `git clone` the server for live
exploration.
TDQS
Scored across 41 tools
Most tools map to a clear resource+action (repositories, branches, pull requests, files, commits), and the bb_ prefix plus descriptive names help separate them. The main ambiguities are bb_get_file vs bb_raw_file, which both read file content, and the several diff tools, but their parameter scopes and descriptions are usually enough to disambiguate.
All tools share a consistent bb_ prefix and overwhelmingly follow a verb_noun pattern such as list_repositories, create_pull_request, and delete_file. Minor deviations like bb_raw_file, bb_application_properties, and bb_detect_repo break the pattern slightly but remain understandable.
41 tools is well into the heavy range for a single MCP server, and the count is inflated by overlapping file readers, multiple diff variants, and a nonfunctional bb_search_code tool. While each tool is individually scoped, the surface is larger than an agent needs for most workflows.
The tool set covers the core developer lifecycle well: project/repo listing, branches, full pull request management with comments, diffs, commits, file read/write, build statuses, and local repo detection. Notable gaps such as repository/project update/delete, tags, and code search are present but do not block the primary Bitbucket workflows.