MCP.Harness
0.1.2
{ "inputs": [ { "type": "promptString", "id": "GITHUB_TOKEN", "description": "PAT do GitHub com escopos 'repo', 'project' e 'read:org'.", "password": true }, { "type": "promptString", "id": "HARNESS_TEMPLATE_OWNER", "description": "Dono do Project-template v2 (default: semog-projects)." }, { "type": "promptString", "id": "HARNESS_TEMPLATE_NUMBER", "description": "Número do Project-template v2 (default: 7)." }, { "type": "promptString", "id": "HARNESS_DEFAULT_REPO", "description": "owner/repo do resource harness://board/current." } ], "servers": { "MCP.Harness": { "type": "stdio", "command": "dnx", "args": ["MCP.Harness@0.1.2", "--yes"], "env": { "GITHUB_TOKEN": "${input:GITHUB_TOKEN}", "HARNESS_TEMPLATE_OWNER": "${input:HARNESS_TEMPLATE_OWNER}", "HARNESS_TEMPLATE_NUMBER": "${input:HARNESS_TEMPLATE_NUMBER}", "HARNESS_DEFAULT_REPO": "${input:HARNESS_DEFAULT_REPO}" } } } }
.vscode/mcp.json settings file.
dotnet tool install --global MCP.Harness --version 0.1.2
dotnet new tool-manifest
dotnet tool install --local MCP.Harness --version 0.1.2
#tool dotnet:?package=MCP.Harness&version=0.1.2
nuke :add-package MCP.Harness --version 0.1.2
MCP.Harness
Servidor MCP (Model Context Protocol) em .NET 10 que expõe o sprint
harness de engenharia como ferramentas para qualquer cliente MCP (Claude
Code, IDEs, agentes). Em vez de depender de scripts soltos (bootstrap.sh) e
de convenções que vivem apenas no CLAUDE.md, o MCP.Harness entrega o ciclo
de vida de tarefas — bootstrap do board, criação de Issues e transição de
Status — como tools versionadas, testáveis e reaproveitáveis entre repos.
Contexto — o que é o sprint harness
O harness organiza todo trabalho não-trivial em torno de um GitHub Project (v2) por repositório, com campos padronizados:
| Campo | Tipo | Valores |
|---|---|---|
Status |
single select | Backlog, Todo, Doing, Done |
Sprint |
iteration | ciclo/iteração atual (14 dias) |
Story Points |
number | estimativa de esforço |
Ciclo de vida de uma task:
- Criação — Issue real + item no Project,
Status = Backlog. - Início —
Status = Todoe, ao começar de fato,Status = Doing. - Execução — commits referenciam a Issue (
refs #N/Closes #N). - Conclusão —
Status = Donee Issue fechada. Trabalho interrompido fica emDoingcom o estado registrado no corpo da Issue.
A Issue é a fonte de verdade — nunca arquivos .md soltos no repo.
O que o servidor expõe
Tools
| Tool | Estado | Descrição |
|---|---|---|
harness_bootstrap |
✅ | Cria o Project v2 a partir do template padronizado e vincula ao repo (porta do bootstrap.sh). |
harness_create_task |
✅ | Cria a Issue, adiciona ao Project, Status = Backlog, Sprint atual e Assignees (default: usuário do token). Dedup por título. |
harness_move_task |
✅ | Move o Status de um item (Backlog / Todo / Doing / Done); valida a opção. |
harness_complete_task |
✅ | Define Status = Done e fecha a Issue com state_reason = completed. Idempotente. |
harness_board |
✅ | Snapshot da sprint (default: corrente), agrupado por Status com soma de Story Points. |
Resources
| Resource | Estado | Conteúdo |
|---|---|---|
harness://board/{owner}/{repo} |
✅ | Snapshot JSON da sprint corrente do board do repo. |
harness://board/current |
✅ | Idem, para o repo padrão (Harness:DefaultRepo). |
harness://config |
✅ | Configuração efetiva + fonte do token (sem o valor). |
Stack
- .NET 10 / C#
- SDK oficial
ModelContextProtocolpara C# - Transporte stdio (padrão para Claude Code); HTTP/SSE opcional
- Acesso ao GitHub via GraphQL (Projects v2) + REST (Issues),
autenticando com PAT (
GITHUB_TOKEN) ou com o token doghCLI
Configuração
Duas fontes, nesta ordem de precedência: variáveis de ambiente →
appsettings.json (ao lado do binário) → defaults.
| Env | Chave (appsettings.json) |
Default | Uso |
|---|---|---|---|
GITHUB_TOKEN / GH_TOKEN |
GitHub:Token |
— | PAT com escopos repo, project, read:org |
| — | GitHub:RestBaseUrl |
https://api.github.com/ |
base REST (troque para GitHub Enterprise) |
| — | GitHub:GraphQlUrl |
https://api.github.com/graphql |
endpoint GraphQL |
HARNESS_TEMPLATE_OWNER |
Harness:TemplateOwner |
semog-projects |
dono do Project-template v2 |
HARNESS_TEMPLATE_NUMBER |
Harness:TemplateNumber |
7 |
número do Project-template v2 |
HARNESS_DEFAULT_REPO |
Harness:DefaultRepo |
— | owner/repo do resource harness://board/current |
O token nunca é logado nem exposto. O resource harness://config mostra
a configuração efetiva e a fonte do token (env GITHUB_TOKEN, gh CLI, …),
nunca o valor. Ver docs/configuracao.md.
Tools já implementadas:
harness_bootstrap (assinatura e diferenças
vs scripts/bootstrap.sh),
harness_create_task,
harness_move_task,
harness_complete_task e
harness_board.
Erros de domínio (status inválido, Issue fora do board, token sem escopo…)
voltam como texto ❌ … no resultado da tool, não como falha crua.
Registrar no Claude Code
Consumir sem clonar o repo — pacote NuGet via dnx (precisa do .NET 10 SDK):
// .mcp.json (na raiz do repo que vai usar o harness)
{
"mcpServers": {
"harness": {
"command": "dotnet",
"args": ["dnx", "MCP.Harness", "--yes"],
"env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
}
}
}
Sem .NET na máquina — imagem de container (GHCR):
{
"mcpServers": {
"harness": {
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "GITHUB_TOKEN",
"ghcr.io/semog-projects/mcp-harness:latest"]
}
}
}
Ou baixe o binário do SO na página de Releases.
Publicação: docs/publicacao.md.
Durante o desenvolvimento deste repo — dotnet run:
// .mcp.json (na raiz do repo que vai usar o harness)
{
"mcpServers": {
"harness": {
"command": "dotnet",
"args": ["run", "--project", "/caminho/para/MCP.Harness/src/MCP.Harness/MCP.Harness.csproj"],
"env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
}
}
}
Build local self-contained: dotnet publish src/MCP.Harness/MCP.Harness.csproj -c Release -r <RID> -o <destino> e aponte command para <destino>/mcp-harness.
O appsettings.json publicado ao lado do binário carrega
Harness:TemplateOwner, Harness:DefaultRepo, etc. sem env vars.
Passo a passo num repo novo
- Gere um PAT com escopos
repo,project,read:org→export GITHUB_TOKEN=…. Para oharness_bootstrapvincular o Project ao repo, use um PAT clássico — a mutationlinkProjectV2ToRepositorynão funciona com PAT fine-grained. As demais tools funcionam com fine-grained (Projects RW + Issues RW + Contents R). - Adicione o
.mcp.jsonacima na raiz do repo. - Rode o harness uma vez: tool
harness_bootstrapcomowner/repodo repo novo — cria o Project v2 e vincula. Se aparecer⚠️ NÃO vinculado, siga ogh project linkda mensagem e rode de novo. - A partir daí,
harness_create_task/harness_move_task/harness_complete_task/harness_board.
Troubleshooting
| Sintoma | Causa provável / correção |
|---|---|
❌ … token sem permissão / token inválido ou expirado |
PAT sem escopo project ou read:org, ou expirado. Gere outro. |
❌ … rate limit do GitHub atingido |
Espere o horário do reset informado na mensagem. |
❌ Nenhum Project v2 vinculado a … |
Rode harness_bootstrap primeiro. |
harness_bootstrap: ⚠️ Board criado, mas NÃO vinculado |
linkProjectV2ToRepository exige token clássico com scope project (PAT fine-grained não serve). Rode o gh project link da mensagem, ou linke na UI, e rode harness_bootstrap de novo. |
❌ … template #7 … pode estar desconfigurado |
HARNESS_TEMPLATE_OWNER/NUMBER apontam para um Project sem os campos padrão. |
❌ Issue #N não está no board |
Use harness_create_task (ou adicione a Issue ao Project na UI). |
| Nenhum token encontrado | export GITHUB_TOKEN=…, ou gh auth login, ou preencha GitHub:Token. |
harness://board/current devolve { "error": … } |
Defina HARNESS_DEFAULT_REPO=owner/repo ou use harness://board/{owner}/{repo}. |
Desenvolvimento
dotnet build
dotnet test # unidade
HARNESS_IT=1 GITHUB_TOKEN=$(gh auth token) \
dotnet test --filter Category=Integration # ponta-a-ponta (GitHub real)
dotnet run --project src/MCP.Harness
Estrutura
src/MCP.Harness/ # host do servidor MCP: tools, resources, appsettings.json, .mcp/server.json
src/MCP.Harness.GitHub/ # cliente GitHub (GraphQL Projects v2 + REST Issues) + serviços do harness
tests/MCP.Harness.Tests/ # testes de unidade e integração
docs/ # uma página por tool + configuracao.md + publicacao.md
Dockerfile # imagem stdio (GHCR)
.github/workflows/ # ci.yml (build+test) · release.yml (tag v* → NuGet/GHCR/Release)
scripts/bootstrap.sh # script legado — referência para a tool harness_bootstrap
Camada de acesso ao GitHub
src/MCP.Harness.GitHub isola toda a conversa com o GitHub e é registrada
com services.AddHarnessGitHub(configuration):
IssuesClient(REST) — criar/ler/fechar Issue, comentar.ProjectsV2Client(GraphQL) — resolver o board de um repo, ler campos e opções (Status/Sprint/Story Points), adicionar item, atualizar valor de campo (single-select, iteration, number) e remover item.GitHubClient— fachada com o atalhoPlaceOnBoardAsync(add + status + sprint + pontos).GitHubTokenProvider— resolve o token:GitHub:Token→GITHUB_TOKEN/GH_TOKEN→gh auth token. Erros da API viramGitHubApiExceptioncom mensagem acionável (escopo faltando, rate limit, 404).
Os testes de integração (Category=Integration) batem no GitHub real e só
rodam com HARNESS_IT=1 e GITHUB_TOKEN no ambiente:
HARNESS_IT=1 GITHUB_TOKEN=$(gh auth token) dotnet test --filter Category=Integration
Relação com o bootstrap.sh
scripts/bootstrap.sh copia um Project-template v2 (com os campos
Status / Sprint / Story Points já configurados) para um novo owner e
vincula ao repositório, usando o gh CLI. A tool harness_bootstrap
replica exatamente esse fluxo pela API do GitHub, sem depender do gh
instalado na máquina do cliente:
gh project copy <template> --source-owner … --target-owner …→ mutationcopyProjectV2gh project link <n> --owner … --repo …→ mutationlinkProjectV2ToRepository- valida o campo
Sprint(iteration) e reporta o calendário de ciclos.
Roadmap
Sprint 1 (atual) — fundação: scaffold do projeto, camada de acesso ao GitHub, tool de bootstrap e CRUD de tasks.
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.