Skip to main content
Glama

ADO Workflows MCP Server

CI coverage PyPI License: MIT

An MCP server exposing ado-workflows as tool calls for AI agents. Enables Copilot and other MCP clients to discover Azure DevOps repositories, manage pull requests, and interact with PR comments and reviews.

Quick Install

Click a badge above to install with one click, or follow manual installation below.

Related MCP server: ado-mcp

Features

  • Repository Discovery: Scan directories for git repos with Azure DevOps remotes

  • PR Lifecycle: Create pull requests, establish PR context from URLs or IDs

  • Review Management: Check reviewer votes, detect stale approvals, find PRs needing attention

  • Comment Workflows: Analyze, post, reply to, and batch-resolve PR comment threads

  • Session Caching: Cache repository context to avoid redundant git CLI lookups

  • Error Handling: Actionable errors with suggestions via actionable-errors

MCP Tools

Repository Discovery

Tool

Description

repository_discovery

Scan a directory for git repos with Azure DevOps remotes, select the best match

set_repository_context

Cache repository context for the session (avoids redundant git CLI lookups)

get_repository_context_status

Inspect current cached context state for debugging

clear_repository_context

Reset cached context, forcing fresh discovery

Pull Requests

Tool

Description

establish_pr_context

Parse a PR URL or resolve a numeric PR ID into reusable context

create_pull_request

Create a new PR from branch names with optional title, description, and draft mode

PR Review

Tool

Description

get_pr_review_status

Fetch reviewer votes, commit history, and detect stale approvals

analyze_pending_reviews

Discover PRs needing review attention across a repository

PR Comments

Tool

Description

analyze_pr_comments

Categorize comment threads by status with author statistics

post_pr_comment

Post a new comment thread to a PR

reply_to_pr_comment

Reply to an existing comment thread

resolve_pr_comments

Batch-resolve comment threads (partial-success semantics)

Installation

Click one of the badges at the top to automatically install in VS Code!

Manual Installation

cd ado-workflows-mcp
uv sync --all-extras

VS Code / Copilot Configuration

Add to your VS Code settings or .vscode/mcp.json:

{
  "mcp.servers": {
    "ado-workflows": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/grimlor/ado-workflows-mcp", "ado-workflows-mcp"],
      "description": "Azure DevOps workflow automation tools"
    }
  }
}

The server communicates over stdio using the Model Context Protocol.

Authentication

Uses Azure DefaultAzureCredential via the ado-workflows library. Authenticate with any method that DefaultAzureCredential supports:

az login                           # Azure CLI (local dev)
az login --use-device-code         # Headless / SSH

Managed identity, environment variables, and other credential providers work automatically in hosted environments.

Error Handling

All errors are returned as structured ActionableError objects with:

  • error / suggestion — human-readable context

  • ai_guidance — machine-readable recovery instructions (action_required, checks, steps, command, discovery_tool)

Errors are returned as data, never raised — the MCP transport stays clean.

Typical Workflow

1. repository_discovery        → find the ADO repo
2. set_repository_context      → cache it for the session
3. establish_pr_context        → resolve a PR URL or ID
4. get_pr_review_status        → check approval state
5. analyze_pr_comments         → see active threads
6. post_pr_comment / reply     → leave feedback
7. resolve_pr_comments         → mark threads as fixed

Development

uv run task check                # lint + type + test (all-in-one)
uv run task test                 # Run tests (37 BDD specs)
uv run task cov                  # Run tests with coverage
uv run task lint                 # Lint (with auto-fix)
uv run task format               # Format code
uv run task type                 # Type check

Note: uv run is optional when the venv is activated via direnv.

Project Structure

src/ado_workflows_mcp/
├── server.py              # FastMCP server entry point
├── mcp_instance.py        # MCP singleton
├── tools/
│   ├── repositories.py    # Repository discovery tools
│   ├── repository_context.py  # Session context management
│   ├── pull_requests.py   # PR lifecycle tools
│   ├── pr_review.py       # Review status tools
│   ├── pr_comments.py     # Comment workflow tools
│   └── _helpers.py        # Shared error-handling utilities
└── py.typed               # PEP 561 marker

