@burningbrosdabi/bbpm-mcp
v0.8.3
Published
Burningbros BBPM MCP — Model Context Protocol server exposing the BB Project Management API to Claude. Create issues, assign tasks, comment, and query the board from a chat prompt.
Maintainers
Readme
Burningbros BBPM MCP
The Burningbros BBPM MCP server bridges Claude ↔ Burningbros BB Project Management. Lets internal staff create issues, attach screenshots, comment, link specs, search across projects, and query the board from a chat prompt — no need to open the web UI.
┌──────────────────┐ stdio / HTTP ┌─────────────────────────┐ HTTPS ┌─────────────────────┐
│ Claude Desktop │ ─────────────────► │ Burningbros BBPM MCP │ ─────────► │ pm.burningbros.kr │
│ Claude Code │ │ (this repo) │ │ /api/external/* │
└──────────────────┘ └─────────────────────────┘ └─────────────────────┘
│
▼
BBPM_API_KEY (per-user, X-API-Key)
— or —
OAuth 2.1 PKCE (claude.ai connector)What you can ask Claude
"Tạo cho tôi 1 task trên project PITB, title 'Fix subtask hover radius', high priority, assign cho Phạm Tùng."
"What's on my plate today?" → Claude calls
whoami+list_my_assignments.
"Tạo bug cho login crash" (kèm screenshot dán vào chat) → Claude calls
get_create_rules→create_issuewith the screenshot as an inline attachment, formatted per the team's bug template.
"Project DW tuần qua thế nào?" →
get_project_digest({ projectKey: 'DW', days: 7 }).
"Đính spec UserAuth vào PITB-42" →
list_specs+link_issue_to_spec.
"Mark PITB-12 as today's focus" →
set_focus_today.
Tools exposed (31 total, grouped by domain)
Issues — read
| Tool | What it does |
|---|---|
| get_issue | Fetch full detail of an issue (+ comments, activities) |
| list_issues | List or summarize issues; rich filters (assignee/priority/type/text/dueIn/hasOverdue) + sparse fields + mode=summary |
| list_my_assignments | Cross-project shortcut: issues currently assigned to the caller |
| list_comments | Page through comments on an issue |
| list_activities | Audit trail (status / assignee / priority / etc. changes) |
| list_issue_spec_links | Specs (and sections) linked to an issue |
| list_attachments_for_issue | All attachments on an issue + uploader profile |
| search_issues | Cross-project case-insensitive title (optionally description) search |
Issues — write
| Tool | What it does |
|---|---|
| create_issue | Create task / bug / epic / sub-task. Accepts inline attachments[] (base64 images, uploaded post-creation). Returns { issue, warnings?, attachments? }. |
| update_issue | Edit title, description, status, priority, assignee, reviewer, labels |
| comment_on_issue | Post a comment with optional @mention (triggers Slack DM) |
| attach_image_to_issue | Attach a screenshot to an existing issue (base64; returns URL + embed markdown) |
| set_focus_today | Mark an issue as today's focus (or any date, or clear it) |
| archive_issue / unarchive_issue | Manual archive/restore (soft-warns when archiving non-terminal) |
| add_label_to_issue / remove_label_from_issue | Manage labels by name; idempotent; reports unknown names instead of failing |
| link_issue_to_spec / unlink_issue_from_spec | Connect issue ↔ spec (optional sectionSlug for deep-link) |
| delete_attachment | Remove an attachment (uploader-only) |
Specs
| Tool | What it does |
|---|---|
| list_specs | List specification documents, filter by category or status |
| get_spec | Fetch a single spec (HTML body) |
| get_spec_markdown | Spec body rendered as markdown — LLM-friendly |
| create_spec | Create a new spec |
| update_spec | Patch title / content / category / status / order |
Workspace meta
| Tool | What it does |
|---|---|
| whoami | Identity of the calling user (resolves "me") |
| list_projects | All BB PM projects you can access |
| list_members | Project members (to resolve names → user IDs) |
| list_labels | Labels defined in a project |
| get_project_digest | Project snapshot over N days: counts + per-assignee + overdue / upcoming / recent buckets + activity stream |
| get_create_rules | Workspace-wide per-IssueType rules (title pattern, description template, required fields, defaults, enforced labels) — call before create_issue |
Token efficiency
The default list_issues response is intentionally sparse — only [id, number, title, status, priority, type, assignee.name]. Opt into heavier fields explicitly:
{ "projectKey": "PITB", "fields": ["description", "labels", "dates"] }For project-state questions ("how is project X going?"), prefer the aggregate path — returns counts only, no row payloads, ~95% smaller:
{ "projectKey": "PITB", "mode": "summary" }Server-side filters (assignee, priority, type, text, updatedSince, dueIn, hasOverdue) let the LLM narrow the result before it leaves the database — much cheaper than paging through everything.
Rules-driven create_issue
Each workspace ships with per-IssueType rules (configured at /admin/issue-rules):
- title pattern (regex like
/^\[BUG\]/or a hint string) - description template (markdown skeleton)
- required fields (soft — missing fields come back as
warnings) - default values (auto-applied when missing)
- enforced labels (auto-attached, created in the project on demand)
The LLM is expected to call get_create_rules({ type }) first so the resulting issue matches the team's expected format. The response surfaces both the rules and the markdown template the LLM uses as the starting point for description. Any unmet rule comes back from create_issue as soft warnings, never a hard reject — so the LLM can follow up with update_issue to patch.
Setup — Claude Desktop (NPX, recommended for individual users)
1. Generate an API key
- Open BB PM → Profile → API Keys → Generate
- Copy the raw key (shown once — looks like
bbpm_<56 hex chars>) - Store it in a password manager
2. Add to claude_desktop_config.json
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or the platform equivalent:
{
"mcpServers": {
"bbpm": {
"command": "npx",
"args": ["-y", "@burningbrosdabi/bbpm-mcp"],
"env": {
"BBPM_API_KEY": "bbpm_paste_your_key_here",
"BBPM_API_BASE": "https://pm.burningbros.kr/api",
"BBPM_FRONTEND_URL": "https://pm.burningbros.kr"
}
}
}
}Restart Claude Desktop. The tools should appear in the tools panel.
Setup — Claude Code (CLI)
claude mcp add bbpm npx -y @burningbrosdabi/bbpm-mcp \
--env BBPM_API_KEY=bbpm_paste_your_key_here \
--env BBPM_API_BASE=https://pm.burningbros.kr/api \
--env BBPM_FRONTEND_URL=https://pm.burningbros.krSetup — Remote HTTP (team-hosted)
The recommended workflow on a VPS uses the bundled Makefile:
curl -fsSL https://raw.githubusercontent.com/burningbrosdabi/bbpm-internal-mcp/main/Makefile -o Makefile
make redeploy # pull newest npm + recreate container
make redeploy VERSION=0.6.1 # pin a specific npm version
make status # docker ps + healthz + discovery probes
make logs # follow container logsThe container is intentionally just node:22-alpine with the package installed at boot via npm i -g. No image to maintain — bumping VERSION is enough.
Or manually:
docker run -d --name bbpm-mcp \
-e BBPM_API_BASE=https://pm.burningbros.kr/api \
-e BBPM_FRONTEND_URL=https://pm.burningbros.kr \
-e MCP_PUBLIC_URL=https://mcp.burningbros.kr \
-e PORT=3333 \
-p 127.0.0.1:3334:3333 \
node:22-alpine \
sh -c 'npm i -g @burningbrosdabi/bbpm-mcp@latest && bbpm-mcp-http'Each user still configures their own BBPM_API_KEY on the client side (Claude Code / Claude Desktop sends it in the per-session env), so the remote server never holds keys at rest. Point clients at https://mcp.burningbros.kr/mcp.
For claude.ai custom connectors, the remote HTTP transport also speaks OAuth 2.1 PKCE — see oauth-server-design.md in the BB PM repo and scripts/oauth-playground.mjs here.
Local development
pnpm install
cp .env.example .env
# edit .env with your local BBPM_API_KEY and BBPM_API_BASE
pnpm dev # stdio transport — test with `npx @modelcontextprotocol/inspector`
pnpm dev:http # HTTP transport — POST JSON-RPC to http://localhost:3333/mcpTo test interactively, point the MCP Inspector at pnpm dev:
npx @modelcontextprotocol/inspector pnpm devArchitecture notes
- One client class (
BbpmClient) wraps the BB PM REST API. Every request injects eitherX-API-Key: bbpm_<hex>(personal key) orAuthorization: Bearer bbpm_at_<…>(OAuth 2.1). Errors come back asBbpmApiErrorwith status + path + message so tool output can quote them verbatim. - One server builder (
buildServer) registers all tools. Transports (stdio / HTTP) wrap the same instance. - Tool definitions are colocated with their Zod input schemas in
src/tools/. Each exports aToolDefinitionconsumed bybuildServer. - Idempotency: write tools (
create_issue,update_issue,comment_on_issue, etc.) are not idempotent at the protocol layer — the LLM is responsible for not repeating them. BBPM's outbox handles its own delivery guarantees downstream of the API.
BB PM API surface consumed
All endpoints are guarded by ApiKeyGuard (accepts API key or OAuth bearer):
Issues
POST /external/issues— create (accepts inlineattachments[])PATCH /external/issues/:projectKey/:issueNumber— updateGET /external/issues/:projectKey/:issueNumber— get oneGET /external/issues/:projectKey— list (with filters, summary mode, sparse fields)POST /external/issues/:projectKey/:issueNumber/comments— commentGET /external/issues/:projectKey/:issueNumber/comments— list commentsGET /external/issues/:projectKey/:issueNumber/activities— audit logPOST /external/issues/:projectKey/:issueNumber/attachments— base64 image uploadGET /external/issues/:projectKey/:issueNumber/attachments— list attachmentsDELETE /external/attachments/:id— delete attachment (uploader-only)GET /external/search?q=...— cross-project ILIKE searchPATCH /external/issues/:projectKey/:issueNumber/focus— set/clear focusDatePOST /external/issues/:projectKey/:issueNumber/archive//unarchivePOST /external/issues/:projectKey/:issueNumber/labels— add labels by nameDELETE /external/issues/:projectKey/:issueNumber/labels— remove labels by namePOST /external/issues/:projectKey/:issueNumber/spec-links— link to specGET /external/issues/:projectKey/:issueNumber/spec-links— list linksDELETE /external/issues/:projectKey/:issueNumber/spec-links/:linkId
Specs
GET /external/projects/:projectKey/specs— list (filter category/status)GET /external/projects/:projectKey/specs/:specId— get one (HTML body)GET /external/projects/:projectKey/specs/:specId/markdown— markdown bodyPOST /external/projects/:projectKey/specs— createPATCH /external/projects/:projectKey/specs/:specId— update
Workspace meta
GET /external/me— calling user profile (whoami)GET /external/me/assignments— cross-project assigned issuesGET /external/projects— projects the caller is a member ofGET /external/projects/:projectKey/members— project membersGET /external/projects/:projectKey/labels— project labelsGET /external/projects/:projectKey/digest?days=N— N-day digestGET /external/issue-rules?type=BUG— global per-IssueType creation rules
Versioning
Tracked in CHANGELOG.md. Recent highlights:
- v0.8.0 —
search_issues(cross-project ILIKE),list_attachments_for_issue,delete_attachment. Closes the read/manage loop on attachments and adds workspace-wide search. - v0.7.0 —
whoami,list_my_assignments,set_focus_today,archive_issue,unarchive_issue,add_label_to_issue,remove_label_from_issue. Productivity shortcuts for the daily workflow. - v0.6.0 —
get_project_digest, full specs CRUD (5 tools), issue ↔ spec links (3 tools). Documentation surface unlocked for the LLM. - v0.5.0 —
get_create_rules,attach_image_to_issue. Sparselist_issuesdefaults + summary mode + 9 filters. Rules-drivencreate_issuewith soft warnings. - v0.4.x — OAuth 2.1 (DCR + PKCE + token revocation) for
claude.aicustom connectors.
