Skip to main content
Glama
ducbachsong

Backlog MCP Server

by ducbachsong

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

  • 22 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/action selector 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_issues and add_comment send 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_fields argument to blank them out.

  • Real mentions — passing mention_user_ids posts a comment that renders as a highlighted @Name mention and triggers a real Backlog notification (bell + email), matching what you get from typing @ in the Backlog UI. Plain @Name text does neither.

  • Attachments on every write — add_comment, create_issue, update_issues and manage_wiki_page take attachments=[...]; files go up in the same request as the rest of the change, and images are referenced inline so they show in the body, not just the file list.

  • Local file stash — files read from Backlog, fetched from the web, or written by Claude are kept in a per-session temp folder under short handles (f1, f2…). Copying a comment with its screenshots to another ticket — even in another space — never pushes the image bytes through the conversation.

  • Parallel fetching and updating for bulk operations (get_issue, get_comments, update_issues, delete_issue all 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.

Related MCP server: Backlog MCP Server

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.

Optional file-handling settings (all have sensible defaults):

Variable

Default

Meaning

BACKLOG_MCP_UPLOAD_DIRS

your Downloads and Desktop

Folders local files may be attached from, separated by ; on Windows (: elsewhere). The stash folder is always allowed.

BACKLOG_MCP_TEMP_DIR

<system temp>/backlog-mcp

Where the stash lives.

BACKLOG_MCP_MAX_FILE_MB

50

Largest single file that can be stashed or uploaded.

BACKLOG_MCP_STASH_MAX_MB

500

Total stash size.

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-level projects and myself. Cached per server run, so kinds='all' is cheap.

Issues

  • get_issues — search/filter; count_only=True returns just the match count.

  • get_issue — one or many keys, fetched in parallel; full=False for 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 状態 / 担当者 / 優先度 / 種別 / 完了理由 / マイルストーン / カテゴリー / 発生バージョン / 開始日 / 期限日 / 予定時間 / 実績時間, plus summary, description, parent_issue_id, a comment, mention_user_ids and clear_fields — all in a single request per issue.

  • delete_issue — one or many keys.

Comments

  • get_comments — one or many issues; last_n=0 for the full thread, last_n=N for the newest N (slimmed).

  • add_comment — comment + optional mention + optional field changes + attached files, all in one request.

  • manage_comment — action='update' or 'delete'.

Attachments & files

  • get_attachments — lists an issue's or wiki page's attachments (or just one comment's, with comment_id); pass attachment_id to view one inline. save=True downloads into the stash and returns handles instead.

  • manage_files — the stash: list, add (from an allowlisted local path, a public url, model-written text, or data_base64), view, remove, clear, and list_dir to find what the user just saved to Downloads/Desktop.

get_comments marks every comment that attached files with attachments: [{id, name}].

Copying a comment with its images to another ticket:

get_comments(['A-1'])                                  → comment 123 has [bug.png]
get_attachments('A-1', comment_id=123, save=True)      → handle 'f1'
add_comment('B-5', content=<copied text>, attachments=['f1'])

Files keep their original names, so ![image][bug.png] references in copied text still render. Pass a different source on the last call to copy across spaces.

Limitations: images pasted into the Claude Desktop chat cannot be attached — the client never hands their bytes to tools. Save the image to Downloads or Desktop and ask Claude to attach it from there. The stash is deleted when the server stops; anything you want to keep should be attached to a ticket or wiki page first.

Project admin

  • manage_project_setting — kind of category / issue_type / milestone / custom_field × action of add / update / delete. Clears the metadata cache on success.

Wiki

  • get_wikis — list, read one page (wiki_id), or count_only.

  • manage_wiki_page — action='create' / 'update' / 'delete'.

Activity & notifications

  • get_activities — scope='project' or 'space'.

  • get_notifications — list, or count_only.

  • mark_notifications_read — one notification, or all when notification_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
  stash.py              per-run temp folder for files; local-path allowlist
  attach.py             `attachments=[...]` -> validated, uploaded attachment ids
  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
    files.py            manage_files
    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/, stash → common/fields/attach → app → tools/. Importing backlog_mcp registers every tool, because each tool module applies @mcp.tool() at import time.

Adding a tool: put it in the matching tools/ module (or add a new module and list it in tools/__init__.py). Reach Backlog through api.get / api.post / api.patch / api.delete rather than requests directly — that request path is what keeps the API key out of error messages.

Security note

Backlog authenticates with a ?apiKey= query parameter, so the key is part of every 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 every error leaving the HTTP layer — if you add a code path that talks to Backlog outside api/http.py, scrub it there too.

Ticket text can steer the model, so the file features are fenced in too: local files can only be read from BACKLOG_MCP_UPLOAD_DIRS and the stash (paths are fully resolved first, so .. and symlinks cannot escape), and manage_files only fetches public http(s) URLs — loopback, private and link-local addresses are refused on every redirect hop.

License

No license specified — all rights reserved by default.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    A
    maintenance
    A Model Context Protocol server that enables Claude to interact with Backlog project management tools through API integration, allowing management of projects, issues, wiki pages and other Backlog resources.
    63
    16,295 npm
    233
    MIT