Skip to main content

MCP server that surfaces Azure DevOps work-item activity for one or more team rosters (multi-org / multi-tenant), so VS Code Copilot Chat can answer manager-style questions like 'what did Ashish work on last week?' or 'analyze the team's last 6 months'.

Project description

ado-team-activity-mcp

A local Model Context Protocol (MCP) server that lets you ask GitHub Copilot Chat in VS Code manager-style questions about Azure DevOps work-item activity across one or more orgs / tenants:

"What did Ashish work on yesterday?" "Give me a team standup for the last 3 days." "Analyze Vibhuti's last 6 months." "Discover the members of the PCOE Team and add them to my config." "Compare Ashish across the pcoe and contoso orgs."

Read-only against ADO by design — no work-item create / update / delete / comment is ever made. The only writes are to your own config.yaml, and every write is a dry-run-by-default, diff-then-confirm, backed-up operation.


Why 0.2.0 is a hard break

The config schema changed from single-org to multi-org. If you're on 0.1.x:

# OLD (0.1.x) — will fail to load on 0.2.0 with a helpful migration message:
organization_url: https://dev.azure.com/your-org
project: YourProject
team: [...]
# NEW (0.2.0):
default_lookback_days: 1
orgs:
  - id: pcoe
    organization_url: https://dev.azure.com/your-org
    project: YourProject
    # tenant_id: <optional Entra tenant GUID>
    team: [...]

That's it — wrap your old config in orgs: and give the org a short id. The loader will tell you exactly what's wrong if you forget.


Architecture

Copilot Chat  ──(MCP tool call)──►  ado-team-activity-mcp (Python, stdio)
                                          │
                          ┌───────────────┼────────────────┐
                          ▼               ▼                ▼
                       ADO org A      ADO org B        local config.yaml
                    (tenant X)      (tenant Y)        (atomic + backed up)
                          ▲
                          │
                  DefaultAzureCredential per tenant (az login)

Read tools

Tool Purpose
list_orgs() What orgs are configured (id, URL, project, tenant, team size).
list_team_members(org=None) Roster for one org or every org.
get_teammate_activity(name, days=?, org=?, include_comments=True) One teammate's work-item activity over the window. If alias collides across orgs and org isn't given, returns needs_disambiguation with the candidate list.
get_team_activity(days=?, org=?, include_comments=True) Same, but for the whole roster of one org or every org.
summarize_contributions(name, days=180, org=?, ...) Aggregated stats for long windows: by-month with gaps, ownership, cadence, active items, comment samples. Use for trend / perf-review / quarterly questions.
get_work_item(id, org, include_comments=True) Drill into one item — fields + last 10 revisions + comments. org is required (IDs are per-org).
get_work_item_comments(id, org, top=50) Comments only. org required.

Discovery tools

Tool Purpose
discover_team_members(org, team_name=None) None → list ADO Teams in the org. With a team name → return its members (display_name, unique_name, is_admin).
apply_discovered_team(org, team_name, overwrite=False, dry_run=True) One-shot: pull members from ADO and merge into your config (with auto-generated unique aliases). Dry-runs by default.

Config-edit tools (all dry-run-by-default)

add_org, remove_org, add_team_member, update_team_member, remove_team_member, set_default_lookback_days — each accepts dry_run: bool = True. Dry-run returns a structured diff + before_yaml/after_yaml. Applying creates a timestamped .bak next to the config first, then writes atomically.

PM-workflow slash-prompts

These appear in Copilot Chat as /standup, /weekly_digest, /perf_review, /coverage_check, /cross_team_lookup. Each is a templated workflow bound to the right tools so you pick the workflow, not the implementation.

Cross-tenant re-auth — no crashes

If a tool fails because your az login is in the wrong tenant, you don't see a stack trace. You see:

{
  "error": "needs_reauth",
  "org_id": "contoso",
  "tenant_id": "00000000-0000-0000-0000-000000000000",
  "remediation": "az login --tenant 00000000-0000-0000-0000-000000000000",
  "detail": "..."
}

…which Copilot Chat will surface to you verbatim: "Run az login --tenant 00000000-... in your terminal."


Install (recommended path)

You need Python 3.11+, Azure CLI, and VS Code with GitHub Copilot Chat.

1. Install the server

pipx is the cleanest option (isolated venv, exposes the command globally):

pipx install ado-team-activity-mcp

If you don't have pipx:

python -m pip install --user pipx
python -m pipx ensurepath
# restart your shell, then:
pipx install ado-team-activity-mcp

Confirm it's on PATH:

where.exe ado-team-activity-mcp

2. Sign in to Azure DevOps

az login

Add --tenant <tenant-id> if your org lives in a non-default tenant. You can sign in to multiple tenants over time — the server caches a separate token per tenant.

3. Create your config

Save this as config.yaml somewhere stable, e.g. C:\Users\<you>\.ado-team-activity\config.yaml:

default_lookback_days: 1

orgs:
  - id: pcoe                                       # short id you pick — used as `org="pcoe"` arg
    organization_url: https://dev.azure.com/your-org
    project: YourProject
    # tenant_id: 72f988bf-86f1-41af-91ab-2d7cd011db47   # optional; set for cross-tenant orgs
    team: []                                       # start empty — let discover_team_members fill it

Tip: leave team: [] and ask Copilot to populate it for you (see "Auto-fill your roster" below).

4. Register the server with VS Code

Command Palette → "MCP: Open User Configuration" — add this under servers:

