Services → Azure DevOps
Connect Azure DevOps
Projects, repositories, pull requests, pipelines, builds and their logs, environments and deployments, classic releases, work items and agent pools — thirty-two tools, one Personal Access Token, nothing to install. Azure DevOps is where "what was deployed, and which step failed" is answered.
Setting this up with your own agent? Give it these instructions.
The whole setup
- In Azure DevOps, open User settings → Personal access tokens → New Token.
- Name it
prodpeek. Organization: the one you will enter as the upstream. Expiration: 90 days or less. - Scopes: Custom defined. Tick only these:
| Scope | Permission |
|---|---|
| Build | Read |
| Code | Read |
| Project and Team | Read |
| Work Items | Read |
| Release | Read |
| Variable Groups | Read |
| Agent Pools | Read |
| Environment | Read & manage — *optional*, see below |
- Create, and copy the token.
- In Prodpeek: Services → Add a service, pick
azuredevops/read-only, set the upstream tohttps://dev.azure.com/your-org, paste the PAT, Test connection.
Environment has no Read-only scope
list_environments and list_environment_deployments answer "what is in prod right now", and they need Environment · Read & manage — Azure DevOps has no Read form of it. That scope can also manage environments and their approval checks. If that trade is not worth it to you, leave it off: those two tools will be refused by Azure DevOps and everything else works.
The upstream is the organisation, not a project. If you paste https://dev.azure.com/acme/Shop/_git/api, Prodpeek says so and tells you to use https://dev.azure.com/acme. https://acme.visualstudio.com and an on-premises collection URL (https://tfs.example.com/tfs/DefaultCollection) work too.
Why there is no MCP server to install
Microsoft publishes an Azure DevOps MCP server. Its hosted form authenticates with OAuth as a signed-in user — the same model as Grafana Cloud's and Cloudflare's, and unusable for the same reason: Prodpeek is a server-side gateway holding a stored team credential, with no browser and no signed-in user.
The Azure DevOps REST API takes a Personal Access Token, which is exactly the shape Prodpeek is built around. So it speaks it directly.
What your agent can then do
azuredevops__list_builds did the last deploy fail, and on which branch
azuredevops__get_build_timeline which step failed, and the error it raised
azuredevops__get_build_log the end of that step's log, as plain text
azuredevops__list_environment_deployments what is in prod right now, and since when
azuredevops__list_pipeline_runs recent runs of one pipeline
azuredevops__list_commits what changed just before this broke
azuredevops__list_pull_requests which PR carried that change, and who approved it
azuredevops__get_item the deploy config at that commit
azuredevops__list_releases classic releases, and each environment's status
azuredevops__list_variable_groups whether DB_HOST is even set (values removed)
azuredevops__list_agents whether the self-hosted agent is online
azuredevops__get_work_item the incident ticket, with its links
get_build_timeline is the one to start with: one call names the failing step and the error it raised, and get_build_log then reads just that log. Read the end of the log first — list_build_logs gives the line count, and each call returns at most 2000 lines.
What it refuses, and the ones that matter
Service connections have no tool. _apis/serviceendpoint/endpoints is the map of every credential the organisation holds for Azure, AWS, container registries and clusters. There is no code path in the adapter that builds that path.
Secure files, PATs and agent registration tokens have no tool. Signing keys and kubeconfigs; the organisation's other tokens; the token that lets a machine join your build pool.
Variable values are removed. list_variable_groups and get_release keep every variable's name and whether it is secret, and replace every value. Secret values arrive empty from Azure DevOps anyway; the others are frequently secrets somebody forgot to tick. list_agents never asks for an agent's capabilities, which are its environment variables.
Free-form WIQL has no tool. It is a POST. run_query runs a *saved* query by id instead, which is a GET.
Queuing a build has no tool, and it is the one people ask for. "Just re-run the pipeline" sounds harmless. A pipeline that deploys is a production change.
Why Tier 2
The Tier 1 half is real: a PAT made from Read scopes refuses every write in this profile *at Azure DevOps*, independently of the gateway. Keep it that way.
It is Tier 2 anyway. The Environment scope has no Read-only form, and several allowed reads return source code and build logs, which hold whatever was committed or printed. The roll-up decides the label.
Azure DevOps also offers no honest introspection: a PAT cannot ask which scopes it holds. So this profile carries no scope probe, and [prove](../use/prove.md) reports the scope as *not introspectable* rather than claiming a check it never made.
Checking the credential really cannot write
ORG=https://dev.azure.com/your-org
PROJECT="Your Project"
# Should succeed, and name the identity the PAT belongs to
curl -sS -u ":$PAT" "$ORG/_apis/connectionData?api-version=7.1-preview" | head -c 300
# Should be REFUSED: queue a build of a definition that does not exist
curl -sS -o /dev/null -w '%{http_code}\n' -u ":$PAT" -X POST \
-H 'Content-Type: application/json' -d '{"definition":{"id":999999999}}' \
"$ORG/$(printf %s "$PROJECT" | sed 's/ /%20/g')/_apis/build/builds?api-version=7.1"
A 401 or 403 on the second is the vendor fence doing its half. A 404 ("definition not found") means the PAT could queue builds and only the made-up id stopped it — remake it without Build · Read & execute. The definition id is deliberately one that cannot exist, so the check never queues anything.