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
Ask Copilot Chat in VS Code about your team's Azure DevOps work — in plain English.
A local Model Context Protocol (MCP) server that turns your ADO orgs into something a manager / PM / tech lead can interrogate from the chat panel.
"What did Ashish work on yesterday?" "Give me a standup for the team for the last 3 days." "Analyze Vibhuti's last 6 months — is she ramping up or down?" "Anything blocked on the team this week?" "Run a perf-review packet for Abhishek over 6 months."
Read-only against ADO. Multi-org, multi-tenant. No PATs in config — uses your existing az login.
Why this exists
Tracking what your team is actually doing in Azure DevOps means clicking through dashboards, hand-rolling WIQL queries, or pestering people for status updates. This MCP server lets your AI assistant do the legwork:
- Standups — "What did the team ship yesterday?" gets a real, dated, linked answer in seconds.
- 1:1 prep — "What's on
<alias>'s plate right now? Any blockers in the comments?" before every 1:1. - Perf reviews — "Pull a 6-month contribution packet for
<alias>— ownership, cadence, gap months, active items." Honest evidence instead of vibes. - Coverage gaps — "Find Active items assigned to teammates who haven't logged anything in 30+ days." Catch orphan work before it ages.
- Cross-team / cross-org rollups — "Compare Ashish across the
pcoeandcontosoorgs." One question, multiple ADOs. - Triage — "Tell me more about WI 1738 — what's the discussion say?" Pulls full comment thread.
Use cases — what you actually get back
"What did Ashish work on yesterday?"
Returns a structured digest grouped by activity bucket (assigned_and_changed, changed_by, created_by, closed_by) — each item links back to ADO. Comments are pulled by default, so the model can mention blockers like "Doc Intelligence 403 raised Jun 1, resolved Jun 2."
"Standup for the team for the last 3 days"
Walks every teammate in your config, in one round-trip per org. Returns per-person item lists. Copilot turns it into a "Yesterday / Today / Blockers" digest you can paste into Slack.
"Analyze <alias>'s last 6 months"
Routes to summarize_contributions — returns server-side aggregations:
- by_month with gap months surfaced explicitly (catches silent periods)
- ownership: User Stories owned, Bugs resolved, Active items still open
- cadence: same-day-close ratio (catches "I closed 14 tickets on March 16" backlog cleanups)
- comment samples — so you can judge documentation quality without a second tool call
Copilot then writes a manager-ready review with honest gaps highlighted.
"Anything blocked across the team this week?"
Pulls team activity, scans titles + tags + comment text for "blocked" / "waiting on" / Blocked state. Lists them with owner and link.
"Refresh my roster"
Calls refresh_roster — pulls fresh members from ADO Teams (and/or recent contributors), reports new joiners + departures, dry-runs the diff, waits for your confirmation before writing.
"Discover what orgs I have access to and add them"
One-time setup. Calls init --discover for you under the hood (or you can run it from the terminal). Auto-populates every org + project + roster you can see.
3-minute setup
You need Python 3.11+, Azure CLI, VS Code with GitHub Copilot Chat.
1. Install
python -m pip install --user pipx
python -m pipx ensurepath
# Close PowerShell + fully quit VS Code, then reopen:
pipx install ado-team-activity-mcp
ado-team-activity-mcp --version
2. Sign in to Azure DevOps
az login
Use az login --tenant <tenant-id> if your org is in a non-default tenant.
3. Auto-create your config
ado-team-activity-mcp init --discover
This:
- Finds every ADO org reachable via your
az login - Lists their projects (you pick which to add)
- For each picked project, lists ADO Teams and scans recent contributors (last 360 days)
- Merges into a deduped roster — catches both formally-assigned team members AND people who actually do work but aren't on a team
- Writes
~/.ado-team-activity/config.yaml - Prints the exact
mcp.jsonsnippet you paste into VS Code's user MCP config
4. Register with VS Code
Command Palette → "MCP: Open User Configuration" → paste the snippet init printed.
5. Reload VS Code
Command Palette → "Developer: Reload Window". Open Copilot Chat, switch to Agent mode, ask:
call list_orgs
You'll see your configured orgs. Then try a real question.
What it can do — full tool reference
Read tools (no writes)
| Tool | What it does |
|---|---|
list_orgs() |
What's configured (id, URL, project, tenant, team size). |
list_team_members(org=None) |
Roster for one org or all orgs. |
get_teammate_activity(name, days=?, org=?, include_comments=True) |
One teammate's items over the window. Comments by default. If alias collides across orgs without org=, returns needs_disambiguation. |
get_team_activity(days=?, org=?, include_comments=True) |
Whole-roster sweep — one org or all. Per-org needs_reauth propagated. |
summarize_contributions(name, days=180, org=?) |
Long-window aggregations: by-month gaps, ownership, cadence, active items, comment samples. Use for trend/perf/quarter questions. |
get_work_item(id, org, include_comments=True) |
One item — fields + last 10 revisions + comments. org required (IDs are per-org). |
get_work_item_comments(id, org, top=50) |
Comments only. org required. |
Discovery + config-write tools
All writes are dry-run-by-default — return a structured diff, you confirm, then a .bak.<timestamp> is made before atomic save.
| Tool | What it does |
|---|---|
discover_team_members(org, team_name=None) |
List ADO Teams in a project, or fetch members of one team. |
apply_discovered_team(org, team_name, overwrite=False, dry_run=True) |
Merge one team's members into config. |
refresh_roster(org=None, source='teams', contributors_days=360, remove_departed=False, dry_run=True) |
Resync roster(s) from ADO. source='contributors' catches people NOT on any team. 'both' = union. Reports new joiners + departures. |
add_org / remove_org |
Org-level edits. |
add_team_member / update_team_member / remove_team_member |
Roster edits. |
set_default_lookback_days |
Change the default day window. |
Slash-prompts (PM workflows)
Type / in Copilot Chat to invoke:
/standup— daily standup digest, grouped by person, blockers first./weekly_digest— themes from the last 7 days, with coverage suggestions./perf_review— 6-month evidence packet for one person, refuses to recommend a raise % (that needs comp data outside ADO)./coverage_check— finds Active items assigned to absent owners; suggests reassignment./cross_team_lookup— resolves a name across every configured org.
Multi-org / multi-tenant — really
The config supports any number of ADO orgs, each in any Entra tenant. Per-tenant tokens are cached automatically.
default_lookback_days: 1
orgs:
- id: pcoe
organization_url: https://dev.azure.com/your-org
project: YourProject
# tenant_id is optional; set it for cross-tenant orgs
team: [...]
- id: contoso
organization_url: https://dev.azure.com/Contoso
project: ContosoApp
tenant_id: 00000000-0000-0000-0000-000000000000
team: [...]
When a tool fails because your az login is in the wrong tenant, the response is a structured needs_reauth payload — Copilot will tell you exactly what to run:
{
"error": "needs_reauth",
"remediation": "az login --tenant 00000000-0000-0000-0000-000000000000",
"org_id": "contoso"
}
No stack traces.
Setup variations
Power-user init --discover flags
ado-team-activity-mcp init --discover \
--orgs all \
--all-projects \
--source both \
--contributors-days 360
| Flag | Effect |
|---|---|
--orgs name1,name2 or --orgs all |
Non-interactive org pick |
--all-projects |
Add every project in each org |
--source teams|contributors|both|none |
How to populate rosters (default both) |
--contributors-days N |
Activity lookback for contributor discovery (default 360) |
--team "Team A,Team B" or --team all |
Non-interactive team pick |
--skip-members |
Empty rosters (you'll populate later) |
--tenant <id> |
Scope discovery to a specific tenant |
--config <path> |
Custom save location |
--force |
Overwrite an existing config (auto-backup first) |
Don't want auto-discovery?
Skip step 3 and create config.yaml by hand — example template lives at config.example.yaml in the source tree. The schema is small.
Don't want pipx?
Plain pip install --user ado-team-activity-mcp works too. You'll just need to find the installed exe path with (Get-Command ado-team-activity-mcp).Source and use that as the command in your mcp.json.
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. There are zero create/update/delete endpoints anywhere. - Writes are local-only (your
config.yaml), always dry-run-by-default, always preceded by a timestamped.bak. - Tokens stay in memory — per-tenant cache, refreshed before expiry. No PAT in config, no credentials in YAML.
- No telemetry. Network traffic is only to Azure DevOps + 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 + fully quit VS Code. Or pin the absolute path from (Get-Command ado-team-activity-mcp).Source into mcp.json. |
PermissionError writing config |
Re-run with --config "$HOME\.ado-team-activity\config.yaml" (default since 0.3.3 — this should never happen on fresh installs). |
init --discover finds 0 orgs |
Your orgs are in a different tenant. Re-run with --tenant <tenant-id>. |
error: needs_reauth in a tool response |
Run the remediation command from the payload verbatim. |
error: needs_disambiguation |
Alias exists in multiple orgs. Re-call with org="<one of the candidates>". |
| Tool not visible in Copilot Chat | Reload the VS Code window after editing user MCP config. |
| Zero items for someone you know is active | Their unique_name doesn't match their ADO UPN. Re-copy from the Assignee chip on a real work item. |
Develop locally (contributors)
git clone <repo>
cd ado-team-activity-mcp
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e ".[dev]"
az login
python scripts\check_auth.py
pytest
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ado_team_activity_mcp-0.4.0.tar.gz.
File metadata
- Download URL: ado_team_activity_mcp-0.4.0.tar.gz
- Upload date:
- Size: 36.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
15d273e02067256f648aad89dc600b79aa0087cb7da133188582569e729176b2
|
|
| MD5 |
7b9d3dca8c7bb6095ec3f2785d611cc2
|
|
| BLAKE2b-256 |
d0b4c22eb65c425305b0348408c556b9d8c19b094480e7018b6cbcd5e595c7ba
|
File details
Details for the file ado_team_activity_mcp-0.4.0-py3-none-any.whl.
File metadata
- Download URL: ado_team_activity_mcp-0.4.0-py3-none-any.whl
- Upload date:
- Size: 37.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b2e3761dc66023a90d0868bfe318fc7d5236423bfc6e54e8b4af82dd2a27b986
|
|
| MD5 |
2972cfbde1df261218fea13b554734d9
|
|
| BLAKE2b-256 |
ae95362ca0d1c2cd7ce4e7c58dd23d0a67254366d5b3b5c603a77f4efe46c76f
|