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:
- Call
discover_team_members(org="pcoe")to list available ADO Teams. - Call
discover_team_members(org="pcoe", team_name="PCOE Team")to fetch members. - Call
apply_discovered_team(org="pcoe", team_name="PCOE Team", dry_run=True)and show you the diff. - Wait for you to say "apply" before re-calling with
dry_run=False. A timestamped.bakis 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 viasummarize_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
Release history Release notifications | RSS feed
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.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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4ac832eb1f68d08d058ea76cf73c7353da1e4dc23d7f7012e06342876fe234b6
|
|
| MD5 |
5f4796f221c92d5204f6537621810681
|
|
| BLAKE2b-256 |
4e5be71902c97e7de99bacac8c1db91469813e570d693825917f7e2a3f7625fd
|
File details
Details for the file ado_team_activity_mcp-0.2.0-py3-none-any.whl.
File metadata
- Download URL: ado_team_activity_mcp-0.2.0-py3-none-any.whl
- Upload date:
- Size: 25.7 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 |
8daad6600db3e951419bc38f14a922f44db4b1850100b0610dc12760f4cfedd5
|
|
| MD5 |
c21f3c1e736d54ac91e9656ec209edc5
|
|
| BLAKE2b-256 |
61ce095bc5b6a5a0dbee6479300c95f32f868bb6014e92ecc411ca11eff2b51d
|