Testing

37 BDD specs across 10 requirement classes — organized by consumer requirement, not code structure.

Requirement Class

Specs

Coverage

TestRepositoryDiscovery

3

Success, working-dir failure, SDK failure

TestSetRepositoryContext

3

Valid context, missing fields, SDK failure

TestGetRepositoryContextStatus

3

Populated, empty, error

TestClearRepositoryContext

2

Reset + clear state

TestEstablishPRContext

3

URL parse, ID resolve, SDK failure

TestCreatePullRequest

3

Success, missing branch, SDK failure

TestGetPRReviewStatus

3

Success, invalid PR, SDK failure

TestAnalyzePendingReviews

3

Results, empty, SDK failure

TestAnalyzePRComments

3

Categorized, no threads, SDK failure

TestPostPRComment

3

Valid post, empty content, SDK failure

TestReplyToPRComment

3

Valid reply, missing thread, SDK failure

TestResolvePRComments

3

Batch resolve, empty list, SDK failure

Documentation

  • Architecture — Tool layers, error propagation, and design decisions

License

This project is licensed under the MIT License.

Available Tools

45 tools
abandon_pull_requestA

Abandon (close without merging) an existing PR.

Args: pr_url_or_id: A full PR URL or numeric PR ID. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), working_directory. Returns: result

add_pr_labelB

Add a label/tag to a PR.

Args: pr_url_or_id: A full PR URL or numeric PR ID. name: Label name. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), name (required), working_directory. Returns: result

add_pr_reviewerA

Add a reviewer to a PR.

Args: pr_url_or_id: A full PR URL or numeric PR ID. reviewer_id: Azure DevOps identity GUID of the reviewer. is_required: Whether the reviewer is required. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), reviewer_id (required), is_required, working_directory. Returns: result

analyze_pending_reviewsA

Discover PRs needing review attention across a repository.

Lists active PRs, filters by age and creator, and enriches each with staleness detection data.

Args: max_days_old: Exclude PRs older than this many days. Default 30. creator_filter: Optional substring match on PR creator. working_directory: Optional path for context resolution.

Inputs: max_days_old, creator_filter, working_directory. Returns: result

analyze_pr_commentsA

Analyze all comment threads on a PR.

Fetches threads, categorizes by status, and extracts author statistics for a structured overview.

Args: pr_url_or_id: A full PR URL or numeric PR ID. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), working_directory. Returns: result

clear_repository_contextA

Reset cached context.

Clears cached discovery results, forcing fresh discovery on the next tool call. Idempotent — safe to call even when no context is set.

Inputs: no named parameters. Returns: result

clone_work_itemA

Clone a work item into a new item of the same type, addressed by URL or ID.

Copies all fields from the source, applies optional overrides, and preserves the parent link. Does not close the source.

Caveat — work board ≠ code repo: passing a bare numeric ID resolves the org/project from the cached repository context, which can land on the wrong organization when the work board lives in a different tenant than any of the discovered code repos. Prefer passing a full work-item URL — clones created in the wrong tenant are unrecoverable without manual cleanup.

Args: source_work_item_url_or_id: A full Azure DevOps work-item URL or a numeric work-item ID for the source. field_overrides: Optional dict of fields to override in the clone. working_directory: Optional path for repository-context resolution when using a numeric ID.

Inputs: source_work_item_url_or_id (required), field_overrides (required), working_directory (required). Returns: result

complete_pull_requestA

Complete (merge) a PR with configurable merge strategy.

Args: pr_url_or_id: A full PR URL or numeric PR ID. merge_strategy: One of: squash, noFastForward, rebase, rebaseMerge. delete_source_branch: Whether to delete the source branch after merge. transition_work_items: Whether to transition linked work items. merge_commit_message: Optional merge commit message. bypass_policy: Whether to bypass branch policies. bypass_reason: Required when bypass_policy is True. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), merge_strategy, delete_source_branch, transition_work_items, +4 more. Returns: result

