standup-mr

Notas de standup a partir do estado de merge requests do GitLab ou GitHub, com as linhas de erro do log de job de um pipeline com falha.

Documentação

standup-mr

standup-mr MCP server Listed on mcpservers.org

Notas de standup baseadas no estado dos merge requests, não nos logs de commit.

A maioria das ferramentas de standup lê seu git log local. Isso responde "o que eu digitei", que não é o que alguém pergunta em um standup. Esta lê GitLab ou GitHub: o que está pronto para merge, o que está bloqueado, o que está esperando por você — e quando um pipeline está vermelho, ela abre o log do job e diz por quê.

O que a torna diferente

ferramentas de log de commitstandup-mr
Fontegit log localAPI do GitLab ou GitHub
Estado do merge request✗pronto / bloqueado / rascunho / obsoleto
Fila de revisão✗apenas pendentes, aprovações filtradas
Pipeline com falha✗linhas de erro do trace do job ou do log do job do Actions
Self-hosted (GitLab CE/EE, GitHub Enterprise)variaprimeira classe

Uso

npx standup-mr fetch                            # JSON, provider auto-detected
npx standup-mr fetch --provider github          # GitHub
npx standup-mr fetch --provider gitlab          # GitLab
npx standup-mr fetch --markdown                 # structured digest
npx standup-mr fetch --lang tr                  # Turkish date labels
npx standup-mr fetch --markdown | npx standup-mr post --google-chat "$URL"

Identidade

GitHubGitLab
Flags--host / --token--host / --token
EnvGITHUB_HOST / GITHUB_TOKENGITLAB_HOST / GITLAB_TOKEN
Sessão CLIgh config de authglab config de auth

O GitHub usa github.com por padrão quando nenhum host é informado. O GitLab não tem padrão — self-hosted é a norma lá, então um host deve vir de uma flag, variável de ambiente, ou da própria config do glab.

O provedor em si é escolhido nesta ordem:

  1. --provider github / --provider gitlab, se passados
  2. um --host reconhecível (github.com, gitlab.com, ou um hostname contendo github/gitlab)
  3. STANDUP_PROVIDER, ou qualquer um dos pares de env GITHUB_* / GITLAB_* que estiver definido
  4. qualquer um de gh / glab que estiver logado

Se nenhum desses resolver — ou ambos resolverem, de forma ambígua — o comando falha com um erro claro em vez de adivinhar.

Então, se você já usa gh ou glab, não há nada para configurar.

Publicar no chat

npx standup-mr fetch --markdown | npx standup-mr post --slack "$SLACK_WEBHOOK_URL"

As três superfícies

CLI — o núcleo. Emite JSON; zero dependências de runtime.

Servidor MCP (mcp/) — uma ferramenta, get_standup_data, para Claude Desktop, Cursor, ou qualquer cliente MCP. Veja mcp/README.md.

Plugin Claude Code — o playbook de escrita de notas, enviado como a skill standup. De dentro do Claude Code:

/plugin marketplace add Jubstaaa/standup-mr
/plugin install standup@standup-mr

Depois digite /standup. As atualizações vêm com /plugin marketplace update standup-mr.

Usando no Cursor, Codex, ou outro assistente

Se você não está usando Claude Code, configure o servidor MCP para dados ao vivo e cole as regras de escrita de notas separadamente.

Cursor — adicione em ~/.cursor/mcp.json (global) ou .cursor/mcp.json (específico do projeto):

{
    "mcpServers": {
        "standup": {
            "command": "npx",
            "args": ["-y", "standup-mr", "mcp"],
            "env": {
                "GITHUB_TOKEN": "ghp_..."
            }
        }
    }
}

Codex — adicione em ~/.codex/config.toml:

[mcp_servers.standup]
command = "npx"
args = ["-y", "standup-mr", "mcp"]

[mcp_servers.standup.env]
GITHUB_TOKEN = "ghp_..."

A chave de configuração exata e o caminho do arquivo dependem da versão para ambos os clientes — se um trecho acima não funcionar, verifique os docs de MCP do Cursor ou a documentação de configuração do Codex para o formato atual, em vez de confiar cegamente neste arquivo.

O servidor expõe três ferramentas:

FerramentaO que faz
get_standup_dataLê o provedor e retorna o relatório como JSON. Opcionais: provider, host, lang.
get_note_instructionsRetorna as regras de escrita de notas, para o assistente escrever a nota como a skill faria.
post_standup_notePublica uma nota finalizada em um webhook do Slack, Discord ou Google Chat.

post_standup_note lê a URL do webhook de STANDUP_WEBHOOK_URL e nunca a recebe como argumento — qualquer pessoa com essa URL pode publicar no canal, então ela pertence aos tokens, não a um transcript. O formato do payload é inferido do host da URL; kind só é necessário quando um proxy a esconde.

