Backlog MCP Server
An MCP server that exposes Backlog project management as tools for Claude Desktop (or any MCP-compatible client). Search and manage issues, comments, wiki pages, milestones, custom fields, notifications, and more — directly from a conversation with Claude.
Features
- 21 tools covering issues, comments, wiki, categories, issue types, milestones, custom fields, attachments, activity feeds, notifications, watchers, and stars. Tools are grouped by subject with a
kind/actionselector rather than split one-per-endpoint, so there is less schema for the model to scan. - Multi-space support — configure any number of Backlog spaces (e.g. separate client/company instances) and target them by name per tool call, without restarting or reconfiguring.
- One request per change —
update_issuesandadd_commentsend every field change plus the comment plus the mention notification in a single PATCH, so Backlog's 課題の変更履歴 gets one entry instead of one per field. - Full ticket field coverage — 状態 / 担当者 / 優先度 / 種別 / マイルストーン / カテゴリー / 発生バージョン / 開始日 / 期限日 / 予定時間 / 実績時間 / 完了理由, each settable by display name or numeric id ('Closed', 'clos' and '4' all work), with a
clear_fieldsargument to blank them out. - Real mentions — passing
mention_user_idsposts a comment that renders as a highlighted@Namemention and triggers a real Backlog notification (bell + email), matching what you get from typing@in the Backlog UI. Plain@Nametext does neither. - Parallel fetching and updating for bulk operations (
get_issue,get_comments,update_issues,delete_issueall accept a list of keys). - Read-only tools require no confirmation; every create/update/delete tool is marked in its docstring for the client to confirm with the user before calling.
Setup
1. Install dependencies
uv sync
# or
pip install -e .
Requires Python 3.11+.
2. Configure Backlog spaces
Copy .env.example to .env and fill in your space(s). Each space needs three variables sharing a common <NAME> suffix:
BACKLOG_API_KEY_<NAME>=...
BACKLOG_HOST_<NAME>=...
PROJECT_KEY_<NAME>=...
<NAME> (lowercased) becomes the source argument you pass to tools. Add as many spaces as you need by repeating the pattern with a different <NAME>. Optionally set DEFAULT_SOURCE=<name> to control which space is used when source is omitted — otherwise the first configured space is used.
Get your API key from Backlog under Personal Settings → API.
3. Register with Claude Desktop
Copy claude_desktop_config.example.json to your Claude Desktop config location, fill in the real command/args paths and credentials, and merge it into your existing mcpServers block if you already have other servers configured:
{
"mcpServers": {
"backlog": {
"command": "/path/to/backlog-mcp/.venv/Scripts/python.exe",
"args": ["/path/to/backlog-mcp/server.py"],
"env": {
"BACKLOG_API_KEY_SPACE1": "your_api_key_here",
"BACKLOG_HOST_SPACE1": "your-space.backlog.com",
"PROJECT_KEY_SPACE1": "YOUR_PROJECT_KEY"
}
}
}
}
Your filled-in claude_desktop_config.json is machine-specific and contains live credentials — keep it out of version control (already covered by .gitignore).
Tools
Discovery & metadata
get_sources— list the configured Backlog spaces.get_project_metadata— one call for every lookup list:project,statuses,users,issue_types,categories,milestones,versions,priorities,resolutions,custom_fields, plus space-levelprojectsandmyself. Cached per server run, sokinds='all'is cheap.
Issues
get_issues— search/filter;count_only=Truereturns just the match count.get_issue— one or many keys, fetched in parallel;full=Falsefor slim records.get_related_issues— parent, children, or both.get_recently_viewed— recently viewed issues or wikis.create_issue— create with every field set at once.update_issues— the write tool. One or many keys; sets any combination of 状態 / 担当者 / 優先度 / 種別 / 完了理由 / マイルストーン / カテゴリー / 発生バージョン / 開始日 / 期限日 / 予定時間 / 実績時間, plussummary,description,parent_issue_id, acomment,mention_user_idsandclear_fields— all in a single request per issue.delete_issue— one or many keys.
Comments
get_comments— one or many issues;last_n=0for the full thread,last_n=Nfor the newest N (slimmed).add_comment— comment + optional mention + optional field changes, all in one request.manage_comment—action='update'or'delete'.
Attachments
get_attachments— lists an issue's or wiki page's attachments; passattachment_idto download one. Images come back inline, text files as text, other binaries as base64.
Project admin
manage_project_setting—kindofcategory/issue_type/milestone/custom_field×actionofadd/update/delete. Clears the metadata cache on success.
Wiki
get_wikis— list, read one page (wiki_id), orcount_only.manage_wiki_page—action='create'/'update'/'delete'.
Activity & notifications
get_activities—scope='project'or'space'.get_notifications— list, orcount_only.mark_notifications_read— one notification, or all whennotification_id=0.
Watchers & stars
manage_watchers—action='list'/'add'/'delete'.add_star— star an issue, comment, or wiki page.
Project layout
server.py entry point — Claude Desktop configs point here
backlog_mcp/
config.py builds the multi-space source registry from env vars
app.py the FastMCP object and process entry point
common.py sentinels shared by tools (default source, "unchanged")
fields.py ticket-field value -> Backlog form body; mention rewriting
api/ everything below the tool definitions
secrets.py API-key redaction (security-critical — read this first)
sources.py source name -> configured Backlog space
http.py the retrying request path all traffic goes through
meta.py project lookup lists, caching, name -> id resolution
slim.py payload trimming
issues.py paginated issue / comment fetching
parallel.py fan-out for multi-key tools
tools/ the MCP tools, one module per subject
metadata.py get_sources, get_project_metadata
issues.py get_issues, get_issue, get_related_issues,
create_issue, update_issues, delete_issue
comments.py get_comments, add_comment, manage_comment
attachments.py get_attachments
project_settings.py manage_project_setting
wiki.py get_wikis, manage_wiki_page
activity.py get_activities, get_recently_viewed,
get_notifications, mark_notifications_read
social.py manage_watchers, add_star
Each layer only imports the ones above it: config → api/ → common/fields →app → tools/. Importing backlog_mcp registers every tool, because each toolmodule applies @mcp.tool() at import time.
Adding a tool: put it in the matching tools/ module (or add a new module andlist it in tools/__init__.py). Reach Backlog through api.get / api.post /api.patch / api.delete rather than requests directly — that request path iswhat keeps the API key out of error messages.
Security note
Backlog authenticates with a ?apiKey= query parameter, so the key is part ofevery request URL, and requests puts the full URL into its exception messages.Those messages reach the MCP client. api/secrets.py scrubs the key out of everyerror leaving the HTTP layer — if you add a code path that talks to Backlogoutside api/http.py, scrub it there too.
License
No license specified — all rights reserved by default.