create_pull_requestB

Create a new pull request via the Azure DevOps SDK.

Constructs a PR from branch names with optional title, description, and draft mode.

Args: source_branch: Source branch name (with or without refs/heads/). target_branch: Target branch name. Defaults to "main". title: Optional PR title. description: Optional PR description. is_draft: Whether to create as a draft PR. working_directory: Optional path for context resolution. work_item_ids: Optional list of work item IDs to link to the PR.

Inputs: source_branch (required), target_branch, title, description, +3 more. Returns: result

create_work_itemA

Create a new work item of any type.

Args: project: Azure DevOps project name. work_item_type: Work item type (e.g. "Task", "Bug", "Product Backlog Item"). fields: Dict mapping field reference names to values. parent_id: Optional parent work item ID for hierarchy linking. working_directory: Optional path for ADO context resolution.

Inputs: project (required), work_item_type (required), fields (required), parent_id (required), +1 more. Returns: result

discover_all_repositoriesA

List every Azure DevOps repository discovered under the working directory.

Walks the working directory (or cwd) for git repositories with Azure DevOps remotes. Use this tool when another tool surfaces a multi-repo ambiguity error to enumerate the candidate repos so an end user can disambiguate.

Args: working_directory: Path to scan. Defaults to the current working directory when omitted.

Inputs: working_directory. Returns: result

establish_pr_contextA

Create reusable PR context from a URL or numeric ID.

Parses a full PR URL or resolves a numeric PR ID using cached repository context.

Args: pr_url_or_id: A full Azure DevOps PR URL or a numeric PR ID. working_directory: Optional path for context resolution when using a numeric ID.

Inputs: pr_url_or_id (required), working_directory. Returns: result

establish_work_item_contextA

Resolve a work-item URL or numeric ID into a structured context.

Parses a full Azure DevOps work-item URL or resolves a bare numeric work-item ID using the cached repository context. The returned AzureDevOpsWorkItemContext carries the organisation, project, work-item ID, and computed org_url for downstream tools.

Caveat — work board ≠ code repo: when resolving a bare numeric ID against a workspace whose work board lives in a different organisation than any of the discovered code repos, the resolved org_url will land on the code-repo organisation, not the work board's. Prefer passing a full work-item URL whenever one is available.

Args: work_item_url_or_id: A full Azure DevOps work-item URL or a numeric work-item ID. working_directory: Optional path for repository-context resolution when using a numeric ID.

Inputs: work_item_url_or_id (required), working_directory. Returns: result

get_current_userA

Get the identity of the authenticated user.

Returns the display name and GUID of the user whose credentials are active for Azure DevOps operations. Useful for self-praise filtering, commit attribution, and permission checks.

Args: working_directory: Optional path for context resolution.

Inputs: working_directory. Returns: result

get_pr_authorA

Get the identity of a PR's creator.

Returns the display name, GUID, and email of the user who created the pull request.

Args: pr_url_or_id: A full PR URL or numeric PR ID. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), working_directory. Returns: result

get_pr_file_changesA

List files changed in a PR with iteration metadata.

Returns a list of dicts, each with keys: path, change_type, change_tracking_id, iteration_id.

Uses the latest iteration.

Args: pr_url_or_id: A full PR URL or numeric PR ID. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), working_directory (required). Returns: result

get_pr_file_contentsA

Fetch file contents for files changed in a PR.

Returns a list of dicts, each with keys: path, content, encoding, size_bytes. Files that fail to fetch are omitted from successes and included as error entries with ai_guidance.

If file_paths is None, fetches all changed files.

Args: pr_url_or_id: A full PR URL or numeric PR ID. file_paths: Optional list of specific file paths to fetch. exclude_extensions: Optional list of file extensions to skip (e.g. [".png", ".lock"]). Case-insensitive; leading dot optional. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), file_paths (required), exclude_extensions (required), working_directory (required). Returns: result

