Azure DevOps MCP Server (Python)
by trosinde
README.md
# Azure DevOps MCP Server (Python)
Model Context Protocol (MCP) server for Azure DevOps integration, enabling AI assistants (Claude Desktop, OpenCode.ai) to interact with work items, test results, Git repositories, and analyze work item dependencies.
**Supported Platforms:**
- ✅ [Claude Desktop](https://claude.ai/desktop) - Anthropic's desktop application
- ✅ [OpenCode.ai](https://opencode.ai) - Terminal-based AI coding agent
## Features
- **Work Items**: Get work items by ID, query with filters, execute WIQL queries
- **Saved Queries**: Execute saved Azure DevOps queries by ID
- **Dependency Analysis**: Analyze work item relationships and dependencies
- **Test Results**: Access test runs and test results
- **Git Repositories**: Browse repositories, commits, and pull requests
- **WIQL Support**: Build and execute custom Work Item Query Language queries
- **Generic Deployment**: Works with cloud and on-premise Azure DevOps (SSL verification disabled by default)
- **Multi-Project Support**: Configure multiple Azure DevOps project base URLs and select per tool invocation
- **Project Enumeration**: `list_projects` tool returns configured shortnames and base URLs
- **Request Timeout**: Optional `timeout` in AZDO_CONFIG (seconds) to bound network calls
## Quick Start (Automated Installation)
### Prerequisites
- Python 3.8 or higher
- Claude Desktop installed
- Azure DevOps Personal Access Token (PAT) with permissions:
- Work Items: Read
- Code: Read
- Test: Read
### Install
Run the installation script with PowerShell:
```powershell
./install.ps1
```
You will be prompted to enter your Azure DevOps Personal Access Token. The script will:
- Install Python dependencies
- Backup your existing Claude Desktop configuration
- Add the MCP server to your configuration
- Create (or reuse) a unified JSON configuration file referenced by `AZDO_CONFIG`
**Parameters:**
| Parameter | Description | Example |
|-----------|-------------|---------|
| `-Projects` | Semicolon-separated `shortname=baseUrl` pairs (baseUrl must include project path) | `"default=https://dev.azure.com/Org/ProjectA;neo=https://dev.azure.com/Org/ProjectNeo"` |
| `-Pat` | Personal Access Token (if omitted you will be prompted) | `"azdopat123"` |
| `-PythonPath` | Python executable to use | `"python"` |
| `-ConfigPath` | Path for generated AZDO config file (optional) | `"C:\path\azure_devops_config.json"` |
**Custom Configuration Example:**
```powershell
./install.ps1 -Projects "default=https://dev.azure.com/Org/ProjectA;neo=https://dev.azure.com/Org/ProjectNeo" -Pat "your-pat-token" -PythonPath "python" -ConfigPath "C:\path\azure_devops_config.json"
```
### Uninstall
```powershell
./uninstall.ps1
```
Removes the server from Claude Desktop and creates a timestamped backup of the config. By default the AZDO_CONFIG file containing project definitions and PATs is retained.
Optional removal of AZDO_CONFIG:
```powershell
./uninstall.ps1 -RemoveConfig
```
When `-RemoveConfig` is supplied the script prompts for confirmation (must type YES) then attempts to delete the JSON file referenced by the server's `AZDO_CONFIG` environment entry (if it exists). Use this only if you no longer need the per-project PAT configuration.
## Setup for OpenCode.ai
[OpenCode](https://opencode.ai) is an AI coding agent for the terminal that supports MCP servers. You can add this Azure DevOps MCP server to OpenCode to interact with your Azure DevOps projects directly from your terminal.
### 1. Install Dependencies
```bash
pip install -r requirements.txt
```
### 2. Configure Azure DevOps Connection
Create your Azure DevOps configuration file (see [Configuration](#configuration) section below for details):
```bash
cp azure_devops_config.example.json azure_devops_config.json
# Edit azure_devops_config.json with your baseUrl and PAT
```
### 3. Add to OpenCode Configuration
Copy the example OpenCode configuration:
```bash
cp opencode.example.jsonc opencode.jsonc
```
Then edit `opencode.jsonc` and update the paths:
```jsonc
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"azure-devops": {
"type": "local",
"command": ["python", "/absolute/path/to/mcp_azure_devops/src/server.py"],
"enabled": true,
"environment": {
"AZDO_CONFIG": "/absolute/path/to/azure_devops_config.json",
"AZDO_LOG_LEVEL": "info"
},
"timeout": 10000
}
}
}
```
**Important**: Replace `/absolute/path/to/` with the actual absolute paths on your system.
### 4. Start OpenCode
Navigate to your project and start OpenCode:
```bash
cd /path/to/your/project
opencode
```
### 5. Use Azure DevOps Tools
You can now use Azure DevOps tools in your prompts:
```
List all configured Azure DevOps projects
```
```
Get work item 123 from the default project
```
```
Query by ID 02576c96-99fa-472b-8929-80b5f1760b02 and show the results
```
For better performance, you can configure OpenCode to only enable Azure DevOps tools for specific agents. See `opencode.example.jsonc` for examples.
## Manual Setup (Claude Desktop)
### 1. Install Dependencies
```bash
pip install -r requirements.txt
```
### 2. Configure Claude Desktop
Add the server configuration to your Claude Desktop config file:
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
```json
{
"mcpServers": {
"azure-devops": {
"command": "python",
"args": ["C:/path/to/mcp_azure_devops/src/server.py"],
"env": {
"AZDO_CONFIG": "C:/path/to/azure_devops_config.json"
}
}
}
}
```
Sample `azure_devops_config.json`:
```json
{
"projects": {
"iris": { "baseUrl": "https://dev.azure.com/Org/ProjectIris", "pat": "xxxxx" },
"neo": { "baseUrl": "https://dev.azure.com/Org/ProjectNeo", "pat": "yyyyy" }
},
"timeout": 15
}
```
**Important**:
- Update the path in `args` to match your installation directory
- Replace placeholder PATs with valid tokens (do NOT commit real PATs)
- Each `baseUrl` includes organization + project path (no trailing slash)
- Configuration is loaded exclusively from `AZDO_CONFIG`; legacy env vars (`AZURE_DEVOPS_BASE_URL`, `AZURE_DEVOPS_PAT`, etc.) are deprecated and ignored by the current implementation.
### Multi-Project Configuration (Per-Project PATs)
Multiple projects are defined exclusively via the `AZDO_CONFIG` JSON file (see above). Each project entry includes its own `baseUrl` and `pat`.
Key points:
- `baseUrl` must include the full organization + project path.
- `pat` must have scopes: Work Items Read, Code Read, Test Read.
- If `default` shortname exists it is used when `project` argument is omitted; else the first project is chosen.
- `timeout` (optional) applies uniformly to all requests.
To add a new project, edit `azure_devops_config.json` and restart Claude Desktop.
Claude tool call example (conceptual):
- "Get work item 123 from project neo" (internally sets `{ "project": "neo", "id": 123 }`)
- If no `project` is specified, the server uses `default` if present, else the first configured project.
### 3. Restart Claude Desktop
After adding the configuration, restart Claude Desktop to load the MCP server.
## Available Tools
All tools accept an optional `project` parameter (string shortname) unless noted otherwise.
### get_work_item
Get a work item by ID.
```
Parameters:
- project: (Optional) Project shortname
- id: Work item ID (number)
- fields: (Optional) Array of specific fields to retrieve
```
### query_by_id
Execute a saved query by its ID.
```
Parameters:
- project: (Optional) Project shortname
- queryId: Query ID (GUID format, e.g., "02576c96-99fa-472b-8929-80b5f1760b02")
- fields: (Optional) Specific fields to retrieve. If not provided, uses query's own columns
```
### get_linked_work_items
Get work items from a query and analyze their dependencies/links.
```
Parameters:
- project: (Optional) Project shortname
- queryId: Query ID (GUID format)
- linkType: (Optional) Filter by link type: "Children", "Parent", "Related", "Tested By"
- fields: (Optional) Specific fields to retrieve
Example: Get all tasks (children) linked to bugs from a query
```
### get_work_items_with_relations
Get work items with their relationship details (parent, children, related items, etc.).
```
Parameters:
- project: (Optional) Project shortname
- ids: Array of work item IDs
- fields: (Optional) Specific fields to retrieve
```
### query_work_items
Query work items using field filters.
```
Parameters:
- project: (Optional) Project shortname
- fields: Array of field names to return (e.g., ["System.Id", "System.Title"])
- filters: Object with filter conditions (e.g., {"System.State": "Active"})
- top: Maximum number of results (default: 50)
```
### execute_wiql
Execute a custom WIQL query.
```
Parameters:
- project: (Optional) Project shortname
- wiql: WIQL query string
Example: "SELECT [System.Id], [System.Title] FROM WorkItems WHERE [System.WorkItemType] = 'Bug'"
```
### get_test_runs
Get recent test runs.
```
Parameters:
- project: (Optional) Project shortname
- top: Maximum number of test runs to return (default: 10)
```
### get_test_results
Get test results for a specific test run.
```
Parameters:
- project: (Optional) Project shortname
- runId: Test run ID (number)
```
### get_repositories
Get all Git repositories in the project.
```
Parameters:
- project: (Optional) Project shortname
```
### get_commits
Get commits from a Git repository.
```
Parameters:
- project: (Optional) Project shortname
- repositoryId: Repository ID or name
- top: Maximum number of commits (default: 20)
```
### get_pull_requests
Get pull requests from a Git repository.
```
Parameters:
- project: (Optional) Project shortname
- repositoryId: Repository ID or name
- status: PR status filter (active, completed, abandoned, all) (default: active)
```
### list_projects
List configured project shortnames and their base URLs.
```
Parameters:
(none)
Returns: Array of { shortname, baseUrl }
Example: "List configured Azure DevOps projects"
```
### ping
Health check summarizing server configuration.
```
Parameters:
(none)
Returns JSON object:
{
"serverVersion": "1.0.0",
"projects": [ { "shortname": "default", "baseUrl": "https://dev.azure.com/Org/ProjectA" }, ... ],
"timeout": 15,
"timestamp": "2025-11-03T12:34:56.789012Z"
}
```
Example prompt: "Ping the Azure DevOps server" or "Health check"
## Usage Examples
Once configured, you can use natural language to interact with Azure DevOps:
### Work Items & Queries
- "Query by ID 02576c96-99fa-472b-8929-80b5f1760b02 and create a table"
- "Get work item 100"
- "Show me all active bugs"
- "Query work items where System.State is Active"
- "In project iris get work item 200"
### Dependency Analysis
- "Give me all tasks linked to work items from query id a5ff7f63-ea7b-4b2e-9528-61513f744570"
- "Show me all children of work items from query [query-id] in project neo"
- "Analyze dependencies for work items 100, 200, 300"
### Test Results
- "Get the latest test runs"
- "Show me test results for run 456 in project iris"
### Git Operations
- "List all Git repositories"
- "Show recent commits in repository MyRepo"
- "Get active pull requests in MyRepo for project neo"
### Project Enumeration
- "List configured Azure DevOps projects"
- "Show projects"
### OpenCode-Specific Examples
When using OpenCode, you can also add instructions to your `AGENTS.md` file to automatically use Azure DevOps tools:
**AGENTS.md:**
```markdown
## Azure DevOps Integration
When working with work items, bugs, or tasks:
- Use Azure DevOps tools to query work items
- Use `list_projects` to see available projects
- Use `get_linked_work_items` for dependency analysis
When analyzing test failures:
- Use `get_test_runs` to see recent test executions
- Use `get_test_results` to investigate specific test failures
```
**Example OpenCode Prompts:**
- "Show me all bugs assigned to me in the current sprint"
- "Analyze the test failures from the last 5 test runs"
- "Create a dependency graph for work item 456 showing all parent and child items"
- "List all active pull requests in the MyRepo repository and summarize their status"
## Configuration
### JSON + Optional .env Overlay
Primary configuration remains the JSON file referenced by `AZDO_CONFIG`. Optionally you can supply or override project entries via environment variables or a `.env` file without editing the JSON (useful for keeping secrets out of tracked files).
Activation methods:
- Set `AZDO_USE_ENV=1` (process env) OR
- Set `AZDO_ENV_PATH` to a custom dotenv file path (e.g. `C:\secrets\azuredevops.env`). If present this also activates overlay.
- Default dotenv path is `./.env` if it exists.
Variable naming pattern (case sensitive):
```
AZDO_PROJECT_<SHORTNAME>_BASE_URL=https://dev.azure.com/Org/ProjectPath
AZDO_PROJECT_<SHORTNAME>_PAT=your_pat_token_here
AZDO_TIMEOUT=20 # optional timeout override in seconds
```
Example `.env`:
```
# Azure DevOps MCP server secrets (DO NOT COMMIT)
AZDO_PROJECT_default_BASE_URL=https://dev.azure.com/Org/ProjectA
AZDO_PROJECT_default_PAT=pat_default_secret
AZDO_PROJECT_neo_BASE_URL=https://dev.azure.com/Org/ProjectNeo
AZDO_PROJECT_neo_PAT=pat_neo_secret
AZDO_TIMEOUT=25
```
Behavior:
- Overlay project entries override same shortnames from JSON.
- Shortname discovery is based on matching both `BASE_URL` and `PAT` variables; partial definitions are ignored.
- Trailing slashes are trimmed automatically.
- Timeout override uses `AZDO_TIMEOUT` if numeric.
- Final configuration must contain at least one valid project (baseUrl + pat) or startup exits.
Security:
- Root `.env` template is committed (contains only placeholders) while other secret variants remain ignored.
- Never commit real PAT values; replace placeholders locally or use a non-tracked `.env.local` file or system environment.
Below is the original JSON-only description for reference (now extended for overlay-only mode):
The server loads configuration primarily from `AZDO_CONFIG` (path to JSON file). Legacy environment variables (`AZURE_DEVOPS_BASE_URL`, `AZURE_DEVOPS_PAT`, `AZURE_DEVOPS_PROJECTS_FILE`, `AZURE_DEVOPS_PROJECTS`, `AZURE_DEVOPS_TIMEOUT`) are deprecated and ignored.
Required file structure (JSON base):
```json
{
"projects": {
"shortname": { "baseUrl": "https://dev.azure.com/Org/ProjectPath", "pat": "your-pat" }
},
"timeout": 15
}
```
Overlay-only minimal example (all real data provided via environment / .env):
```json
{
"projects": {},
"timeout": 15
}
```
- `projects` must be a non-empty object unless overlay is active (AZDO_USE_ENV=1 or AZDO_ENV_PATH set) and supplies valid project entries.
- Each project (from JSON or overlay) must include `baseUrl` and `pat`.
- `timeout` is optional (seconds).
### SSL Configuration
The server supports both cloud and on-premise Azure DevOps instances. SSL verification is disabled by default (`verify=False`) to ensure compatibility across different environments. Users deploying in highly secure environments can implement certificate pinning separately if needed.
### Structured Logging
The server supports optional structured JSON logging to stderr for debugging and monitoring. Logging is controlled by the `AZDO_LOG_LEVEL` environment variable.
**Log Levels:**
- `none` (default): No logging output
- `info`: Log tool invocations with timestamp, tool name, project, duration, and success/error status
- `debug`: Include all info-level data plus sanitized tool parameters
**Configuration:**
Add `AZDO_LOG_LEVEL` to the server environment in Claude Desktop config:
```json
{
"mcpServers": {
"azure-devops": {
"command": "python",
"args": ["C:/path/to/mcp_azure_devops/src/server.py"],
"env": {
"AZDO_CONFIG": "C:/path/to/azure_devops_config.json",
"AZDO_LOG_LEVEL": "info"
}
}
}
}
```
**Log Format (JSON to stderr):**
```json
{
"timestamp": "2025-11-03T12:34:56.789012Z",
"level": "INFO",
"tool": "get_work_item",
"project": "default",
"duration_ms": 123.45,
"status": "success",
"error": null,
"params": {...}
}
```
**Viewing Logs:**
On Windows, logs are written to:
```
%APPDATA%\Claude\logs\mcp-server-azure-devops.log
```
On macOS:
```
~/Library/Logs/Claude/mcp-server-azure-devops.log
```
**Notes:**
- Logging writes to stderr and does not interfere with MCP stdio protocol
- Sensitive data (PAT) is never logged
- Logging errors never crash the server
- Use `info` level for production monitoring
- Use `debug` level for troubleshooting (includes request parameters)
## Security Notes
⚠️ **Important**:
- Your PAT (Personal Access Token) is stored in the Claude Desktop configuration file
- Ensure this file has appropriate permissions and is not shared or committed to version control
- The installation script creates automatic backups of your Claude Desktop configuration
- Backups are stored in `%APPDATA%\Claude\` with timestamps
## Testing
Set the `AZDO_CONFIG` environment variable before running tests:
**Windows (PowerShell):**
```powershell
$env:AZDO_CONFIG = "C:\path\azure_devops_config.json"
python tests/test_client.py
```
**macOS/Linux (bash):**
```bash
export AZDO_CONFIG=/path/azure_devops_config.json
python tests/test_client.py
```
### Run All Tests
```bash
python tests/test_client.py
```
### Test Dependency Analysis
```bash
python tests/test_dependencies.py
```
### Multi-Project Integration Test
```bash
python tests/test_integration.py
```
### Manual Testing
Test specific queries:
```bash
python tests/test_dependencies.py
```
## Troubleshooting
### Server not showing in Claude Desktop
1. Check if Claude Desktop config is valid JSON
2. Verify the path to `src/server.py` is correct
3. Check Claude Desktop logs: `%APPDATA%\Claude\logs\mcp-server-azure-devops.log`
4. Restart Claude Desktop
### 401 Authentication Error
1. Verify your PAT is valid and not expired
2. Ensure PAT has required permissions (Work Items: Read, Code: Read, Test: Read)
3. Check if you can access the Azure DevOps URL in your browser
### SSL Issues
1. Verify you can access the Azure DevOps URL directly in a browser
2. Check firewall/proxy settings if behind a corporate network
3. SSL verification is disabled by default; if you need certificate pinning, implement it separately
### Query by ID not working
1. Verify the query ID is correct (GUID format)
2. Ensure you have access to the query in Azure DevOps
3. Check if the query exists in the specified project
### ImportError or Module Not Found
1. Ensure all dependencies are installed: `pip install -r requirements.txt`
2. Verify Python version is 3.8 or higher: `python --version`
### OpenCode.ai Issues
#### MCP Server Not Loading
1. Check that paths in `opencode.jsonc` are absolute paths
2. Verify `AZDO_CONFIG` path points to a valid configuration file
3. Check OpenCode logs: Run `opencode` with increased verbosity
4. Ensure Python is in your PATH: `which python` or `where python`
#### Tools Not Available
1. Verify the MCP server is enabled: `"enabled": true` in `opencode.jsonc`
2. Check if tools are disabled globally in the `tools` section
3. Restart OpenCode after configuration changes
#### High Token Usage
1. Consider disabling Azure DevOps tools globally and enabling per-agent
2. Use the `/undo` command if a tool returns too much data
3. Be specific in your prompts to target specific work items or queries
## Project Structure
```
mcp_azure_devops/
├── src/
│ ├── server.py # MCP server implementation
│ ├── config.py # Unified config loader (AZDO_CONFIG)
│ ├── logging_utils.py # Structured JSON logging
│ └── client.py # Azure DevOps REST API client
├── tests/
│ ├── test_client.py # Tool invocation tests
│ ├── test_dependencies.py # Dependency analysis tests
│ ├── test_integration.py # Multi-project integration tests
│ ├── test_logging.py # Logging functionality tests
│ ├── test_mock.py # Offline mock data tests
│ ├── test_ping.py # Health check tests
│ └── test_mock_client.py # Mock client for testing
├── reviews/
│ ├── README.md # Review process documentation
│ └── YYYYMMDD_HHMMSS_*.md # Timestamped review documents
├── azure_devops_config.example.json # Example Azure DevOps configuration
├── azure_devops_config.json # User configuration (gitignored)
├── opencode.example.jsonc # Example OpenCode.ai configuration
├── install.ps1 # Installation script (Claude Desktop)
├── uninstall.ps1 # Uninstallation script (Claude Desktop)
├── requirements.txt # Python dependencies
├── .env # Environment variable template
├── .gitignore
├── CONTEXT.md # Requirements documentation
└── README.md # This file
```
## Development
Based on proven Azure DevOps client code from the DvoiPad project, ensuring reliability and compatibility with enterprise Azure DevOps instances.
## License
MIT
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues