npm.io
1.5.9 • Published 5h agoCLI

@vunguyen/ado-mcp-server

Licence
MIT
Version
1.5.9
Deps
10
Size
331 kB
Vulns
0
Weekly
0

Azure DevOps MCP Server

A Model Context Protocol (MCP) server for Azure DevOps Work Item Tracking, enabling AI Agents (Claude Code, Cursor, OpenCode, Antigravity) to interact with Azure DevOps directly.

Version: 1.0.0
Status: Stable
Last Updated: 2026-07-19

Features

  • MCP Tool Interface - 19 tools for work item management, state transitions, and backlog queries
  • Secure Credential Management - Encrypted storage of PAT and NTLM credentials
  • Schema-Agnostic - Dynamically discovers and adapts to any Azure DevOps process template
  • Intelligent State Transitions - Semantic actions (start/review/complete/block) map to actual states
  • Markdown Content - AI Agent provides Markdown; server converts to HTML automatically
  • Single-User Local - Runs as a local process per user, no multi-tenant overhead
  • Smart Caching - 1-hour schema cache reduces API calls to Azure DevOps
  • Rate Limiting - Throttling and retry logic for Azure DevOps API limits

Installation

Prerequisites
  • Node.js 18+
  • npm or yarn
  • Access to Azure DevOps Server 2022 (on-prem) or Azure DevOps Services (cloud)
  • Personal Access Token (PAT) or NTLM credentials
Quick Start
# Install globally via npm
npx @vunguyen/ado-mcp-server

# Or install locally
npm install @vunguyen/ado-mcp-server
npx ado-mcp-server

The server will:

  1. Start MCP server on stdio - Ready for AI Agent clients (Claude Code, Cursor, etc.)
  2. Start Config UI - Available at http://localhost:7939 for profile management
Configuration in AI Agent
Claude Code

Add to ~/.claude/mcp.json:

{
  "ado-mcp": {
    "command": "npx",
    "args": ["@vunguyen/ado-mcp-server"]
  }
}

Then configure MCP in Claude Code settings.

Cursor, OpenCode, Antigravity

Similar process - add MCP configuration pointing to:

npx @vunguyen/ado-mcp-server

Configuration

Step 1: Add Connection Profile
  1. Open Config UI: http://localhost:7939

  2. Fill in connection details:

    • Profile Name: Name to reference this connection (e.g., "My Azure DevOps")
    • Base URL:
      • Cloud: https://dev.azure.com/myorgname
      • On-prem: https://tfs.mycompany.com
    • Collection (on-prem only): Usually DefaultCollection
    • Default Project: Optional, used as fallback
    • Auth Type: PAT or NTLM
    • Credential:
      • PAT: Your personal access token
      • NTLM: username:password
  3. Test Connection to verify credentials are valid

Step 2: Use in AI Agent

When AI Agent calls MCP tools, include profile parameter:

get_work_item(profile="My Azure DevOps", id=123)

Tool Reference

Profile Management (REST API)

These are configured via the Config UI, not MCP tools.

  • GET /api/profiles - List all profiles
  • POST /api/profiles - Create new profile
  • POST /api/profiles/{id}/test - Test connection
  • DELETE /api/profiles/{id} - Delete profile
MCP Tools for AI Agent
Read Operations
  • get_work_item(profile, id, includeRelations?, includeComments?) - Get work item details
  • query_work_items(profile, project?, wiql) - Free-form WIQL query (fallback)
  • get_backlog(profile, project, team, backlogLevel) - Get prioritized backlog
  • list_work_items_by_type(profile, project, workItemTypes[], ...) - Predefined query
  • get_remaining_work(profile, project, team, iterationPath?) - Calculate sprint metrics
  • list_my_work_items(profile, project, assignedTo, ...) - Personal work items