get_pr_review_statusA

Get comprehensive review status with vote invalidation detection.

Fetches PR details, reviewer votes, commit history, and detects stale approvals that the raw API buries.

Args: pr_id: Pull request ID. working_directory: Optional path for context resolution.

Inputs: pr_id (required), working_directory. Returns: result

get_pr_work_itemsA

List work items linked to a PR (read-only).

Args: pr_url_or_id: A full PR URL or numeric PR ID. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), working_directory. Returns: result

get_pull_requestA

Retrieve full PR metadata including reviewers, labels, and work items.

Args: pr_url_or_id: A full PR URL or numeric PR ID. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), working_directory. Returns: result

get_repo_file_contentA

Fetch a single file's content from any branch, commit, or tag.

Returns a dict with keys: path, content, encoding, size_bytes.

Context (repository, project, org) is resolved from the cached RepositoryContext unless explicit params are provided.

Args: path: File path within the repository. ref: Branch name, commit SHA, or tag. None = default branch. repository: Repository name (overrides context). project: Project name (overrides context). working_directory: Optional path for context resolution.

Inputs: path (required), ref (required), repository (required), project (required), +1 more. Returns: result

get_repository_context_statusA

Inspect current cached context state.

Returns cache state, timestamps, and working directory details. Useful for agents debugging context issues or verifying setup.

Inputs: no named parameters. Returns: result

get_work_itemA

Fetch a single work item by URL or numeric ID.

Returns WorkItemDetail with all fields, area path, parent ID, and a full fields dict for type-specific access.

Caveat — work board ≠ code repo: passing a bare numeric ID resolves the org/project from the cached repository context, which can land on the wrong organization when the work board lives in a different tenant than any of the discovered code repos. Prefer passing a full work-item URL whenever one is available.

Args: work_item_url_or_id: A full Azure DevOps work-item URL or a numeric work-item ID. working_directory: Optional path for repository-context resolution when using a numeric ID.

Inputs: work_item_url_or_id (required), working_directory (required). Returns: result

get_work_itemsA

Batch-fetch multiple work items by ID with full field data.

Args: project: Azure DevOps project name. work_item_ids: List of numeric work item IDs. working_directory: Optional path for ADO context resolution.

Inputs: project (required), work_item_ids (required), working_directory (required). Returns: result

get_work_item_type_fieldsA

Discover available fields for a work item type in a project.

Returns field metadata including name, reference name, type, and whether the field is required.

Args: project: Azure DevOps project name. work_item_type: Work item type (e.g. "Task", "Bug"). working_directory: Optional path for ADO context resolution.

Inputs: project (required), work_item_type (required), working_directory (required). Returns: result

list_commitsB

List git commits from a local repository.

Returns commit summaries with sha, message, author, date, and repo name. No ADO connection is needed.

Args: repo_path: Absolute path to the local git repository. authors: Optional list of author names/emails to filter by. since: Optional date string to filter commits after (e.g. "2026-01-01"). max_count: Maximum number of commits to return (default 100).

Inputs: repo_path (required), authors (required), since (required), max_count (required). Returns: result

list_pr_labelsB

List all labels on a PR.

Args: pr_url_or_id: A full PR URL or numeric PR ID. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), working_directory. Returns: result

list_pr_reviewersB

List all reviewers on a PR with vote details.

Args: pr_url_or_id: A full PR URL or numeric PR ID. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), working_directory. Returns: result

list_pull_requestsA

List pull requests matching search criteria.

Returns PR summaries with id, title, status, web_url, and more.

Args: project: Azure DevOps project name. creator_id: Optional GUID to filter by PR creator. reviewer_id: Optional GUID to filter by reviewer. status: PR status filter (default "all"). repository_id: Optional repository ID for repo-scoped queries. top: Maximum number of results (default 50). working_directory: Optional path for ADO context resolution.

