ado-mcp
# Azure DevOps MCP Server
A production-grade [Model Context Protocol](https://modelcontextprotocol.io) server for Azure DevOps. Exposes Azure DevOps operations as MCP tools (plus, in later phases, resources and prompts) over **stdio** (local) and **Streamable HTTP** (hosted/multi-user).
- **TypeScript** (ESM, Node 20+)
- ADO access via the official **`azure-devops-node-api`** SDK, with an axios **REST fallback** for endpoints the SDK doesn't cover (search, analytics, etc.)
- Three auth modes: **PAT**, **Azure CLI (`az login`)**, **On-Behalf-Of + Entra JWT** (hosted)
- Per-tool **RBAC**, destructive-op guard, secret redaction, structured logging, retry with backoff
> **Status:** All 6 phases complete — **113 tools** across 13 domains, plus **4 MCP resources** and **4 MCP prompts**:
> - **core** (7) · **repos** (15) · **pullrequests** (12) · **workitems** (16) · **boards** (10)
> - **pipelines** (13) · **releases** (8) · **testplans** (10) · **wiki** (7) · **search** (3) · **artifacts** (5)
> - **security** (5) · **analytics** (2)
> - **Resources:** `ado://projects`, `ado://project/{project}/repos`, `ado://project/{project}/workitem/{id}`, `ado://project/{project}/repo/{repo}/pullrequest/{prId}`
> - **Prompts:** `pr-review`, `release-readiness`, `sprint-planning`, `bug-triage`
>
> **Hardening:** per-host circuit breaker, retry w/ backoff + Retry-After, secret redaction, per-tool RBAC + destructive guard, audit logging, ESLint, a Vitest suite (unit + live MCP-protocol test), and an Azure Pipelines CI (`azure-pipelines.yml`).
---
## 1. Prerequisites
- **Node.js ≥ 20** and npm
- An **Azure DevOps organization** you can access
- One of:
- a **Personal Access Token** (PAT), or
- the **Azure CLI** installed and `az login` completed, or
- (hosted) an **Entra app registration** with the ADO delegated permission, for OBO
## 2. Install
```bash
cd "E:\MCP Servers\ado-mcp-server"
npm install
```
## 3. Configure
```bash
cp .env.example .env # PowerShell: Copy-Item .env.example .env
```
Edit `.env`. Minimum for a quick local start with the Azure CLI:
```env
ADO_ORG=YourOrgName
ADO_DEFAULT_PROJECT=YourProject
AUTH_MODE=azcli
```
### Auth modes
| `AUTH_MODE` | Needs | Notes |
|---|---|---|
| `azcli` | `az login` done locally | Easiest for dev. No secrets stored. |
| `pat` | `ADO_PAT` | PAT scopes must cover the tools you call (e.g. *Work Items: Read & Write*, *Code: Read & Write*). |
| `obo` | `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET` | **HTTP transport only.** Validates the caller's Entra JWT, then exchanges it for an ADO token preserving the user's identity. |
> A **PAT** is created in Azure DevOps → *User settings → Personal access tokens*.
## 4. Build & run
```bash
npm run build # compile to dist/
npm start # stdio transport (default)
```
Development with auto-reload:
```bash
npm run dev # stdio
npm run dev:http # Streamable HTTP on PORT (default 3000)
```
Force a transport regardless of `TRANSPORT`:
```bash
node dist/index.js --transport http
node dist/index.js --transport stdio
```
## 5. Connect a client
### Claude Desktop / VS Code / Claude Code (stdio)
Add to your MCP client config (e.g. Claude Desktop `claude_desktop_config.json`).
**Published package via `npx`** (recommended distribution — no clone, no build):
```json
{
"mcpServers": {
"azure-devops": {
"command": "npx",
"args": ["-y", "ado-mcp-server"],
"env": {
"ADO_ORG": "YourOrgName",
"ADO_DEFAULT_PROJECT": "YourProject",
"AUTH_MODE": "pat",
"ADO_PAT": "<your-pat>"
}
}
}
}
```
**Local build via `node`** (for development on a clone):
```json
{
"mcpServers": {
"azure-devops": {
"command": "node",
"args": ["E:\\MCP Servers\\ado-mcp-server\\dist\\index.js"],
"env": {
"ADO_ORG": "YourOrgName",
"ADO_DEFAULT_PROJECT": "YourProject",
"AUTH_MODE": "azcli"
}
}
}
}
```
> The org is **never hardcoded** — it comes from `ADO_ORG` in the client's `env` block, so the same published package serves any org.
### Remote / hosted (Streamable HTTP)
```bash
node dist/index.js --transport http
```
Endpoint: `POST http://localhost:3000/mcp` · health: `GET /health`.
In `obo` mode every request must carry `Authorization: Bearer <Entra access token>`.
## 6. Verify it works
```bash
# Health (HTTP mode)
curl http://localhost:3000/health
# From an MCP client, call the connectivity probe tool:
# ado_get_me → confirms auth + org connection
# ado_list_projects
```
A scripted stdio smoke test (lists tools without calling ADO):
```bash
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke","version":"1.0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
| ADO_ORG=x AUTH_MODE=pat ADO_PAT=dummy node dist/index.js
```
## 7. Publishing (npx distribution)
This server is distributed as an npm package so anyone can run it with
`npx ado-mcp-server` — no clone or build on their side.
```bash
npm run build # compile (also runs automatically via prepublishOnly)
npm version patch # bump version
npm publish # publishes; only dist/, README.md, .env.example ship (see "files")
```
After publishing, the `npx` client config in §5 works as-is. To test the
package contents before publishing:
```bash
npm pack --dry-run # lists exactly what will be uploaded
npm pack # builds the .tgz locally; install it to smoke-test
```
> **Auth for distributed use:** prefer **`AUTH_MODE=pat`** — each user supplies
> their own `ADO_PAT` (and `ADO_ORG`) in their MCP client's `env`. `azcli` only
> works where the user has the Azure CLI installed and `az login` completed.
## 8. Scripts
| Script | Purpose |
|---|---|
| `npm run build` | Compile TypeScript → `dist/` |
| `npm start` | Run compiled server (stdio) |
| `npm run start:http` | Run compiled server (HTTP) |
| `npm run dev` / `dev:http` | Watch-mode dev (tsx) |
| `npm run typecheck` | `tsc --noEmit` |
| `npm run lint` | ESLint |
| `npm test` | Vitest |
## 9. Configuration reference
See [.env.example](.env.example). Key vars: `ADO_ORG`, `ADO_DEFAULT_PROJECT`, `ADO_API_VERSION`, `AUTH_MODE`, `ADO_PAT`, `AZURE_TENANT_ID/CLIENT_ID/CLIENT_SECRET`, `TRANSPORT`, `PORT`, `LOCAL_ROLE`, `LOG_LEVEL`, `ALLOW_DESTRUCTIVE`.
- **`ALLOW_DESTRUCTIVE`** — destructive tools (`delete_*`, complete PR, deploy release, …) are blocked unless this is `true`.
- **`LOCAL_ROLE`** — effective RBAC role in `pat`/`azcli` modes (`admin`/`editor`/`viewer`). In `obo` mode roles come from Entra App Roles on the caller's token.
## 10. Architecture (short)
```
transport (stdio | http)
→ server (McpServer + registry)
→ dispatch (RBAC · destructive guard · audit · error envelope)
→ domain tools (Zod schemas)
→ domain services
→ AdoClient (azure-devops-node-api SDK | REST fallback + retry)
→ auth (PAT | AzCli | OBO credential)
```
Each ADO area is a self-contained module under `src/domains/<area>/` exporting a `DomainModule`. To add an area, create the module and append it to `domains` in [src/server.ts](src/server.ts) — nothing else changes.
**Full walkthrough:** see [docs/END_TO_END_FLOW.md](docs/END_TO_END_FLOW.md) for how a request travels through every layer (startup, a tool call step by step, auth flows, resources/prompts, reliability, and a worked example).
TDQS
Scored across 113 tools
Most tools have clearly distinct purposes, especially with well-defined descriptions for different resource types. However, a few pairs like 'ado_list_pipelines' vs 'ado_list_build_definitions' (YAML vs classic builds) could cause minor confusion without careful reading.
All tool names follow a strict 'ado_verb_noun' pattern in snake_case. Verbs are consistently imperative (list, get, create, update, delete) and nouns are descriptive (repo, branch, pr, work_item, pipeline, etc.). No naming convention deviations are present.
With 113 tools, the server is extremely comprehensive but far exceeds the typical well-scoped range (3-15). The high number makes it difficult for agents to efficiently navigate and choose the correct tool, and it would benefit from being split into multiple focused servers per Azure DevOps domain.
The tool surface covers an impressively broad range of Azure DevOps features: source control, pull requests, work items (with queries, comments, attachments, links), boards, sprints, backlogs, pipelines (YAML and classic), releases, test management, wikis, search, feeds, security, and analytics. Only niche areas like service connections or variable groups are missing, but the core workflows are fully supported.