{
  "servers": {
    "ado-team-activity": {
      "type": "stdio",
      "command": "ado-team-activity-mcp",
      "env": {
        "ADO_ACTIVITY_CONFIG": "${userHome}/.ado-team-activity/config.yaml"
      }
    }
  }
}

${userHome} is a built-in VS Code variable — no per-user editing needed. If ${userHome} doesn't resolve, use the absolute path with forward slashes (e.g. C:/Users/<you>/.ado-team-activity/config.yaml).

If pipx's shim isn't on PATH (some Windows setups), set command to the absolute path you got from (Get-Command ado-team-activity-mcp).Source.

5. Reload VS Code

Then open Copilot Chat in Agent mode and try the examples below.


Auto-fill your roster from ADO (no manual typing)

Once an org is configured with team: [], just ask:

"Discover the team members of the PCOE Team in the pcoe org and add them to my config."

Copilot will:

  1. Call discover_team_members(org="pcoe") to list available ADO Teams.
  2. Call discover_team_members(org="pcoe", team_name="PCOE Team") to fetch members.
  3. Call apply_discovered_team(org="pcoe", team_name="PCOE Team", dry_run=True) and show you the diff.
  4. Wait for you to say "apply" before re-calling with dry_run=False. A timestamped .bak is created on apply.

Edit your config from chat

"Add Vibhuti to the pcoe org. Her UPN is v-vivasani@microsoft.com." "Mark Ashish as is_admin in the pcoe org." "Set default_lookback_days to 7."

Each goes through dry_run=True → diff shown → you confirm → atomic write + .bak. You can roll back any change by copying the .bak file back over config.yaml.


Example prompts

Day-to-day

  • What did Ashish work on yesterday?
  • Run a standup for the last 3 days. (invokes /standup)
  • Anything blocked on the team this week?
  • Tell me more about work item 1738 in the pcoe org.
  • What's the discussion on 1738?

Trend / review

  • Analyze Vibhuti's last 6 months. (routes via summarize_contributions)
  • Run a perf-review packet for Abhishek over 6 months. (invokes /perf_review)
  • Is Abhishek still active in this project?

Multi-org

  • Compare Ashish across pcoe and contoso. (invokes /cross_team_lookup)
  • Give me a weekly digest for every org. (invokes /weekly_digest)

Coverage / risk

  • Find Active items still assigned to absent owners. (invokes /coverage_check)

Privacy & security

  • Read-only against ADO. The server calls only query_by_wiql, get_work_items, get_work_item, get_revisions, get_comments, get_projects, get_teams, get_team_members_with_extended_properties. No create/update/delete endpoints exist in the code.
  • Writes are local-only, always dry-run-by-default, always preceded by a .bak.<timestamp> backup of your config.
  • Tokens live in memory (per-tenant cache), refreshed automatically before expiry. No PAT in config, no credentials in YAML.
  • No telemetry. Network traffic is only to Azure DevOps and Entra ID for token acquisition.
  • Roster is local to you. Every manager keeps their own config.yaml.

Troubleshooting

Symptom Fix
ado-team-activity-mcp: command not found pipx ensurepath, restart shell (and fully quit VS Code from the tray, not just reload). Or pin the absolute path in mcp.json.
Config file uses the old single-org format Wrap your old config in orgs: as the loader's error message describes.
error: needs_reauth in a tool response Run the remediation command from the payload verbatim (az login or az login --tenant <id>).
error: needs_disambiguation The alias exists in multiple orgs. Re-call the tool with org="<one of the candidates>".
error: unknown_name Check list_team_members(). If the person isn't there, ask Copilot to add them or run discover_team_members to pull them from ADO.
Zero items for someone you know is active Their unique_name doesn't match ADO's UPN. Open a work item assigned to them in ADO, click the Assignee chip, and use the email shown under their name.

Develop locally (contributors)

git clone <repo-url>
cd ado-team-activity-mcp
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e ".[dev]"
Copy-Item config.example.yaml config.yaml          # then fill in
az login
python scripts\check_auth.py                        # per-org pre-flight
pytest                                              # 24 tests

The workspace's .vscode/mcp.json is wired for development — runs the server out of the local .venv using python -m ado_activity_mcp. Reload VS Code and the server is available alongside any pipx-installed copy.

Publish a new version (maintainer)

# bump version in pyproject.toml first
pip install --upgrade build twine
python -m build
twine upload dist/*

Needs a PyPI account and an API token saved in ~/.pypirc.


License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ado_team_activity_mcp-0.2.0.tar.gz (26.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ado_team_activity_mcp-0.2.0-py3-none-any.whl (25.7 kB view details)

Uploaded Python 3

File details

Details for the file ado_team_activity_mcp-0.2.0.tar.gz.

File metadata

  • Download URL: ado_team_activity_mcp-0.2.0.tar.gz
  • Upload date:
  • Size: 26.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for ado_team_activity_mcp-0.2.0.tar.gz
Algorithm Hash digest
SHA256 4ac832eb1f68d08d058ea76cf73c7353da1e4dc23d7f7012e06342876fe234b6
MD5 5f4796f221c92d5204f6537621810681
BLAKE2b-256 4e5be71902c97e7de99bacac8c1db91469813e570d693825917f7e2a3f7625fd

See more details on using hashes here.

File details

Details for the file ado_team_activity_mcp-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for ado_team_activity_mcp-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8daad6600db3e951419bc38f14a922f44db4b1850100b0610dc12760f4cfedd5
MD5 c21f3c1e736d54ac91e9656ec209edc5
BLAKE2b-256 61ce095bc5b6a5a0dbee6479300c95f32f868bb6014e92ecc411ca11eff2b51d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page