Inputs: project (required), creator_id (required), reviewer_id (required), status (required), +3 more. Returns: result

list_repo_itemsA

List files and folders at a path on any branch, commit, or tag.

Returns a list of dicts, each with keys: path, is_folder, git_object_type, object_id, commit_id, url.

Context (repository, project, org) is resolved from the cached RepositoryContext unless explicit params are provided.

Args: path: Directory path to list. Defaults to "/". ref: Branch name, commit SHA, or tag. None = default branch. recursion: "none", "oneLevel" (default), or "full". repository: Repository name (overrides context). project: Project name (overrides context). working_directory: Optional path for context resolution.

Inputs: path (required), ref (required), recursion (required), repository (required), +2 more. Returns: result

move_work_items_to_sprintA

Move work items to a target sprint by updating their iteration path.

Does not auto-include children — callers decide which IDs to move.

Args: project: Azure DevOps project name. work_item_ids: List of work item IDs to move. iteration_path: Target iteration path (e.g. "One\FY26\Q4\2Wk\2Wk22"). working_directory: Optional path for ADO context resolution.

Inputs: project (required), work_item_ids (required), iteration_path (required), working_directory (required). Returns: result

post_pr_commentA

Post a new comment thread to a PR.

Creates a new comment thread with the specified content and status.

Args: pr_url_or_id: A full PR URL or numeric PR ID. comment_text: Comment body text. status: Thread status (default "active"). working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), comment_text (required), status, working_directory. Returns: result

post_pr_commentsA

Batch-post comments to a PR with optional file/line positioning.

Each comment dict has keys: content: str (required) file_path: str | None (optional — anchors to file) line_number: int | None (optional — anchors to line, requires file_path) status: str (optional — default "active")

Iteration context is auto-resolved. Comments are positioned on the latest iteration.

dry_run=True validates and returns what would be posted.

Args: pr_url_or_id: A full PR URL or numeric PR ID. comments: List of comment dicts to post. dry_run: If True, validate without posting. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), comments (required), dry_run (required), working_directory (required). Returns: result

post_rich_commentsA

Batch-post structured review comments with severity, type, and formatting.

Each comment dict has keys: comment_id: str (required — unique identifier) title: str (required — short heading) content: str (required — comment body) severity: str (optional — "info","suggestion","warning","error","critical") comment_type: str (optional — "general","line","file","suggestion","security","performance") file_path: str | None (optional — anchors to file) line_number: int | None (optional — anchors to line, requires file_path) suggested_code: str | None (optional) reasoning: str | None (optional) business_impact: str | None (optional) tags: list[str] (optional) status: str (optional — default "active") parent_thread_id: int | None (optional — reply to existing thread)

String severity/comment_type values are coerced to enums at this layer. Invalid values return an ActionableError listing valid options.

dry_run=True validates and shows what would be posted without calling the API. filter_self_praise=True (default) removes praise comments authored by the caller.

Args: pr_url_or_id: A full PR URL or numeric PR ID. comments: List of comment dicts to post. dry_run: If True, validate without posting. batch_size: Number of comments per API batch (default 5). filter_self_praise: If True, filter out self-praise comments. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), comments (required), dry_run (required), batch_size (required), +2 more. Returns: result

query_work_itemsA

Query work items via WIQL and return enriched data.

Executes a WIQL query and returns work item summaries with id, title, state, type, and effort tracking fields.

Args: project: Azure DevOps project name. wiql: WIQL query string. top: Optional maximum number of results. working_directory: Optional path for ADO context resolution.

Inputs: project (required), wiql (required), top (required), working_directory (required). Returns: result

remove_pr_labelB

Remove a label from a PR.

Args: pr_url_or_id: A full PR URL or numeric PR ID. label_name: Label name to remove. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), label_name (required), working_directory. Returns: result

remove_pr_reviewerB

Remove a reviewer from a PR.

Args: pr_url_or_id: A full PR URL or numeric PR ID. reviewer_id: Azure DevOps identity GUID of the reviewer. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), reviewer_id (required), working_directory. Returns: result

