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

Easy mode — auto-discover every ADO org you have access to:

ado-team-activity-mcp init --discover

This finds every org reachable via your az login, lists their projects, asks which to add, and writes a valid config.yaml for you. Then prints the exact mcp.json snippet to paste into VS Code.

Useful flags:

  • --config <path> — write somewhere other than $HOME\.ado-team-activity\config.yaml
  • --orgs all / --orgs name1,name2 — skip the interactive prompt
  • --all-projects — when an org has multiple projects, add every one
  • --tenant <tenant-id> — scope discovery to a specific Entra tenant
  • --force — overwrite an existing config (a timestamped .bak is made first)

Manual mode — create the file yourself:

mkdir $HOME\.ado-team-activity
notepad $HOME\.ado-team-activity\config.yaml

Paste this and edit the values:

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.3.3.tar.gz (35.2 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.3.3-py3-none-any.whl (35.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: ado_team_activity_mcp-0.3.3.tar.gz
  • Upload date:
  • Size: 35.2 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.3.3.tar.gz
Algorithm Hash digest
SHA256 1649c5e874c626b850770238b73b99f4f39b40ed5eebe7297da446de431af3b6
MD5 aa298697f8ab0d190bd9f38a429b57ae
BLAKE2b-256 b6239a146d4f2f62d5377d39128d0d1fabc4bedfd9e4ef0a55bef361c0d7ab06

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ado_team_activity_mcp-0.3.3-py3-none-any.whl
Algorithm Hash digest
SHA256 65dbf15195733f50c3ccfdf32be3ba04ae47db18b2fef6dd413a3e08cec6d1f2
MD5 b52ed7590bab37a6006ac73d9a7e89ec
BLAKE2b-256 ff7a06c28bd978faac8a4f66e905d55cf0de607d3e39446f9493635dbe961611

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