Skip to main content
Glama
README.md
# azure-devops-cli-mcp

本地 MCP server,把 Claude Desktop / Cowork 橋接到本機的 Azure DevOps CLI。
Claude 可透過它完整使用 `az devops`、`az repos`、`az boards`、`az pipelines`、`az artifacts`。

## 前置需求

- Node.js >= 20
- Azure CLI(含 azure-devops extension):`az extension add --name azure-devops`
- 已完成 `az login`
- 不需要 `az devops configure --defaults`:server 會自動帶入預設
  organization / project / repository(見下方「啟動參數」)。

## 安裝(團隊成員)

```
npm install -g git+https://github.com/A016098Tony/azure-devops-cli-mcp.git
```

repo 內已含編譯好的 `dist/`,安裝時不需要編譯。更新版本時重跑同一行命令即可。

> 註:script 刻意不叫 `build`/`prepare`——npm 11 全域安裝 git 套件時,
> 只要 package.json 有 `build`/`prepare`/`prepack`/`install` 類 script
> 就會觸發安裝端編譯,且因 `npm_config_global` 洩漏到內層 npm 而失敗。
> 命名為 `compile` 可讓安裝流程完全跳過編譯步驟。

## Claude Desktop 設定

開啟 `claude_desktop_config.json`(Windows 完整路徑:
`C:\Users\<你的帳號>\AppData\Roaming\Claude\claude_desktop_config.json`;也可從
Claude Desktop → Settings → Developer → Edit Config 開啟),在 `mcpServers` 加入:

```json
{
  "mcpServers": {
    "azure-devops-cli": {
      "command": "npx",
      "args": ["azure-devops-cli-mcp", "--project", "MS", "--repository", "MS-Web"]
    }
  }
}
```

此設定檔 Claude Desktop(含 Cowork)與 Claude Code 共用同一格式。
claude.ai 網頁版不支援本機 stdio MCP server。

## Claude Code 設定

在專案根目錄建立 `.mcp.json`,讓團隊成員 clone 後即可使用:

```json
{
  "mcpServers": {
    "azure-devops-cli": {
      "type": "stdio",
      "command": "azure-devops-cli-mcp",
      "args": ["--project", "MS", "--repository", "MS-Web"],
      "env": {}
    }
  }
}
```

再於 `.claude/settings.json` 加入以下設定,略過首次使用時的信任確認:

```json
{
  "enabledMcpjsonServers": ["azure-devops-cli"]
}
```

兩個檔案都建議一起 commit。

## 啟動參數

三個參數皆選填,未指定時使用內建預設值:

| 參數 | 預設值 | 說明 |
|------|--------|------|
| `--organization` | `https://dev.azure.com/SKMHHIS` | 可只給短名(如 `SKMHHIS`),自動補完整 URL |
| `--project` | `MS` | 預設專案 |
| `--repository` | `MS-Web` | 只套用在 `repos pr` 命令 |

命令未指定 `--org` / `--project`(`repos pr` 未指定 `--repository`)時,
server 會自動補上這些預設值;命令中明確指定時以命令為準。
若某個 az 子命令不接受被補上的參數,server 會自動移除該參數重試一次。

> **Windows + nvm 注意**:桌面應用(GUI 程序)繼承的 PATH 可能與終端機不同,
> 若出現「找不到 npx」,把 `command` 改成 `npx.cmd` 的絕對路徑
> (用 `(Get-Command npx.cmd).Source` 查出,例如 `C:\nvm4w\nodejs\npx.cmd`),
> `args` 不變。

**務必完整結束並重新啟動 Claude Desktop**(關閉分頁不夠,要整個結束再開)才會載入。
啟動後可在對話框左下角的「+」→ Connectors 看到 `azure-devops-cli` 及其工具。

### 輸出編碼(中文亂碼)

Windows 上的 `az` 往 pipe 輸出時使用系統 ANSI code page(繁中為 cp950 / Big5),
而不是 UTF-8;`az.cmd` 以 `python -I` 啟動,`PYTHONUTF8`、`PYTHONIOENCODING`
與 `chcp 65001` 都無效。server 因此會先嚴格以 UTF-8 解碼 `az` / `git` 的 stdout 與 stderr,
失敗時改用系統 ANSI code page 解碼(950→Big5、936→GBK、932→Shift_JIS、949→EUC-KR、
125x→windows-125x),查不到或不認得時退回 UTF-8。

若自動偵測不準,可在 MCP 設定的 `env` 設定 `AZ_OUTPUT_ENCODING`
(`TextDecoder` 支援的編碼名稱,如 `big5`、`gbk`),它只在輸出不是合法 UTF-8 時作為備援編碼。

> **限制**:不在 Big5 範圍的字元(如 emoji、部分罕用字)在 `az` 端就無法編碼,
> 這類內容請改用走 REST 的工具(如 `az_workitem_relations`、`az_rest`)讀取。

## 工具

| 工具 | 用途 |
|------|------|
| `az_devops` | 執行任意 DevOps 家族命令,例如 `repos pr list --status active`。未指定輸出格式時自動用 JSON。 |
| `az_devops_help` | 查詢命令語法,等同 `az <command> --help`。 |
| `az_workitem_attach` | 上傳本機檔案為 work item 附件並建立連結(文字與 binary 皆可,上限 100MB)。例如把 code review 報告或錯誤截圖附到 work item。 |
| `az_attachment_download` | 下載 work item 的圖與附件到系統暫存目錄(路徑由 server 決定)。同時收 HTML 欄位的內嵌 `<img>` 與 `relations` 的 `AttachedFile`;內嵌圖不在 `relations` 裡,只查 relations 會漏掉需求描述的截圖。也可用 `url` 模式下載單一附件。 |
| `az_pr_show` | 取得 PR 完整資訊(REST),含 source/target branch 與狀態,並預設一併回傳關聯 work item(`workItemRefs`);可用 `includeWorkItemRefs: false` 關閉。 |
| `az_pr_changes` | 取得 PR 異動檔案清單(REST iterations/changes),自動使用最新 iteration。 |
| `az_pr_workitems` | 取得 PR 關聯的 work item 清單(REST)。`az_pr_show` 已預設含這份清單,只在單獨要 work item、不想拉整包 PR 資訊時才需要。 |
| `az_workitem_relations` | 取得 work item 含 relations(REST,$expand=relations),可檢查附件重名。注意 `relations` 看不到描述裡的內嵌圖片,要取圖請用 `az_attachment_download`。 |
| `az_pr_comment` | 在 PR 建立討論串留言或回覆既有討論串(REST)。 |
| `az_workitem_update` | 更新 work item 欄位/寫入 Discussion(REST json-patch,僅允許 /fields/*)。 |
| `az_rest` | 通用 Azure DevOps REST 呼叫(GET/POST/PATCH),供未涵蓋的端點使用。 |
| `az_git_fetch` | 在主機端對本機 repo 執行 `git fetch`(唯讀)。Cowork sandbox 內 fetch 被 proxy 擋下(403)時的替代路徑,fetch 完成後 sandbox 內即可用本機 git 操作 `origin/<branch>`。 |
| `az_git_ls_remote` | 在主機端查詢遠端 refs(`git ls-remote`,不下載物件),可先確認遠端分支存在。 |

REST 工具的認證與 `az_workitem_attach` 相同:優先使用 `AZURE_DEVOPS_EXT_PAT`
環境變數,否則使用 `az login` 的憑證。所有 REST URL 鎖定在預設 organization,
無法對其他主機發送請求。

僅允許 `devops`、`repos`、`boards`、`pipelines`、`artifacts` 五個命令群組;
其餘 az 命令(如 `vm`、`account`)一律拒絕。認證依賴本機的 `az login`
(`az_workitem_attach` 會內部執行 `az account get-access-token` 取 token;
若設定了 `AZURE_DEVOPS_EXT_PAT` 環境變數則優先使用該 PAT),
server 不儲存任何憑證。

### PR 與 work item 串接

常見流程是「從 PR 找到關聯 work item,再把報告或截圖附上去」。
`az_pr_show` 預設就會回傳 `workItemRefs`,所以一次呼叫即可:

```jsonc
// 1. 取 PR 資訊,順便拿到關聯 work item
az_pr_show { "prNumber": 104443 }
// → { "pullRequestId": 104443, "status": "active", ...,
//     "workItemRefs": [{ "id": "160708", "url": "..." }] }

// 2. 上傳檔案到該 work item
az_workitem_attach { "workItemId": 160708, "filePath": "D:\\report.md" }
```

有兩點容易踩到:

- **`workItemRefs[].id` 是字串**(`"160708"`),而 `az_workitem_attach` 的
  `workItemId` 要求數字,串接時必須轉型。
- **`az_workitem_attach` 的附件一律上傳到預設 project**(沒有 per-call 覆寫參數)。
  若 work item 不在預設 project,請改用 `az_rest` 自行呼叫 attachments 端點。

只需要確認附件是否已存在(避免重複上傳)時,用 `az_workitem_relations`
檢查 `AttachedFile` 的 `attributes.name`。反向要把 work item 的圖與附件抓到本機,
用 `az_attachment_download`(見下節)。

### 下載 work item 的圖與附件

Azure DevOps 把圖片存在兩個不同的地方,`az_attachment_download` 兩邊都會收:

| 來源 | 出現在哪 | 存到 |
|------|----------|------|
| 描述裡貼上的截圖 | HTML 欄位的 `<img src>` | `<暫存根目錄>/workitem-<id>/images/` |
| 掛在 work item 上的附件 | `relations` 的 `AttachedFile` | `<暫存根目錄>/workitem-<id>/attachments/` |

掃描的 HTML 欄位有三個:`System.Description`、
`Microsoft.VSTS.Common.AcceptanceCriteria`、`Microsoft.VSTS.TCM.ReproSteps`。

**內嵌圖片不會出現在 `relations` 裡**,所以只用 `az_workitem_relations` 檢查會漏掉
需求描述裡的 UI 截圖 —— 實測 work item 160132 有 2 張內嵌圖與 6 個 `.md` 附件,
`relations` 只看得到後者。

#### 檔案存在哪

固定在系統暫存目錄底下的 `azure-devops-mcp/`(Windows 是
`%TEMP%\azure-devops-mcp\`),**呼叫端無法指定路徑**:

```
%TEMP%/azure-devops-mcp/
├─ workitem-160132/
│  ├─ images/        內嵌截圖
│  └─ attachments/   AttachedFile
└─ single/           url 模式的單檔
```

這是刻意的設計。呼叫這個工具的是模型,而模型可能剛讀完一份**外部可控**的
work item 描述;若讓呼叫參數決定寫檔位置,等於讓描述內容有機會指定路徑。
移除參數就沒有這個著陸點。回傳訊息會給出絕對路徑,直接讀取即可。

檔案屬暫存性質,作業系統會自行清理,需要時重抓即可。
**每次下載同一個 work item 會先清空該資料夾再重抓**,
所以本機內容一定對應 ADO 現況,不會留下已刪除或改名的舊檔誤導判讀。

```jsonc
// 一次抓齊兩個來源
az_attachment_download { "workItemId": 160132 }
// → C:\Users\<你>\AppData\Local\Temp\azure-devops-mcp\workitem-160132
//   images/       image.png (221071 bytes)、image-2.png (295748 bytes)
//   attachments/  design.md (11918 bytes)、spec.md (11956 bytes)…

// 只抓單一附件(relations 的 URL 不帶檔名,記得一併給 fileName)
az_attachment_download { "url": "https://dev.azure.com/...", "fileName": "design.md" }
// → …\azure-devops-mcp\single\design.md
```

`workItemId` 與 `url` 擇一,兩個都給或都不給會被拒絕。

url 模式可另外給 `fileName` 指定存檔名稱。**relations 的附件 URL 不帶檔名**
(回應的 `content-disposition` 也沒有 filename),所以從 `az_workitem_relations`
拿到 url 要單獨下載時,請把該附件的 `attributes.name` 一併傳進來,否則會存成
`attachment`、連抓兩個還會互相覆蓋。內嵌圖的 URL 本身帶 `?fileName=`,不受影響。
`fileName` 只決定固定暫存目錄裡的檔名,決定不了目錄,且同樣會經過檔名清理。
同一次下載內的同名檔會自動改名(`image.png` → `image-2.png`)——
ADO 內嵌圖的預設檔名都叫 `image.png`,這在實務上很常見。

附件名含 Windows 不允許的字元(`< > : " | ? *` 與控制字元)時會換成 `_`。
`:` 特別重要:NTFS 會把 `report:v1.md` 當成 alternate data stream,
寫入不會報錯,但目錄裡只留下 0 bytes 的 `report`,內容藏在資料流裡。
ADO 的附件名可能來自 Mac/Linux,這些字元在那裡是合法的。

單檔上限 100MB。附件 URL 必須與預設 organization 同網域,否則直接拒絕且
**不發出請求**,避免認證 token 外洩到其他主機。個別檔案下載失敗不會中斷整批,
會列在回傳訊息的失敗清單裡。

### 安全防護

命令經由 shell 執行,因此雙引號外含有 shell 控制字元(`& | ; < > ( ) \` ^` 或換行)
或有未配對雙引號的命令會被拒絕,以免 `repos list & <任意命令>` 之類的串接繞過群組
限制而執行任意本機命令。含特殊字元的參數值(例如 WIQL 或 `--query` 的 JMESPath 運算式)
用雙引號包起來即可正常執行,例如:
`boards query --wiql "SELECT [System.Id] FROM WorkItems WHERE [System.State] <> 'Closed'"`。

### Git 工具

`az_git_fetch` / `az_git_ls_remote` 在主機端執行 git 的唯讀網路操作,
`repoPath` 必須是主機端的絕對路徑。`az_git_ls_remote` 的 `patterns`
可給多個 pattern,符合任一者的 ref 即列出(同原生 `git ls-remote`)。
參數經嚴格驗證:remote 只接受名稱(不接受 URL)、refspec/patterns
不可以 `-` 開頭(擋 `--upload-pack` 等危險選項)。不提供 push、pull 或任何寫入操作。認證使用主機端的
git credential(如 Git Credential Manager)。

## 開發

```
git clone https://github.com/A016098Tony/azure-devops-cli-mcp.git
npm install
npm test              # vitest 單元 + 整合測試(不需要 az)
node scripts/smoke.mjs  # 實機煙霧測試(需要 az login)
```

改動 `src/` 後務必執行 `npm run compile` 並把 `dist/` 一起 commit——
安裝端直接使用 repo 內的 `dist/`,忘記重新編譯會讓使用者裝到舊版行為。

TDQS

A3.7/5.0

Scored across 12 tools

Disambiguation4/5

Tools are mostly distinct: the dedicated az_pr_* and az_workitem_* tools target specific resources and are clearly differentiated from the generic az_devops CLI passthrough and az_rest fallback. Minor ambiguity exists between az_devops (which can also run PR/workitem commands) and the dedicated REST tools, though the descriptions explicitly advise using the dedicated tools first. The az_git_fetch vs az_git_ls_remote pair is well-separated by read-only scope.

Naming Consistency3/5

There are two conventions mixed: a non-prefixed 'az_devops'/'az_devops_help' pair and a prefixed 'az_rest', 'az_git_fetch', 'az_git_ls_remote', plus camelCase-free hyphenated domain tools (az_pr_show, az_workitem_attach). The az_* prefix is consistent but the grouping/casing is inconsistent—some use domain_verb (az_pr_show), some use verb placement like az_git_fetch. Not chaotic, but not a single predictable pattern.

Tool Count4/5

12 tools for an Azure DevOps MCP server is reasonable. Each dedicated tool earns its place by covering a commonly-needed operation with the REST API, while the generic az_devops passthrough and az_rest fallbacks consolidate the remaining surface. Slightly on the higher end but justified by the breadth of Azure DevOps domains covered.

Completeness4/5

The tool surface covers a broad set of Azure DevOps operations: CLI passthrough for the main command groups, help lookup, PR inspection (show/changes/workitems/comment), work item management (attach/update/relations), generic REST passthrough, and git helpers. Notable gaps: no dedicated tool for creating a PR (relies on az_devops CLI), and the git tools are read-only helpers rather than full git coverage, but these are reasonable trade-offs given the generic az_devops passthrough and az_rest fallback.

Maintenance

ActivityMaintained
ResponsivenessNo issues