reply_to_pr_commentA

Reply to an existing comment thread.

Adds a reply to a specific thread on a PR.

Args: pr_url_or_id: A full PR URL or numeric PR ID. thread_id: Existing thread ID to reply to. comment_text: Reply body text. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), thread_id (required), comment_text (required), working_directory. Returns: result

repository_discoveryA

Discover Azure DevOps repositories from local git remotes.

Scans the working directory (or cwd) for git repos, extracts ADO remote metadata, and selects the best match.

Args: working_directory: Path to scan. Defaults to the current working directory when omitted.

Inputs: working_directory. Returns: result

resolve_pr_commentsA

Batch-resolve PR comment threads.

Sets thread status to the target status for a list of thread IDs. Uses partial-success semantics — individual thread errors don't fail the entire batch.

Args: pr_url_or_id: A full PR URL or numeric PR ID. thread_ids: Thread IDs to resolve. status: Target thread status (default "fixed"). working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), thread_ids (required), status, working_directory. Returns: result

retarget_pull_requestA

Change the target branch of an existing PR.

Args: pr_url_or_id: A full PR URL or numeric PR ID. target_branch: New target branch name. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), target_branch (required), working_directory. Returns: result

set_pr_draft_statusA

Toggle a PR between draft and published state.

Args: pr_url_or_id: A full PR URL or numeric PR ID. is_draft: True to mark as draft, False to publish. working_directory: Optional path for context resolution.

Inputs: pr_url_or_id (required), is_draft (required), working_directory. Returns: result

set_repository_contextA

Cache repository context for the session.

Sets the working directory and caches discovery results so subsequent tool calls skip redundant git CLI lookups.

Args: working_directory: Path to the git repository root.

Inputs: working_directory (required). Returns: result

update_pull_requestA

Update title and/or description of an existing PR.

Args: pr_url_or_id: A full PR URL or numeric PR ID. title: New title (optional). description: New description (optional). working_directory: Optional path for context resolution. work_item_ids: Optional list of work item IDs to link to the PR.

Inputs: pr_url_or_id (required), title, description, working_directory, +1 more. Returns: result

update_work_itemA

Update fields on an existing work item, addressed by URL or ID.

Accepts a dict of field reference names to values (e.g. {"System.State": "Closed", "System.IterationPath": "..."}).

Caveat — work board ≠ code repo: passing a bare numeric ID resolves the org/project from the cached repository context, which can land on the wrong organization when the work board lives in a different tenant than any of the discovered code repos. Prefer passing a full work-item URL whenever one is available — mutations in the wrong tenant are unrecoverable without manual intervention.

Args: work_item_url_or_id: A full Azure DevOps work-item URL or a numeric work-item ID. fields: Dict mapping field reference names to new values. working_directory: Optional path for repository-context resolution when using a numeric ID.

Inputs: work_item_url_or_id (required), fields (required), working_directory (required). Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.6/5.0

    Scored across 45 tools

    Disambiguation4/5

    Most tools have clearly distinct purposes, especially the PR and work item operations. However, the context management tools (set, clear, get status, discover, list) are numerous and could be confusing, though they perform different actions.

    Naming Consistency4/5

    Naming predominantly follows a verb_noun pattern in snake_case, but there is inconsistency between using 'pr' (add_pr_label, list_pr_reviewers) and 'pull_request' (abandon_pull_request, complete_pull_request). This mixing is minor but noticeable.

    Tool Count2/5

    45 tools is excessive for the apparent scope. Many tools are redundant (e.g., three comment posting tools) and the context management could be streamlined. The count feels bloated and increases cognitive load.

    Completeness4/5

    Core PR and work item lifecycles are well-covered, including creation, updates, reviews, and linking. Minor gaps exist (e.g., no delete work item), but the overall surface is rich. The analytics tools add valuable capabilities.

    Maintenance

    ActivityNo data
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers