AzureDevOpsServer.Mcp
0.1.2
{ "inputs": [ { "type": "promptString", "id": "ADOS_COLLECTION_URL", "description": "Full Azure DevOps Server collection URL, e.g. https://devops.example.local/DefaultCollection" }, { "type": "promptString", "id": "ADOS_PAT", "description": "Personal Access Token used for all REST calls", "password": true }, { "type": "promptString", "id": "ADOS_DEFAULT_PROJECT", "description": "Default project used when a tool call does not specify one" }, { "type": "promptString", "id": "ADOS_API_VERSION", "description": "Override of the REST API version, defaults to 7.0" } ], "servers": { "AzureDevOpsServer.Mcp": { "type": "stdio", "command": "dnx", "args": ["AzureDevOpsServer.Mcp@0.1.2", "--yes"], "env": { "ADOS_COLLECTION_URL": "${input:ADOS_COLLECTION_URL}", "ADOS_PAT": "${input:ADOS_PAT}", "ADOS_DEFAULT_PROJECT": "${input:ADOS_DEFAULT_PROJECT}", "ADOS_API_VERSION": "${input:ADOS_API_VERSION}" } } } }
.vscode/mcp.json settings file.
dotnet tool install --global AzureDevOpsServer.Mcp --version 0.1.2
dotnet new tool-manifest
dotnet tool install --local AzureDevOpsServer.Mcp --version 0.1.2
#tool dotnet:?package=AzureDevOpsServer.Mcp&version=0.1.2
nuke :add-package AzureDevOpsServer.Mcp --version 0.1.2
AzureMCP
MCP (Model Context Protocol) server for Azure DevOps Server (on-premises), built with .NET 10 / C# on top of the official ModelContextProtocol C# SDK and distributed as a NuGet package.
Status: preview — available on NuGet.org as AzureDevOpsServer.Mcp.
Why
Most existing MCP integrations for Azure DevOps target Azure DevOps Services (cloud). This project focuses on on-premises Azure DevOps Server installations (2019 / 2020 / 2022+): collection URLs, REST API versions supported by on-prem servers, and Personal Access Token (PAT) authentication — including classic TFS behaviors such as sign-in page responses on failed authentication.
Tools
62 tools across 9 areas:
| Area | Tools |
|---|---|
| Server | server_info |
| Projects | list_projects, get_project |
| Work items | query_work_items, get_work_item, get_work_items, get_work_item_revisions, create_work_item, update_work_item, add_work_item_comment, get_work_item_comment, list_work_item_comments, link_work_item, add_work_item_attachment |
| Queries & metadata | list_queries, run_saved_query, list_work_item_types, list_work_item_states, list_iterations, list_areas |
| Repositories | list_repositories, list_branches, get_file_content, list_commits, get_commit, list_repository_items, diff_branches |
| Pull requests | list_pull_requests, list_my_pull_requests, get_pull_request, create_pull_request, get_pull_request_changes, get_pull_request_policies, list_pull_request_work_items, link_pull_request_to_work_item, list_pull_request_threads, add_pull_request_comment, reply_to_pull_request_thread, update_pull_request_comment, set_pull_request_thread_status, vote_on_pull_request, update_pull_request, update_pull_request_status, add_pull_request_reviewer, remove_pull_request_reviewer |
| Builds | list_build_definitions, list_builds, queue_build, get_build_timeline, get_build_log, list_build_artifacts |
| Releases | list_release_definitions, list_releases, get_release, create_release, list_release_approvals, update_release_approval, deploy_release_environment |
| Wiki | list_wikis, list_wiki_pages, get_wiki_page, create_or_update_wiki_page |
get_pull_request and both listing tools return reviewer votes, merge status, and draft state, so questions like "who approved this and can it merge?" are answered without extra calls.
Tools that operate inside a project fall back to ADOS_DEFAULT_PROJECT when no project is given. Every tool carries MCP annotations (readOnlyHint / destructiveHint), so clients can require confirmation only where it matters, and all HTTP calls go through a standard resilience pipeline with retries and timeouts.
Trimming the tool list
62 tools is a lot for one client to carry, and clients cap how many tools they send per request. Two variables keep the surface small:
ADOS_TOOLSETS=workitems,pullrequestsexposes only the areas a team actually uses — the example above drops the list from 62 tools to 29.ADOS_READ_ONLY=trueremoves every write tool, leaving 41 read-only tools. Useful when an agent should be able to look at Azure DevOps but not change it, without relying on PAT scopes alone.
Both can be combined, and an unknown toolset name fails at startup with the list of valid names instead of silently exposing the wrong tools.
The server also sends MCP instructions on connect: the default project, whether it runs read-only, and how to use the tools well (field lists for work items, timeline before logs, raising limits instead of assuming something is missing). Tools publish output schemas, so clients receive structured results rather than opaque JSON, and failures carry the Azure DevOps error message instead of the raw error envelope.
Responses are bounded so a single call cannot flood an agent's context: build logs and file contents are capped (30 000 characters by default) and report their total length and whether they were truncated, binary files are detected instead of dumped, list tools take an explicit limit, and work item tools accept a field list instead of returning every field.
Prompts
Ready-made workflows that chain the tools:
| Prompt | What it does |
|---|---|
review_pull_request |
Reads the pull request, its changed files, and existing threads, then reports findings by severity |
diagnose_build_failure |
Walks the build timeline to the failing task and reads the relevant part of its log |
sprint_status |
Finds the current iteration and summarizes states, blockers, and risks |
Requirements
- .NET 10 SDK
- A reachable Azure DevOps Server (on-premises) collection URL
- A PAT created in that collection, with the minimal scopes required for the tools you use
Setting up from scratch on a new machine
1. Install prerequisites
- .NET 10 SDK —
winget install Microsoft.DotNet.SDK.10on Windows, or download from dotnet.microsoft.com; verify withdotnet --list-sdks - Git — only needed while running from source
2. Create a PAT on your Azure DevOps Server
- Open your collection in a browser and sign in
- Click your avatar → Security → Personal access tokens → New Token
- Pick a short expiration and only the scopes you need:
- Work Items — Read & write (queries, details, create/update/comment)
- Code — Read & write (repositories, file content, pull requests; Read is enough without
create_pull_request) - Build — Read & execute (definitions, builds; Read is enough without
queue_build)
- Copy the token immediately — it is shown only once
3. Get the server
Option A — from NuGet (recommended): nothing to download manually; the MCP client fetches and runs the published package via dnx AzureDevOpsServer.Mcp --yes on first start.
Option B — from source (for development):
git clone https://github.com/eXoz00rd/AzureMCP.git
cd AzureMCP
dotnet build AzureDevOpsServer.Mcp.slnx
dotnet run --project tests/AzureDevOpsServer.Mcp.Tests
4. Configure your MCP client
Use one of the configurations from Usage below — VS Code Copilot (.vscode/mcp.json), Visual Studio (.mcp.json), or any other MCP-capable client. For Claude Code:
claude mcp add azure-devops-server -e ADOS_COLLECTION_URL=https://devops.example.local/DefaultCollection -e ADOS_PAT=YOUR_PAT -- dnx AzureDevOpsServer.Mcp --yes
5. Verify
Ask the agent to call server_info or to "list projects on our DevOps server". The server refuses to start when ADOS_COLLECTION_URL or ADOS_PAT is missing and logs the exact reason to stderr, so a misconfigured client fails fast with a clear message.
Usage
The server runs directly from the published NuGet package via dnx. Example MCP client configuration (Claude Code, VS Code, etc.):
{
"mcpServers": {
"azure-devops-server": {
"command": "dnx",
"args": ["AzureDevOpsServer.Mcp", "--yes"],
"env": {
"ADOS_COLLECTION_URL": "https://devops.example.local/DefaultCollection",
"ADOS_PAT": "${env:ADOS_PAT}"
}
}
}
}
Running from source
{
"mcpServers": {
"azure-devops-server": {
"command": "dotnet",
"args": ["run", "--project", "D:/Projects/AzureMCP/src/AzureDevOpsServer.Mcp"],
"env": {
"ADOS_COLLECTION_URL": "https://devops.example.local/DefaultCollection",
"ADOS_PAT": "${env:ADOS_PAT}"
}
}
}
}
GitHub Copilot in VS Code
Create
.vscode/mcp.jsonin your workspace (or run theMCP: Add Servercommand):{ "inputs": [ { "id": "ados-pat", "type": "promptString", "description": "Azure DevOps Server Personal Access Token", "password": true } ], "servers": { "azure-devops-server": { "type": "stdio", "command": "dnx", "args": ["AzureDevOpsServer.Mcp", "--yes"], "env": { "ADOS_COLLECTION_URL": "https://devops.example.local/DefaultCollection", "ADOS_PAT": "${input:ados-pat}", "ADOS_DEFAULT_PROJECT": "MyProject" } } } }To run from source instead (e.g. for development), replace the command:
"command": "dotnet", "args": ["run", "--project", "D:/Projects/AzureMCP/src/AzureDevOpsServer.Mcp"]Open Copilot Chat, switch to Agent mode, and start the server when prompted. VS Code asks for the PAT on first start and stores it securely — the token never lands in the config file.
Click the tools icon in the chat input to confirm the
azure-devops-servertools are enabled, then ask Copilot for example to "list projects on our DevOps server".
GitHub Copilot in Visual Studio
Visual Studio 2022 (17.14+) uses the same configuration format. Put the JSON above in a file named .mcp.json next to your solution (or %USERPROFILE%\.mcp.json to make it global), restart Visual Studio, and enable the server's tools in the Copilot Chat tool picker while in Agent mode.
Testing the integration
Try these prompts in Copilot agent mode and watch which tool gets called:
- "Show the Azure DevOps server info" →
server_info, returns the collection URL and defaults without the PAT - "List projects on our DevOps server" →
list_projects - "Find active bugs in project X" →
query_work_itemswith a WIQL query - "Show file /README.md from repository Y" →
get_file_content - "Queue a build for definition 12" →
queue_build(Copilot asks for confirmation before write operations)
Troubleshooting
- Server does not start — open the MCP log (VS Code: Output panel → the
azure-devops-serverchannel). A missingADOS_COLLECTION_URLorADOS_PATis reported explicitly at startup - "Authentication against Azure DevOps Server failed" — the PAT is invalid, expired, or missing scopes; TFS sign-in page responses (HTTP 203) are detected and reported as this error as well
- TLS / certificate errors — on-premises servers usually present a certificate from an internal certificate authority. The server reports this explicitly instead of failing with an opaque SSL error; fix it by importing the authority certificate into the machine trust store (Windows:
Manage computer certificates→ Trusted Root Certification Authorities → Import). Certificate validation is never disabled, because the PAT travels on that connection - Older servers — for Azure DevOps Server 2019 / 2020 set
ADOS_API_VERSIONto5.0/6.0 dnxnot found — the .NET 10 SDK is required; verify withdotnet --list-sdks
Configuration
| Variable | Required | Description |
|---|---|---|
ADOS_COLLECTION_URL |
yes | Full collection URL, e.g. https://devops.example.local/DefaultCollection |
ADOS_PAT |
yes | Personal Access Token used for all REST calls |
ADOS_DEFAULT_PROJECT |
no | Default project used when a tool call does not specify one |
ADOS_API_VERSION |
no | Override the REST API version for every area (defaults to 7.0) |
ADOS_API_VERSION_WIT |
no | REST API version for work item and query calls |
ADOS_API_VERSION_GIT |
no | REST API version for repository and pull request calls |
ADOS_API_VERSION_BUILD |
no | REST API version for build calls |
ADOS_API_VERSION_RELEASE |
no | REST API version for release calls |
ADOS_API_VERSION_WIKI |
no | REST API version for wiki calls |
ADOS_API_VERSION_WIT_COMMENTS |
no | REST API version for the work item comments API (defaults to 7.0-preview.3) |
ADOS_TOOLSETS |
no | Comma-separated toolsets to expose: projects, workitems, queries, repositories, pullrequests, builds, releases, wiki. All are enabled by default; server_info is always available |
ADOS_READ_ONLY |
no | Set to true to expose only read-only tools; every create, update, and delete tool disappears from the tool list |
ADOS_LOG_LEVEL |
no | Minimum level of logs written to stderr (defaults to Warning; use Information or Debug for diagnostics) |
Security
- The PAT is read only from environment variables — never from command-line arguments, committed configuration files, or source code
- No secrets are ever stored in this repository
- Failed authentication (including TFS sign-in page responses with status 203) surfaces a clear error instead of confusing parse failures
- Use a PAT with the minimal scopes needed and a short expiration date
- Use HTTPS for the collection URL
Building from source
git clone https://github.com/eXoz00rd/AzureMCP.git
cd AzureMCP
dotnet build AzureDevOpsServer.Mcp.slnx
dotnet run --project tests/AzureDevOpsServer.Mcp.Tests
dotnet format --verify-no-changes
CI runs the same steps on every push and pull request, then collects coverage and packs the NuGet package.
Publishing a release
Releases are published to NuGet.org by the release workflow:
Publishing uses NuGet Trusted Publishing — a policy on nuget.org tied to this repository and
release.yml; no API key secret is stored. The workflow exchanges the GitHub OIDC token for a short-lived key viaNuGet/loginTag the commit and push the tag:
git tag v0.1.0-preview.2 git push origin v0.1.0-preview.2The workflow builds, tests, packs with the version taken from the tag (also synced into
.mcp/server.json), and pushes the package to NuGet.org
Roadmap
- Wiki search through the Search extension
- Work item attachments
- Code search
Support the project
If this server saves you time, you can support its development here: suppi.pl/exoz0rd. Entirely optional — the package stays free and MIT licensed either way.
License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.2 | 100 | 9/14/2026 |
| 0.1.1 | 105 | 9/10/2026 |
| 0.1.0 | 138 | 8/12/2026 |
| 0.1.0-preview.9 | 89 | 8/11/2026 |
| 0.1.0-preview.8 | 72 | 8/11/2026 |
| 0.1.0-preview.7 | 65 | 8/10/2026 |
| 0.1.0-preview.6 | 67 | 8/10/2026 |
| 0.1.0-preview.5 | 61 | 8/10/2026 |
| 0.1.0-preview.4 | 59 | 8/10/2026 |
| 0.1.0-preview.3 | 70 | 8/10/2026 |
| 0.1.0-preview.2 | 61 | 8/10/2026 |
| 0.1.0-preview.1 | 75 | 8/10/2026 |