From azure-devops
Work with Azure DevOps Server — analyse pipeline failures, review pull requests, create and update pull requests, and generate changelogs since a given build or commit. Use when the user mentions ADO pipelines, builds, PRs, changelogs, or pastes Azure DevOps URLs. Also trigger for PR creation/update requests in repositories with an Azure DevOps Server remote.
npx claudepluginhub mediainterface/claude-marketplaceThis skill is limited to using the following tools:
1. Run `git remote get-url origin` via Bash.
Creates isolated Git worktrees for feature branches with prioritized directory selection, gitignore safety checks, auto project setup for Node/Python/Rust/Go, and baseline verification.
Executes implementation plans in current session by dispatching fresh subagents per independent task, with two-stage reviews: spec compliance then code quality.
Dispatches parallel agents to independently tackle 2+ tasks like separate test failures or subsystems without shared state or dependencies.
git remote get-url origin via Bash.parse_ado_remote with the remote URL.parse_ado_remote fails because the ado MCP server is not running (tool not found / connection error), the ADO_PAT environment variable is most likely missing. Follow the Authorization Troubleshooting section below and stop.server, collection, project, repository values — use them for ALL subsequent ado_get, ado_post, ado_patch, ado_delete calls.If any MCP tool call fails because the ado server is unavailable or returns an authentication/authorization error (HTTP 401/403), tell the user exactly what to do:
The Azure DevOps MCP server could not start or authenticate because
ADO_PATis not set or is invalid.You need a Personal Access Token (PAT) for your Azure DevOps Server instance.
How to create a PAT:
- Open your Azure DevOps Server in the browser.
- Click your profile picture (top right) → Security → Personal access tokens.
- Click + New Token.
- Give it a descriptive name (e.g.
claude-code).- Set the expiration as desired.
- Select the required scopes:
- Code: Read & Write (for PR creation/update and repository access)
- Build: Read (for pipeline analysis)
- Click Create and copy the token.
How to provide the PAT to Claude Code:
Add it to your shell environment (e.g.
~/.bashrc,~/.zshrc, or~/.env):export ADO_PAT="your-personal-access-token"Then restart your terminal / Claude Code session so the MCP server picks it up.
After providing these instructions, stop — do not attempt any further ADO API calls.
When the user provides a URL or build ID, the referenced resource may belong to a different repository than the one you are currently in. After fetching metadata from the API (build metadata, PR metadata), compare the repository.name field from the response against the local repository value from Step 0.
If they differ, warn the user before proceeding:
"The build/PR belongs to repository {remote repo}, but you are currently in {local repo}. Local git operations (reading pipeline YAML, checking out branches, generating diffs) will use the wrong codebase. Do you want to continue anyway?"
Only proceed if the user explicitly confirms.
Five MCP tools are available via the ado server:
| Tool | Parameters | Description |
|---|---|---|
ado_get | server, collection, project, path, accept? | HTTP GET |
ado_post | server, collection, project, path, body, accept? | HTTP POST |
ado_patch | server, collection, project, path, body, accept? | HTTP PATCH |
ado_delete | server, collection, project, path, accept? | HTTP DELETE |
parse_ado_remote | remote_url | Parse git remote into components |
path: API path relative to {server}/{collection}/{project}/_apis — e.g. /build/builds/123path may include query parameters (e.g. ?searchCriteria.status=active)body: JSON string for POST/PATCHaccept: Override Accept header (default: application/json). Use text/plain for build logs.server, collection, project: Always use the values from Step 0's parse_ado_remote call.| Endpoint | Description |
|---|---|
GET /build/builds/{buildId} | Build metadata (pipeline name, status, source branch, trigger reason, start/finish times, definition ID) |
GET /build/builds/{buildId}/timeline | Execution timeline — array of records (stages, jobs, tasks) with type, name, state, result, issues[], log.id |
GET /build/builds/{buildId}/logs/{logId} | Plain text log for a specific task (use log.id from timeline). Use accept="text/plain". |
GET /build/builds/{buildId}/changes | Commits associated with the build. Each entry has id, message, author, timestamp. |
GET /build/definitions/{definitionId} | Pipeline definition metadata. Key field: process.yamlFilename for YAML pipelines. |
| Endpoint | Description |
|---|---|
GET /git/repositories/{repo} | Repository metadata. Key field: defaultBranch (e.g., refs/heads/main). |
GET /git/repositories/{repo}/pullrequests/{prId} | PR metadata (title, description, status, source/target branches, author, creation date, merge status). |
POST /git/repositories/{repo}/pullrequests | Create a PR. Body: { sourceRefName, targetRefName, title, description }. Ref names must be refs/heads/{branch}. |
PATCH /git/repositories/{repo}/pullrequests/{prId} | Update a PR. Body: only fields to change (title, description, status). Status values: active, abandoned, completed. |
GET /git/repositories/{repo}/pullrequests?searchCriteria.sourceRefName=refs/heads/{branch}&searchCriteria.status=active | Search for active PRs by source branch. Returns { value: [...] }. |
GET /git/repositories/{repo}/pullrequests/{prId}/threads | PR comment threads. Filter out threads where all comments have commentType: "system". |
Trigger: User provides a pipeline URL (containing /_build/results?buildId=) or a numeric build ID, or asks about a build failure.
Parse input: Extract buildId from URL query parameter, or use the numeric ID directly.
Fetch build metadata:
ado_get(server, collection, project, path="/build/builds/{buildId}")
Note the definition.id for step 6, and the sourceBranch, requestedFor, startTime, finishTime, result.
Repository check: Compare repository.name from the response against the local repository from Step 0. If they differ, warn the user (see "Repository Mismatch Check" above) and stop unless confirmed.
Fetch timeline:
ado_get(server, collection, project, path="/build/builds/{buildId}/timeline")
From the records array, identify entries where result is "failed" and type is "Task". Note their log.id and any issues[] entries.
Fetch logs for each failed task:
ado_get(server, collection, project, path="/build/builds/{buildId}/logs/{logId}", accept="text/plain")
Extract error lines matching: ##[error], error:, error , FAILED, fatal:, fatal , exception:, exception (case-insensitive). Focus your analysis on these error lines rather than dumping the full log.
Fetch associated commits:
ado_get(server, collection, project, path="/build/builds/{buildId}/changes")
Checkout the build's source branch so local files match what the build ran against:
git branch --show-current (or git rev-parse HEAD if detached)git stash -urefs/heads/ prefix from sourceBranch (from step 2)git fetch origin {sourceBranch} && git checkout origin/{sourceBranch} --detachsourceVersion (commit SHA) from the build metadata instead: git fetch origin {sourceVersion} && git checkout {sourceVersion} --detachFetch pipeline definition:
ado_get(server, collection, project, path="/build/definitions/{definitionId}")
If process.yamlFilename is present, read that YAML file from the local repo. Follow template: references to read template files too.
Analyse and report — provide:
Common failure categories: build errors, test failures, deployment errors, infrastructure errors, configuration errors, dependency issues.
Restore original branch:
git checkout {originalBranch} (or git checkout {originalCommit} if was detached)git stash popTrigger: User provides a PR ID (numeric) or a PR URL, or asks to review a PR.
Parse input: Extract PR ID from the URL path or use the numeric ID directly.
Fetch PR metadata:
ado_get(server, collection, project, path="/git/repositories/{repo}/pullrequests/{prId}")
Note sourceRefName, targetRefName, title, description, createdBy, creationDate, status.
Repository check: Compare repository.name from the response against the local repository from Step 0. If they differ, warn the user (see "Repository Mismatch Check" above) and stop unless confirmed.
Generate local git diffs:
Strip refs/heads/ prefix from source and target branch names, then:
git fetch origin {sourceBranch} {targetBranch}
git diff --name-status origin/{targetBranch}...origin/{sourceBranch}
git diff --stat origin/{targetBranch}...origin/{sourceBranch}
git diff origin/{targetBranch}...origin/{sourceBranch}
git log --oneline origin/{targetBranch}...origin/{sourceBranch}
If the source branch no longer exists (e.g., already merged and deleted), git fetch will fail. In this case, check if the PR metadata contains lastMergeSourceCommit.commitId and use that commit SHA instead of the branch name: git fetch origin {commitId} then diff against {commitId} instead of origin/{sourceBranch}.
If git operations fail for any other reason, report the error to the user and stop. Do NOT fall back to API-based changes.
Fetch PR comment threads:
ado_get(server, collection, project, path="/git/repositories/{repo}/pullrequests/{prId}/threads")
Filter out system-generated threads (where all comments have commentType: "system"). Show human comments.
Checkout the source branch so you can explore the full codebase in its PR state:
git branch --show-current (or git rev-parse HEAD if detached)git stash -ugit checkout origin/{sourceBranch} --detach (or git checkout {commitId} --detach if the deleted-branch SHA fallback was used in step 3)Gather context:
Review the PR covering:
Be specific — reference file paths and line numbers. Distinguish blockers from suggestions.
Restore original branch:
git checkout {originalBranch} (or git checkout {originalCommit} if was detached)git stash popTrigger: User asks to create a PR, or $ARGUMENTS starts with create.
Verify branch is pushed:
CURRENT_BRANCH=$(git branch --show-current)
git rev-list --count "origin/$CURRENT_BRANCH..HEAD" 2>/dev/null
If the branch is not tracked or has unpushed commits, inform the user and ask if they want to push. If yes: git push -u origin $CURRENT_BRANCH. If no: stop.
Check for existing PR:
ado_get(server, collection, project, path="/git/repositories/{repo}/pullrequests?searchCriteria.sourceRefName=refs/heads/{branch}&searchCriteria.status=active")
If a PR exists, inform the user (show title and ID) and ask if they want to update it instead. If yes, switch to PR Update workflow.
Get default branch:
ado_get(server, collection, project, path="/git/repositories/{repo}")
Use the defaultBranch field (strip refs/heads/ prefix) as the target branch.
Gather commit information:
git log --oneline "origin/{targetBranch}..{currentBranch}"
Ask for Asana ticket ID — format: ID-XXXXX (e.g., ID-17885).
Check for PR template:
Use Glob to check for .azuredevops/pull_request_template.md in the repo root. If found, read it.
Generate title and description:
Title format: Icon <Asana-Ticket-Id> Component - Änderungsbeschreibung
fix, bugfix, hotfix)refactor, cleanup, restructure)docs, documentation)Description: Must be in German.
https://app.asana.com/0/search?q=ID-XXXXX) in an appropriate section (or add ## Asana section)## Asana section at top with ticket link, summary of changes (German), list of commitsPresent to user for review: Show generated title and full description. Apply changes if requested. Repeat until approved.
Create the PR:
ado_post(server, collection, project, path="/git/repositories/{repo}/pullrequests", body='{"sourceRefName":"refs/heads/{source}","targetRefName":"refs/heads/{target}","title":"{title}","description":"{description}"}')
Report result: Show the PR URL and ID.
Trigger: User asks to update a PR, or $ARGUMENTS starts with update.
Find the PR:
ado_get(server, collection, project, path="/git/repositories/{repo}/pullrequests?searchCriteria.sourceRefName=refs/heads/{currentBranch}&searchCriteria.status=active")
ado_get(server, collection, project, path="/git/repositories/{repo}/pullrequests/{prId}")
Show current PR state: Display current title and description.
Ask what to update: Title, description, or Asana link.
Generate updated values following the same formatting rules as the Create workflow (German language, title schema with icon/Asana-ID/component).
Present changes for confirmation: Show old vs. new values.
Update the PR:
ado_patch(server, collection, project, path="/git/repositories/{repo}/pullrequests/{prId}", body='{"title":"{newTitle}","description":"{newDescription}"}')
Only include fields that are being changed.
Report result: Confirm the update and show the PR URL.
Trigger: User asks what changed since a build or commit, or $ARGUMENTS starts with changelog.
Determine the base commit SHA from the user's input:
/_build/results?buildId=, extract the buildId from the query parameter, then proceed as build ID.ado_get(server, collection, project, path="/build/builds/{buildId}")
Extract the sourceVersion field — this is the commit SHA.
Repository check: Compare repository.name from the response against the local repository from Step 0. If they differ, warn the user (see "Repository Mismatch Check" above) and stop unless confirmed.Resolve repository name: Use the repository value from Step 0's parse_ado_remote call.
Get default branch:
ado_get(server, collection, project, path="/git/repositories/{repo}")
Use the defaultBranch field. Strip refs/heads/ prefix for git operations (e.g., refs/heads/main → main).
Fetch latest from default branch:
git fetch origin {defaultBranch}
Ensure the base commit is available locally:
git cat-file -t {commit}
If this fails (commit not found), fetch it:
git fetch origin {commit}
If it still fails, report: "Commit {commit} not found locally or on the remote." and stop.
Check if there are changes:
git rev-list --count {commit}..origin/{defaultBranch}
If the count is 0, report: "Default branch is at the same commit as the build — no new changes." and stop.
Collect commit log:
git log --format='%h %an <%ae> %s' {commit}..origin/{defaultBranch}
Collect file stats:
git diff --stat {commit}..origin/{defaultBranch}
Collect full diff:
git diff {commit}..origin/{defaultBranch}
Present three sections:
Commit Log — all commits between the base commit and origin/{defaultBranch}, showing short SHA, author, and commit message.
File Overview — git diff --stat output, grouped by top-level directory or component to show which areas were touched. Include total files changed, insertions, and deletions.
Narrative Summary — a prose summary describing the changes conceptually: what features were added, what bugs were fixed, what was refactored. Written as a briefing for someone who wants to understand what the next build will include without reading diffs.