Três formatos são implementados: slack e google-chat ambos publicam {"text"}, discord publica {"content"}.

Slack e Google Chat não renderizam Markdown padrão, então a nota é reescrita na saída: **bold** vira *bold* e um cabeçalho ## vira uma linha em negrito. Código inline, blocos cercados e seus conteúdos são deixados intactos. Discord fala Markdown nativamente e é enviado sem alterações. Qualquer outra coisa que aceite um corpo no formato Slack — Mattermost, Rocket.Chat, um endpoint n8n ou Zapier — funciona hoje passando kind: "slack", ou --slack URL na CLI.

Fora do MCP, as mesmas regras estão disponíveis no stdout:

npx standup-mr instructions >> AGENTS.md

--markdown é um resumo, não uma nota escrita

--markdown organiza o material bruto em seções legíveis. Ele não agrupa eventos em temas nem diagnostica bloqueios — esse é o trabalho do modelo, e vive no prompt do cliente MCP ou na skill do Claude Code.

  • Sem IA: um resumo estruturado.
  • Com IA: uma nota que você pode ler em voz alta.

Como é o resumo

Saída anonimizada de uma execução real de segunda-feira — note que sexta e sábado cada um tem sua própria seção, e que um merge request que o GitLab ainda não avaliou não é chamado de pronto:

# Monday, 31 August — dev

_Structured digest — not a written note._

## Previous working day: Friday, 28 August

- `acme/ui` pushed to — fix(keyboard): scale keys to viewport (4 commits)
- `acme/ui` accepted — chore(deps): bump @acme/ui to 0.5.18
- `acme/api` opened — feat: package subscription sales

## Previous working day: Saturday, 29 August

- `acme/ui` pushed to — fix(keyboard): close the autofill bar (1 commit)

## Ready to merge (2)

- `acme/api` !196 fix: normalise the +90 trunk prefix
- `acme/web` !194 refactor: loading state — **no pipeline ran**

## Blocked (1)

- `acme/terminal` !49 fix: relative date chips — **1 unresolved comment(s)**

## Reviews (2 pending)

- `acme/mobile` !501 chore: upgrade to RN 0.87 — Teammate

## Blockers

- `acme/mobile` !6 — job `quality`
    - `npm ERR! code E404`
    - `npm ERR! 404 Not Found - GET https://registry.example.com/@acme%2fui`

A última seção é o ponto da ferramenta. Toda outra ferramenta de standup pode te dizer que o pipeline está vermelho; esta abre o log do job com falha e mostra o 404 — e um 404 em vez de um 403 geralmente significa que o escopo do token está errado, não que o pacote está faltando.

Limitações conhecidas

  • O feed de eventos do GitHub é raso. Ele é limitado a cerca de 300 eventos nos últimos 90 dias, então uma conta muito ativa ou uma lacuna antiga pode silenciosamente perder os eventos mais antigos. O GitLab não tem um limite documentado comparável.
  • A atividade do GitHub só é visível para um token da mesma conta, e eventos de repositórios privados não aparecem para tokens de outras pessoas, mesmo com escopos suficientemente amplos.
  • No GitHub, CI que reporta apenas pela API legada de commit-statuses — ainda como alguns fornecedores integram — aparece como pipelineMissing. O estado do check é lido apenas de check-runs.
  • Um bloqueador cujo diagnóstico não pôde ser buscado ainda é reportado, como job: "unknown" com uma linha de erro diagnosis unavailable: …. O merge request está bloqueado de qualquer forma; apenas a explicação está faltando. Erros de servidor são tentados duas vezes primeiro, e um token rejeitado ainda falha a execução.

Atualizando da 0.1.x

A 0.2.0 muda a saída JSON, a API da biblioteca e as opções do MCP. Se você canaliza standup fetch para qualquer coisa, ou importa o pacote, leia CHANGELOG.md antes de atualizar. A versão curta:

  • previous e previousEvents são substituídos por previousDays[], uma entrada por dia ativo, então um fim de semana não engole mais a sexta-feira. jq .previous agora retorna null sem erro.
  • MergeRequest, Review e Blocker carregam um campo provider obrigatório, e Provider.getReviews recebe um Identity em vez de um id numérico.
  • O CollectOptions.provider do MCP agora é um nome de provedor; injete uma instância de Provider através de providerImpl.

Usuários do plugin Claude Code devem executar /plugin marketplace update standup-mr — a skill standup mudou junto com o formato do relatório.

Requisitos

Node 20 ou mais novo. O núcleo da CLI (fetch, post, instructions) não puxa dependências de runtime. O servidor MCP (comando mcp) traz uma: @modelcontextprotocol/sdk.

Licença

MIT