Create Operations
  • create_work_item(profile, project, workItemType, title, description, acceptanceCriteria, ...)

    • description and acceptanceCriteria are required
    • Server auto-converts Markdown → HTML
    • Validates required markdown headings
  • create_bug(profile, project, title, reproSteps, acceptanceCriteria, description, ...)

    • All 4 parameters required (CN-13)
    • Separate fields for repro steps vs. acceptance criteria
    • Description must include risk/mitigation heading
State Management (Semantic - Preferred)
  • start_work(profile, id, comment?) → Moves to InProgress (CN-15)
  • mark_in_review(profile, id, comment?) → Moves to Resolved (CN-15)
  • complete_work(profile, id, comment?) → Moves to Completed (CN-15)
  • reopen_work(profile, id, comment?) → Moves back to InProgress (CN-15)
  • block_work(profile, id, reason) → Adds [BLOCKED] comment, no state change (CN-15)
State Management (Fallback)
  • update_work_item(profile, id, fields) - Direct field update (CN-08)
  • report_progress(profile, id, state?, comment) - State + comment (CN-09)
Bug Resolution
  • resolve_bug(profile, id, resolution, comment?) - Set resolution reason (Fixed, Duplicate, As Designed, Won't Fix, Cannot Reproduce)
  • close_bug(profile, id, comment?) - Close completed bug
Relationships
  • link_work_items(profile, sourceId, targetId, linkType, force?) - Parent-child or related links

Architecture

Layered Design
Transport Layer (stdio + REST)
    ↓
Tool Handler Layer (19 MCP tools + Config UI)
    ↓
Domain Layer (Business Logic - State Machine, Validation)
    ↓
Infrastructure Layer (Azure DevOps Client, Config Store, Caching)
Data Storage
  • Config Store (~/.ado-mcp-server/config.json): Encrypted connection profiles
  • Schema Cache (in-memory, 1-hour TTL): Work item types, fields, states, transitions
  • Idempotency Cache (in-memory, 24-hour TTL): Prevents duplicate tool calls
  • Logs (~/.ado-mcp-server/logs/): Audit trail (no credentials logged)
Key Behaviors
Behavior Details
Rate Limiting 5-second minimum between tool calls per profile; auto-sleep 60s on HTTP 429
Schema Agnostic No hardcoded field/type/state names - all discovered dynamically
Profile Required Every tool call must specify profile explicitly (no "active" profile)
Markdown → HTML AI Agent provides Markdown; server converts before sending to Azure DevOps
Retry Logic Up to 5 retries for failed comment additions; automatic retry on rate limit
Error Messages Azure DevOps errors passed through verbatim; server errors are sanitized

Troubleshooting

Connection Failed (401/403)

401 Unauthorized:

  • PAT: Verify token is valid and hasn't expired
  • NTLM: Verify username/password is correct for your domain

403 Forbidden:

  • Your user account lacks permissions for the specified project/work item
  • Request appropriate permissions from your Azure DevOps administrator
Connection Failed (404)
  • Cloud: Verify base URL format is https://dev.azure.com/myorgname (not .com)
  • On-prem: Verify collection name (usually DefaultCollection)
  • Verify project name is spelled correctly
SSL Certificate Error (on-prem)

If using a self-signed certificate:

  1. In Config UI, enable "Allow Self-Signed SSL Certificates"
  2. Understand the security implications: only enable for trusted internal servers
Rate Limit (HTTP 429)

The server automatically handles rate limiting:

  • Sleeps 60 seconds when encountering 429
  • Retries the failed request
  • If still persistent, reduce frequency of tool calls
Credentials Not Saved
  • Ensure Config UI can write to ~/.ado-mcp-server/
  • Check file permissions: ls -la ~/.ado-mcp-server/
  • Review logs in ~/.ado-mcp-server/logs/

Logs

Logs are written to ~/.ado-mcp-server/logs/:

  • ado-mcp-YYYY-MM-DD.log - Info and debug level
  • error-YYYY-MM-DD.log - Errors only

Log Rotation: Automatically rotates when file exceeds 10MB; keeps 5 days of history.

Setting Log Level
LOG_LEVEL=debug npx @vunguyen/ado-mcp-server

Levels: error, warn, info, debug

Security Considerations

What We Do:

  • Encrypt credentials at rest using AES-256-CBC with local encryption key
  • Never log credentials, even in error cases
  • Bind Config UI to localhost only (127.0.0.1)
  • Use official Azure DevOps SDK for all API calls
  • Validate all inputs before passing to Azure DevOps

What You Should Do:

  • Don't share PAT tokens - treat them like passwords
  • For NTLM, ensure your machine is on a secure network
  • Regularly rotate PAT tokens (every 90 days recommended)
  • Don't enable "Allow Self-Signed Cert" unless on trusted internal network
  • Backup ~/.ado-mcp-server/ if switching machines

What We Don't Do:

  • Multi-tenant isolation (single-user per instance)
  • Network-level authentication (beyond credential in profile)
  • Audit logging of AI Agent actions (log is local only)

Development

Local Setup
# Install dependencies
npm install

# Type checking
npm run type-check

# Build
npm run build

# Run in development
npm run dev

# Run tests
npm run test
npm run test:coverage

# Lint
npm run lint
Project Structure
source/
├── src/
│   ├── bin/
│   │   └── index.ts              # Entry point
│   ├── domain/
│   │   ├── stateMachine.ts       # State transition logic (CN-15)
│   │   ├── workItemRules.ts      # Validation rules (CN-06, CN-13)
│   │   └── profileResolver.ts    # Profile resolution (CN-11)
│   ├── handlers/
│   │   ├── toolHandler.ts        # Base class for all tools
│   │   ├── toolRegistry.ts       # Tool definitions
│   │   ├── mcp/                  # Individual tool implementations
│   │   └── rest/                 # Config UI REST endpoints
│   ├── infra/
│   │   ├── adoClient.ts          # Azure DevOps API wrapper
│   │   ├── configStore.ts        # Profile storage & encryption
│   │   ├── schemaCache.ts        # Schema caching
│   │   ├── markdownConverter.ts  # Markdown → HTML
│   │   ├── rateLimiter.ts        # Rate limiting
│   │   ├── logger.ts             # Logging
│   │   └── exceptionHandler.ts   # Error handling
│   ├── mcp/
│   │   └── server.ts             # MCP server setup
│   ├── ui/
│   │   ├── server.ts             # Config UI Express app
│   │   └── public/               # Static HTML/JS
│   └── types/
│       └── index.ts              # Type definitions
├── package.json
├── tsconfig.json
├── vitest.config.ts
└── README.md
Adding a New Tool
  1. Create handler in src/handlers/mcp/myTool.ts:
import { ToolHandler } from '../toolHandler';
import { ToolInput, ToolResult } from '@types/index';

export class MyToolHandler extends ToolHandler {
  name = 'my_tool';

  protected async handle(input: ToolInput, profile: any): Promise<ToolResult> {
    // Implementation
    return { success: true, data: {} };
  }
}
  1. Add tool definition to src/handlers/toolRegistry.ts
  2. Register in src/mcp/server.ts
  3. Write tests in src/handlers/mcp/__tests__/myTool.test.ts

API Versioning

This server targets:

  • Azure DevOps REST API 7.0 (main endpoints)
  • Azure DevOps Comments API 7.0-preview.3 (on-prem Server 2022)
  • Azure DevOps Work Item Tracking API 7.0

Cloud instances may use different preview versions for Comments API - the SDK abstracts this difference.

Performance

Operation Target SLA Typical
Read (get, query) < 3s 1-2s
Write (create, update) < 5s 2-4s
Batch (50 items) < 15s 8-12s
Schema cache hit < 50ms 10-20ms
First schema load (cache miss) < 3s 1-2s

Support

For issues or questions:

  1. Check the logs: ~/.ado-mcp-server/logs/
  2. Enable debug logging: LOG_LEVEL=debug npx @vunguyen/ado-mcp-server
  3. Review documentation in /docs/

License

MIT

References

Keywords