Metadata-Version: 2.4
Name: ado-team-activity-mcp
Version: 0.4.0
Summary: 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'.
Author-email: Ashish <ashish301201@gmail.com>
License: MIT
License-File: LICENSE
Keywords: ado,azure-devops,copilot,mcp,standup,team,vscode,wiql
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Bug Tracking
Classifier: Topic :: Software Development :: Version Control
Requires-Python: >=3.11
Requires-Dist: azure-devops>=7.1.0b4
Requires-Dist: azure-identity>=1.15.0
Requires-Dist: mcp[cli]>=1.0.0
Requires-Dist: msrest>=0.7.1
Requires-Dist: pydantic>=2.5.0
Requires-Dist: python-dateutil>=2.8.2
Requires-Dist: pyyaml>=6.0.1
Requires-Dist: requests>=2.31
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: twine>=5.1; extra == 'dev'
Description-Content-Type: text/markdown

# 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 `pcoe` and `contoso` orgs."* 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

```powershell
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

```powershell
az login
```

Use `az login --tenant <tenant-id>` if your org is in a non-default tenant.

### 3. Auto-create your config

```powershell
ado-team-activity-mcp init --discover
```

This:
1. Finds every ADO org reachable via your `az login`
2. Lists their projects (you pick which to add)
3. For each picked project, lists ADO Teams **and** scans recent contributors (last 360 days)
4. Merges into a deduped roster — catches both formally-assigned team members AND people who actually do work but aren't on a team
5. Writes `~/.ado-team-activity/config.yaml`
6. Prints the exact `mcp.json` snippet 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.

```yaml
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:

```json
{
  "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

```powershell
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`](https://github.com/) 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)

```powershell
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](LICENSE).
