@og-mcp/ado-mcp
v0.1.0
Published
Production-grade Model Context Protocol server for Azure DevOps (stdio + Streamable HTTP).
Downloads
158
Maintainers
Readme
Azure DevOps MCP Server
A production-grade Model Context Protocol 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-apiSDK, 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-triageHardening: 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 logincompleted, or - (hosted) an Entra app registration with the ADO delegated permission, for OBO
2. Install
cd "E:\MCP Servers\ado-mcp-server"
npm install3. Configure
cp .env.example .env # PowerShell: Copy-Item .env.example .envEdit .env. Minimum for a quick local start with the Azure CLI:
ADO_ORG=YourOrgName
ADO_DEFAULT_PROJECT=YourProject
AUTH_MODE=azcliAuth 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
npm run build # compile to dist/
npm start # stdio transport (default)Development with auto-reload:
npm run dev # stdio
npm run dev:http # Streamable HTTP on PORT (default 3000)Force a transport regardless of TRANSPORT:
node dist/index.js --transport http
node dist/index.js --transport stdio5. 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):
{
"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):
{
"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_ORGin the client'senvblock, so the same published package serves any org.
Remote / hosted (Streamable HTTP)
node dist/index.js --transport httpEndpoint: POST http://localhost:3000/mcp · health: GET /health.
In obo mode every request must carry Authorization: Bearer <Entra access token>.
6. Verify it works
# 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_projectsA scripted stdio smoke test (lists tools without calling ADO):
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.js7. 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.
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:
npm pack --dry-run # lists exactly what will be uploaded
npm pack # builds the .tgz locally; install it to smoke-testAuth for distributed use: prefer
AUTH_MODE=pat— each user supplies their ownADO_PAT(andADO_ORG) in their MCP client'senv.azclionly works where the user has the Azure CLI installed andaz logincompleted.
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. 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 istrue.LOCAL_ROLE— effective RBAC role inpat/azclimodes (admin/editor/viewer). Inobomode 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 — nothing else changes.
Full walkthrough: see 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).
