mcp-azure-devops-server
# 🔷 mcp-azure-devops-server
[](LICENSE)




[](https://modelcontextprotocol.io)


[](https://github.com/Tiberriver256/mcp-server-azure-devops)
Servidor [MCP](https://modelcontextprotocol.io) que conecta assistentes de IA (Claude Code, VS Code, Claude Desktop, Cursor) a uma instância **on-premise** do **Azure DevOps Server 2022**.
> Baseado no [Azure DevOps MCP Server](https://github.com/Tiberriver256/mcp-server-azure-devops), de Micah Rairdon, e adaptado para uso exclusivo com o Azure DevOps Server on-premise. Detalhes na seção **Créditos**, no final.
## 🧰 Tools
> 🚧 **Projeto em construção.** Por enquanto só a área de **Work Items** está disponível. As demais áreas serão adicionadas aos poucos.
| Área | Tools | Status |
|---|---|:---:|
| **Work Items** | `list_work_items`, `get_work_item`, `create_work_item`, `update_work_item` | ✅ Disponível |
| Projetos | — | 🗓️ Planejado |
| Repositórios | — | 🗓️ Planejado |
| Pull Requests | — | 🗓️ Planejado |
| Pipelines | — | 🗓️ Planejado |
| Wiki | — | 🗓️ Planejado |
| Busca | — | 🗓️ Planejado |
| Tool | O que faz | Escreve no Azure DevOps? |
|---|---|:---:|
| `list_work_items` | Lista work items por filtros, consulta salva ou WIQL | 👀 não |
| `get_work_item` | Detalhes completos de um work item pelo ID | 👀 não |
| `create_work_item` | Cria tarefa, bug, história, épico etc., com vínculo ao item pai | ✍️ **sim** |
| `update_work_item` | Altera campos, estado, tags e registra comentários | ✍️ **sim** |
Os parâmetros de cada tool estão na seção **Referência das tools**, mais abaixo.
## 💡 Exemplos de uso
Com o servidor registrado, basta conversar com o assistente: ele decide sozinho quando chamar cada tool. Os pedidos abaixo foram escritos para o Claude Code, mas funcionam em qualquer cliente MCP.
### 📝 Escrever histórias de usuário e registrá-las no Boards
> Leia `docs/requisitos-exportacao.md`, escreva as histórias de usuário com critérios de aceite no formato Dado/Quando/Então e registre cada uma no Boards como filha da Feature 1200, na Sprint 14. Antes de criar, me mostre a lista para eu aprovar.
O Claude redige as histórias, mostra o rascunho e, depois da sua aprovação, chama `create_work_item` uma vez por história, com `parentId`, `iterationPath` e `acceptanceCriteria`. No fim, devolve o ID e o link de cada card.
### 🐛 Registrar um bug encontrado durante a implementação
> Enquanto mexíamos no `PedidoService`, vimos que o desconto é aplicado duas vezes quando o cupom é reutilizado. Não corrija agora: abra um Bug com os passos para reproduzir em Repro Steps, o arquivo e a linha envolvidos, prioridade 2 e a tag `debito-tecnico`.
O bug fica registrado para correção futura e você não perde o foco da tarefa atual. Como o Claude já está com o código aberto, o card sai com arquivo, linha e a causa provável, detalhes que costumam se perder quando o registro fica para depois.
Para tornar isso um hábito, adicione uma regra ao `CLAUDE.md` do projeto:
```markdown
Ao encontrar um bug fora do escopo da tarefa atual, não o corrija. Registre-o como Bug
no Azure DevOps, com passos para reproduzir e a tag `encontrado-em-dev`, me informe o
ID e continue a tarefa.
```
### 🛠️ Implementar a partir de um card
> Leia a US 890 e implemente de acordo com os critérios de aceite.
`get_work_item` traz a descrição, os critérios de aceite e os itens relacionados. Assim o Claude trabalha com o requisito registrado no card, e não com um resumo que você teria de digitar.
### 🧩 Quebrar uma história em tarefas
> Quebre a US 890 em tarefas técnicas de backend, frontend e testes, atribua todas a mim e vincule-as como filhas da US.
### ✅ Atualizar o card ao terminar
> Terminei a US 890. Mova para Resolved e comente no card um resumo do que mudou, com o hash do commit.
`update_work_item` muda o estado e grava o comentário na aba *Discussion*.
### 🔎 Consultar e triar o backlog
> Quais bugs ativos da área `Portal\Backend` estão sem responsável? Ordene por prioridade.
> O que está atribuído a mim na Sprint 14 e ainda está em New?
> Rode a consulta salva "Bugs críticos" e me diga o que mudou desde ontem.
### 🎯 Dicas
- 👀 **Peça revisão antes de criar em lote.** "Me mostre antes de criar" evita dezenas de cards criados com base num requisito mal interpretado.
- 🏷️ **Informe o tipo e o item pai.** Os nomes dos tipos variam conforme o processo: *User Story* no Agile, *Product Backlog Item* no Scrum, *Requirement* no CMMI e *Issue* no Basic.
- 🐞 **Em Bugs, peça os passos em Repro Steps.** Nos processos Agile, Scrum e CMMI, o formulário de Bug exibe o campo *Repro Steps* (`Microsoft.VSTS.TCM.ReproSteps`) e não *Description*. Sem esse pedido, os passos vão para um campo que o formulário não mostra.
- 🔔 **Tudo o que for gravado leva o seu nome.** Cards e comentários aparecem como criados pelo dono do PAT e geram notificações para o time.
## ✨ Características
- 🏢 **Só on-premise.** Fala com a REST API no formato `http(s)://<servidor>/<collection>/_apis/...`, autenticando com Personal Access Token (PAT) via header `Authorization: Basic`. Não há nenhum fluxo OAuth/Entra ID — isso é exclusivo do Azure DevOps Services (cloud) e não se aplica aqui.
- 🎛️ **Sem nada hardcoded.** URL do servidor, collection, PAT e versão da API vêm todos de variáveis de ambiente.
- 🔒 **Local e sem telemetria.** Roda via stdio. A única saída de rede é para o `ADO_SERVER_URL` que você configurar.
- 🪶 **Sem dependências de HTTP.** Usa o `fetch` nativo do Node, o que mantém `ADO_API_VERSION` realmente configurável (SDKs oficiais fixam a versão da API por método) e dá controle sobre TLS corporativo.
- 🧪 **174 testes unitários**, todos com a API mockada — nenhuma chamada de rede real.
## 📋 Requisitos
- Node.js 20.11 ou superior (testado em 24.x)
- Um PAT do Azure DevOps Server com escopo **Work Items (Read, write, & manage)**
## 📦 Instalação
```bash
npm install
npm run build
```
## ⚙️ Configuração
Copie `.env.example` para `.env` e preencha:
```bash
cp .env.example .env
```
| Variável | Obrigatória | Padrão | Descrição |
|---|:---:|---|---|
| `ADO_SERVER_URL` | sim | — | URL base da instância, **sem** a collection e **sem** `/_apis`. Ex.: `https://devops.empresa.local` ou `http://tfs.empresa.local:8080/tfs` |
| `ADO_COLLECTION` | sim | — | Nome da Project Collection. Ex.: `DefaultCollection` |
| `ADO_PAT` | sim | — | Personal Access Token |
| `ADO_API_VERSION` | não | `7.1` | Versão da REST API. O Azure DevOps Server 2022 suporta `7.1`; o 2022.1 também aceita `7.2-preview` |
| `ADO_DEFAULT_PROJECT` | não | — | Projeto usado quando a tool é chamada sem `project`. Reduz muito os erros do assistente ao adivinhar nomes |
| `ADO_REQUEST_TIMEOUT_MS` | não | `30000` | Timeout por requisição |
| `ADO_MAX_RETRIES` | não | `2` | Tentativas extras em 429/5xx e falhas de rede |
| `LOG_LEVEL` | não | `info` | `debug`, `info`, `warn`, `error` ou `silent`. O PAT nunca é gravado em log |
| `ADO_TLS_REJECT_UNAUTHORIZED` | não | `true` | `false` desliga a verificação de certificado TLS. **Inseguro**, só para laboratório |
| `NODE_EXTRA_CA_CERTS` | não | — | Caminho para o CA da organização. É o caminho correto para certificado interno |
### 🔑 Como gerar o PAT
1. Acesse `<ADO_SERVER_URL>/<ADO_COLLECTION>/_usersSettings/tokens`
2. **New Token**, defina a validade
3. Em *Scopes*, marque **Work Items → Read, write, & manage**
4. Copie o token — ele só aparece uma vez
### 🩺 Verificando a configuração
Antes de plugar no VS Code, confirme que o servidor alcança o Azure DevOps:
```bash
node dist/index.js --check
```
Saída esperada:
```
Conexão OK.
Servidor: https://devops.empresa.local
Collection: DefaultCollection
API: 7.1
Projeto: MeuProjeto
```
Qualquer falha aqui vem com a mensagem já traduzida (PAT inválido, servidor inacessível, certificado não confiável, collection errada).
## 💻 Registrando no VS Code
Crie ou edite `.vscode/mcp.json` no seu workspace — ou o `mcp.json` global, via `MCP: Open User Configuration` na paleta de comandos:
```jsonc
{
"servers": {
"azure-devops": {
"type": "stdio",
"command": "node",
"args": ["C:\\mcp-azure-devops-server\\dist\\index.js"],
"env": {
"ADO_SERVER_URL": "https://devops.empresa.local",
"ADO_COLLECTION": "DefaultCollection",
"ADO_PAT": "${input:ado-pat}",
"ADO_API_VERSION": "7.1",
"ADO_DEFAULT_PROJECT": "MeuProjeto"
}
}
},
"inputs": [
{
"id": "ado-pat",
"type": "promptString",
"description": "Personal Access Token do Azure DevOps Server",
"password": true
}
]
}
```
O bloco `inputs` faz o VS Code pedir o PAT na primeira execução e guardá-lo com segurança, em vez de deixá-lo em texto puro num arquivo versionado. Se preferir usar o `.env` do projeto, basta omitir `env` do `mcp.json` — mas isso só funciona quando o workspace aberto é a própria pasta deste repositório, porque o `.env` é lido a partir do diretório de trabalho do processo.
Depois de salvar, abra a paleta e rode **MCP: List Servers** para confirmar que `azure-devops` aparece como iniciado, e verifique as tools no seletor de ferramentas do Chat.
## 🤖 Registrando no Claude Code
Cada cliente MCP tem seu próprio registro e **nenhum lê o do outro**: o `.vscode/mcp.json` da seção anterior é exclusivo do VS Code. Para o Claude Code o registro fica em `~/.claude.json` (escopos `local` e `user`) ou num `.mcp.json` na raiz do projeto (escopo `project`).
Vale repetir o que isso significa na prática: **não existe "subir" o servidor**. Não há daemon, porta nem `npm start` rodando em segundo plano. Quem cria o processo é o cliente — o Claude Code executa `node dist/index.js` ao iniciar, conversa JSON-RPC pelo stdin/stdout e encerra o processo ao fechar. O que você precisa deixar pronto é o build e o registro.
### 1️⃣ Build
```bash
npm install
npm run build
```
Obrigatório: o que roda é o `dist/`, não o `src/`, e o `dist/` não é versionado. Repita o `npm run build` a cada alteração no código.
### 2️⃣ Registrar
```bash
claude mcp add azure-devops --scope user \
-e ADO_SERVER_URL=https://devops.empresa.local \
-e ADO_COLLECTION=DefaultCollection \
-e ADO_PAT=SEU_PAT_AQUI \
-e ADO_API_VERSION=7.1 \
-e ADO_DEFAULT_PROJECT=MeuProjeto \
-- node /caminho/absoluto/para/mcp-azure-devops-server/dist/index.js
```
No PowerShell, troque a continuação de linha `\` por crase (`` ` ``) ou escreva tudo em uma linha só. O `--` separa os flags do `claude` do comando do servidor; use caminho absoluto, com barras normais.
| Escopo | Onde grava | Quando usar |
|---|---|---|
| `local` (padrão) | `~/.claude.json`, sob o projeto atual | Testar sem afetar outros projetos |
| `user` | `~/.claude.json`, global | Uso normal — as tools ficam disponíveis em qualquer projeto |
| `project` | `.mcp.json` na raiz, versionado | Compartilhar a configuração com o time. **Nunca** com o PAT inline — use `"ADO_PAT": "${ADO_PAT}"`, que o Claude Code expande a partir do ambiente |
### 3️⃣ Verificar
Reinicie o Claude Code — o registro só é lido no boot. Depois:
```bash
claude mcp list
```
`azure-devops` deve aparecer como **Connected**. Dentro da sessão, `/mcp` mostra o servidor e suas quatro tools.
### ❓ Por que passar `env` aqui é obrigatório
O servidor carrega o `.env` a partir do **diretório de trabalho do processo**, e quem define esse diretório é o cliente: é o projeto onde você abriu o Claude Code, não a pasta deste repositório. Só quando você abre o Claude Code dentro do próprio `mcp-azure-devops-server` é que o `.env` é encontrado sozinho. Em qualquer outro projeto, sem `-e` o servidor sobe e falha com:
```
Configuração inválida. Corrija as variáveis de ambiente:
- ADO_SERVER_URL: Invalid input: expected string, received undefined
- ADO_PAT: Invalid input: expected string, received undefined
```
Alternativa ao `-e`, que evita o PAT em texto puro no `~/.claude.json`: defina as variáveis no ambiente do usuário do sistema operacional. O processo filho as herda independentemente do diretório, e o registro fica só `claude mcp add azure-devops --scope user -- node /caminho/para/dist/index.js`. No Windows, `setx ADO_PAT "..."` (exige reabrir o terminal ou o VS Code); em Linux/macOS, exporte no `~/.bashrc` ou `~/.zshrc`.
### 🔄 Ciclo de desenvolvimento
Alterou o `src/` → `npm run build` → **reinicie o Claude Code**. O processo do servidor nasce no boot do cliente, então rebuildar sem reiniciar não muda nada na sessão em andamento.
### 👥 Instalando na máquina de outra pessoa
O transporte é stdio: o servidor roda como processo local, na mesma máquina do cliente. Não há instância central para apontar. Cada pessoa precisa:
1. Clonar o repositório (ou receber a pasta) e rodar `npm install && npm run build`;
2. Gerar o **próprio PAT** em `<servidor>/<collection>/_usersSettings/tokens` — o PAT é pessoal e intransferível, e toda criação, edição ou comentário feito pelas tools aparece no Azure DevOps como autoria de quem gerou o token;
3. Rodar o `claude mcp add` com os caminhos e o PAT dela.
Um `.mcp.json` versionado (escopo `project`) com `"ADO_PAT": "${ADO_PAT}"` resolve o passo 3 para o time inteiro: cada pessoa só precisa ter a variável no ambiente.
## 🔌 Outros clientes MCP
Em qualquer outro cliente que fale stdio (Claude Desktop, Cursor), os ingredientes são os mesmos — comando `node`, argumento com o caminho absoluto de `dist/index.js` e as variáveis em `env` — mas cada um tem seu próprio arquivo de registro, em formato próprio. Consulte a documentação do cliente para saber onde ele procura.
## 📚 Referência das tools
### 📋 `list_work_items`
Lista work items de um projeto. Três formas de filtrar:
- **Filtros diretos:** `assignedTo` (aceita `@me`), `states`, `workItemTypes`, `areaPath`
- **`queryId`:** executa uma consulta salva pelo GUID
- **`wiql`:** consulta WIQL completa, para critérios que os filtros não cobrem
Retorna no máximo 200 itens por chamada (padrão 50), com `skip` para paginar e `totalMatched` com o total encontrado.
### 🔍 `get_work_item`
Detalhes completos de um work item pelo ID: descrição, critérios de aceite, responsável, datas, campos customizados e relações. `expand: "none"` + `fields` traz só o que interessa quando se quer economizar contexto.
### ➕ `create_work_item`
Cria um work item. Exige `workItemType` e `title`. Aceita descrição, critérios de aceite, responsável, área, sprint, prioridade, tags, `parentId` (cria o vínculo hierárquico) e `additionalFields` para campos customizados — é por ele que vão os passos de reprodução de um Bug (`Microsoft.VSTS.TCM.ReproSteps`).
### ✏️ `update_work_item`
Atualiza campos e/ou registra comentário (vai para `System.History`, a aba *Discussion*). Só envia os campos informados. Para tags:
- `tags` **substitui** a lista inteira (`[]` limpa tudo)
- `tagsToAdd` / `tagsToRemove` alteram incrementalmente, preservando as demais
### 📌 Observações que valem para todas
- **Campos de texto longo são HTML**, não Markdown e nunca CDATA: descrição, critérios de aceite, passos de reprodução, comentários.
- **IDs de work item são únicos na collection inteira**, então `project` é opcional em `get_work_item` e `update_work_item`.
- Campos customizados vão por **nome de referência** (`Custom.Sistema`), não pelo rótulo da tela.
## 🛠️ Desenvolvimento
```bash
npm run dev # execução com recarga automática
npm test # testes unitários
npm run test:watch # testes em watch
npm run test:coverage # cobertura
npm run typecheck # checagem de tipos
npm run build # compila para dist/
```
### 🗂️ Estrutura
```
src/
index.ts entry point (stdio) e modo --check
server.ts cria o McpServer e registra as features
config/env.ts leitura e validação das env vars com zod
clients/
azure-devops-client.ts HTTP: Basic+PAT, retry, paginação, erros
url-builder.ts URLs on-premise e escape de literais WIQL
features/work-items/
schemas.ts contrato único de entrada/saída
tool-definitions.ts descrições em linguagem natural para a LLM
index.ts registra as tools no servidor
mapper.ts API crua -> formato enxuto
patch-document.ts construção do JSON Patch
wiql.ts montagem segura de consultas WIQL
work-item-api.ts leitura em lote (limite de 200 IDs)
<tool>/{schema,feature,index}.ts
shared/errors/ hierarquia de erros + tradução de mensagens
shared/logger.ts log local em stderr, com redação do PAT
types/azure-devops.ts tipos da REST API
tests/ espelha src/, com a API mockada
```
### 🧱 Adicionando uma nova área
Cada área entra em `src/features/<nome>/`, seguindo o mesmo formato de work items (`<tool>/{schema,feature,index}.ts` e um `tool-definitions.ts` com as descrições para a LLM), e é ativada com uma linha em [server.ts](src/server.ts). Ao terminar, atualize a tabela da seção **Tools**.
### 🧠 Decisões de design
**Log sempre em `stderr`.** No transporte stdio o `stdout` é o canal JSON-RPC; um único `console.log` corrompe a sessão e o cliente desconecta.
**401 e 403 são erros diferentes.** 401 é PAT inválido ou expirado; 403 é PAT válido sem o escopo necessário. As soluções são distintas, então as mensagens também são.
**Página de login do IIS é tratada como erro de autenticação.** Em on-premise é comum o servidor responder `200`/`203` com o HTML da tela de login quando o PAT é inválido, em vez de `401`. Sem essa detecção, o HTML chegaria ao assistente como se fosse resposta legítima da API.
**Erros viram `isError: true`, não exceção.** A tool devolve a mensagem traduzida e acionável, o que permite ao modelo se corrigir sozinho em vez de apenas reportar a falha.
**Literais de WIQL são escapados.** Um projeto chamado `Cliente's App` quebraria a consulta; sem escape, argumentos de tool poderiam injetar cláusulas WIQL.
**Leitura em lote fatiada em 200 IDs.** Acima disso o endpoint `wit/workitems?ids=` responde 400.
**`op: replace` para substituir tags.** O Azure DevOps trata `op: add` em `System.Tags` como merge; `replace`, por sua vez, falha se o campo estiver vazio. O código lê o estado atual e escolhe o operador certo.
## 🧯 Solução de problemas
| Sintoma | Causa provável |
|---|---|
| `Falha de autenticação ... página de login` | PAT inválido, expirado, ou gerado em outra instância/collection |
| `Permissão negada` | PAT sem o escopo *Work Items (Read, write, & manage)*, ou sem acesso ao projeto |
| `Recurso não encontrado` com projeto correto | `ADO_COLLECTION` errada, ou o projeto está em outra collection |
| `Falha na validação do certificado TLS` | Certificado interno. Aponte `NODE_EXTRA_CA_CERTS` para o CA da organização |
| `ADO_SERVER_URL não deve incluir /_apis` | Informe apenas a URL base; o caminho da API é montado pelo servidor |
| Erro de `api-version` não suportada | Ajuste `ADO_API_VERSION` para `7.1` (2022) ou `7.2-preview` (2022.1) |
| O servidor não aparece no VS Code | Use caminho **absoluto** em `args` e confirme que `npm run build` foi executado |
Para diagnóstico detalhado, rode com `LOG_LEVEL=debug` — cada requisição é registrada em stderr, com o PAT redigido.
## 🙏 Créditos
Este projeto é baseado no [Azure DevOps MCP Server](https://github.com/Tiberriver256/mcp-server-azure-devops), de Micah Rairdon ([@Tiberriver256](https://github.com/Tiberriver256)), distribuído sob a licença MIT. Esta versão foi adaptada para uso exclusivo com o Azure DevOps Server 2022 on-premise, com autenticação por PAT.
## 📄 Licença
Distribuído sob a [licença MIT](LICENSE). O arquivo preserva o aviso de copyright do projeto original, como a licença exige.
TDQS
Scored across 4 tools
The four tools have clearly distinct purposes: list for querying sets, get for fetching one item by ID, create for new items, and update for modifying existing items. The descriptions explicitly cross-reference each other, so an agent is unlikely to select the wrong tool.
All tool names follow the verb_noun pattern with the same domain object: list_work_items, get_work_item, create_work_item, update_work_item. The only variation is the plural on list_work_items, which is conventional and predictable.
Four tools is a well-scoped set for focused Azure DevOps work item management. Each tool covers a distinct core operation, and the small count avoids redundancy and confusion.
The set covers the main work item lifecycle: query, read, create, and update, including comments and tag changes. Missing delete and explicit link management are minor gaps that agents can work around, especially since deletion is less common in work item workflows.