FluxGit MCP Server

Servidor MCP do Git com 23 ferramentas somente leitura. Propostas de escrita são executadas apenas após uma pessoa revisar o impacto específico da operação e aprová-las no FluxGit Desktop.

Documentação

fluxgit-mcp-sidecar

mcp-name: io.github.fluxgit-hq/fluxgit-mcp-server

License Glama score MCP

Servidor Model Context Protocol (MCP) com foco em segurança para Git.

Agentes de IA inspecionam. FluxGit mantém o controle.

Um servidor MCP em Rust com 38 contratos para agentes de código de IA: 25 ferramentas somente leitura e 13 ferramentas de operação com aprovação humana (12 propostas mais cancelamento de uma proposta pendente). O sidecar nunca executa uma escrita no Git; ele faz a ponte entre propostas aprovadas e o aplicativo de desktop FluxGit.

An AI agent proposes a merge; FluxGit shows the diff, reason and conflict preflight, then waits for human approval.

Para comparações de orçamento de contexto, veja o benchmark público de tokens de contexto do Git. Ele publica o fixture, saídas brutas, scripts e checksums, incluindo tanto a varredura ampla de CLI quanto um contraexemplo menor ajustado manualmente.


Por que isso existe

Agentes de codificação com IA são cada vez mais solicitados a navegar em repositórios reais: explicar o estado do branch, resumir diffs, encontrar commits perdidos, recomendar próximos passos seguros. Para fazer isso bem, um agente precisa de contexto do Git mais rico que git status e estruturado o suficiente para raciocinar. Para fazer isso com segurança, um agente nunca deve ser capaz de mutar refs silenciosamente, forçar push, descartar trabalho ou aplicar patches sem que um humano aprove a consequência.

Outros servidores MCP para Git enfrentam uma escolha: permanecer estritamente somente leitura (utilidade limitada) ou expor ferramentas de escrita diretamente (perigoso — agentes alucinam, prompts podem ser envenenados, erros são destrutivos). Este sidecar não escolhe nenhum dos dois. A inspeção é validada por esquema e limitada; as operações passam por um handshake de escrita com UI: o agente propõe, o FluxGit mostra a prévia, o usuário aprova no aplicativo, e o FluxGit executa através de seu pipeline de segurança com pontos de restauração e auditoria.


O que está exposto

25 ferramentas somente leitura

FerramentaPropósito
repo.briefConsciência situacional em uma chamada — branch, ahead/behind, operação em andamento, resumo da árvore de trabalho, stashes, drift agregado de submódulos, commits recentes, convenções detectadas e dicas de próximos passos. A primeira chamada recomendada de uma sessão de agente; substitui 6-10 chamadas brutas ao git e é orçada por tokens por design
repo.scopeEscopo de monorepo — alterações da árvore de trabalho de uma subárvore, commits recentes, churn (commits + autores em uma janela) e proprietários do CODEOWNERS em uma única chamada
repo.statusÁrvore de trabalho, branch atual, caminhos sujos
repo.refsBranches, tags, remotes, stashes
repo.branchStackBranch atual vs upstream / base / relacionado
repo.historyHistórico de commits paginado
repo.reflogLinha do tempo de movimentação com dicas de recuperação
repo.conflictPreflightPrever resultado de merge/rebase antes de executar
conflict.readConflito ativo como dados estruturados — operação em andamento, commits produtores ours/theirs, classificação de estágio por arquivo, conteúdos base/ours/theirs (limitados por tamanho, sinalizados como binários) e intervalos de linhas da região de marcadores. Chega de analisar sopa de <<<<<<<
commit.detailsMetadados de um único commit + arquivos alterados
worktree.changesResumo de alterações da árvore de trabalho por caminho
worktree.listTodos os worktrees (principal + vinculados) com branch/detached, SHA do HEAD e flags de bloqueado/removível — a base somente leitura para worktrees paralelos de agentes
submodule.statusLista e estado de submódulos
diff.textPatch de texto padrão (compatível com git diff)
diff.semanticExplicação semântica negociada por capacidade
diff.semanticFallbacksCaminhos que caíram de semântico para texto
fleet.radarFila de atenção multi-repositório
fleet.digestO que mudou na frota desde um momento — movimentos de reflog do HEAD e de branches locais de muitos repositórios, do mais novo ao mais antigo, limitados por maxEvents (padrão 200, máximo 1000). repoPaths, ou repositórios registrados do FluxGit dentro das raízes permitidas quando omitido. identity é exatamente o que o Git registrou (a identidade configurada, não prova de uma pessoa ou agente); rewrote sinaliza movimentos que descartaram o tip anterior (reset, amend, rebase, movimentos forçados). Lê apenas arquivos de reflog; nada é buscado ou escrito
agents.presenceQuais outros agentes de codificação estão trabalhando neste repositório — apenas de fontes locais (processos de agentes em execução e seus filhos, os armazenamentos de sessão dos próprios agentes, arquivos que eles mantêm no repositório, editores com agentes integrados e registros de presença do FluxGit MCP). Por agente: state (trabalhando/aberto/recente), sources, branch, última ferramenta e arquivos relativos ao repositório quando conhecidos. Nomes são o que cada ferramenta ou cliente MCP declara sobre si mesmo. Seu próprio registro MCP é excluído; descobertas que provavelmente são da sua própria sessão são marcadas como likelyCaller. Nunca retorna prompts, mensagens ou conteúdos de arquivos
safety.timelineEventos de segurança sintetizados de pontos de restauração + reflog
safety.eventDetailsAprofundamento em um evento da linha do tempo
flux.latestRestorePointPonto de restauração mais recente do FluxGit
flux.restorePointsLista de pontos de restauração
flux.restorePointDetailsUm ponto de restauração com refs antes/depois
operation.statusStatus assíncrono autoritativo por previewId; faça polling após uma prévia retornar accepted: true e não relate um resultado do Git antes que ele se torne terminal

13 ferramentas de escrita com handshake de UI

Todas as 12 propostas de operation.preview.* são despachadas através do gateway do FluxGit quando configurado. O sidecar faz POST da proposta, realiza uma leitura de status limitada, e normalmente retorna imediatamente com accepted: true, o previewId canônico, status atual e nextAction.tool: "operation.status". O aplicativo FluxGit renderiza um cartão de aprovação "Solicitado por agente de IA" enquanto a revisão humana continua assíncronamente. O código 10003 é reservado para uma ponte ausente, inválida ou inalcançável; não é um timeout de aprovação humana.

Todos os 12 esquemas de prévia aceitam um idempotencyKey limitado opcional. Reutilize-o apenas ao tentar novamente a mesma intenção lógica; o sidecar o limita ao tipo de operação para que a nova tentativa resolva para a proposta existente no gateway. Omita-o para uma nova intenção—mesmo quando os outros argumentos correspondem—e o sidecar envia uma nova chave baseada em UUID. As ferramentas de prévia continuam, portanto, a anunciar idempotentHint: false.

FerramentaPropósitoDespacho no gateway
operation.preview.mergePropor um merge para revisão humanaPOST /v1/mcp/operation/preview/merge → cartão de aprovação no FluxGit
operation.preview.rebasePropor um rebase não interativointeractive: true falha na validação de esquema antes do POST/criação do cartão; solicitações aceitas fazem POST /v1/mcp/operation/preview/rebase e abrem um cartão de aviso de reescrita de histórico
operation.preview.discardPropor descarte de alterações da árvore de trabalhoPOST /v1/mcp/operation/preview/discard → aviso específico do caminho; o FluxGit exige um stash de segurança antes de descartar alterações correspondentes
operation.preview.resetPropor reset soft / mixed / hardPOST /v1/mcp/operation/preview/reset → cartão ciente do modo (modo hard força confirmação forte)
operation.preview.patchPropor aplicação de um patch gerado por agentePOST /v1/mcp/operation/preview/patch → prévia de patch em monoespaço + alternância applyToIndex
operation.preview.planPropor uma sequência de 1 a 10 passos usando os cinco tipos de passos de plano suportados (merge, rebase, discard, reset, patch)POST /v1/mcp/operation/preview/plan → cartão de passos numerados; passos destrutivos exigem uma caixa de seleção explícita. Um passo rebase com interactive: true é rejeitado pela validação de esquema antes do despacho; a execução para na primeira falha. Seu checkpoint pré-plano ancora apenas o commit do branch: a recuperação protegida restaura HEAD/arquivos rastreados, enquanto o índice original, a árvore de trabalho e arquivos não rastreados exigem os snapshots de passos separados/superfícies de recuperação da Safety Timeline
operation.preview.worktreePropor criação de um worktree isolado para uma tarefa paralela (não destrutivo; nunca toca no histórico)POST /v1/mcp/operation/preview/worktree → cartão de aprovação com branch + caminho de destino + motivo; passa pela mesma ação de criação de worktree que um clique manual usa
operation.preview.commitPropor staging + commit com uma mensagem (não destrutivo; amend não suportado)POST /v1/mcp/operation/preview/commit → cartão de aprovação lista os arquivos exatos que serão colocados em staging e commitados; passa pelo pipeline normal de commit (hooks, assinatura, política); a conclusão retorna o novo SHA
operation.preview.pushPropor push de um branch para um remote (set-upstream opcional; force-with-lease mostra um aviso de ALTO risco)POST /v1/mcp/operation/preview/push → cartão de aprovação com remote + branch + aviso de força quando aplicável; executa o fluxo de push protegido
operation.preview.branchPropor criação (e opcionalmente checkout) de um branch a partir de um ponto inicialPOST /v1/mcp/operation/preview/branch → cartão de aprovação com nome + ponto inicial + escolha de checkout
operation.preview.branchDeletePropor exclusão de branches locais mesclados em um ou mais repositórios (targets, até 20 repositórios × 20 branches, 100 no total). O agente nomeia os branches; o FluxGit decide quais são excluíveis. Branches remotos nunca são tocadosPOST /v1/mcp/operation/preview/branchDelete → o cartão inspeciona cada branch nativamente e mantém qualquer branch com commits fora do HEAD ou de seu upstream, com checkout em qualquer lugar, ou cujo tip se moveu; cada tip excluído é registrado no histórico de exclusão de branches da Fleet, onde Restore o recria. A conclusão retorna resultados por branch deleted/failed/skipped
operation.preview.submodulePointerPropor registrar (record, requer message) ou retornar a (return) um ponteiro de submódulo em qualquer profundidade (parentPath + relativePath). Pins opcionais expectedRecordedOid / expectedCheckedOutOid, conforme lidos de submodule.statusPOST /v1/mcp/operation/preview/submodulePointer → record commita apenas o gitlink no pai através do próprio commit do Git (hooks e assinatura se aplicam; nada é enviado por push); return faz checkout do commit registrado em detached, registrando o checkout anterior como um ponto de restauração. O submódulo deve estar inicializado, limpo e diferente de seu ponteiro registrado
operation.cancelCancelar a proposta ainda pendente do próprio agente por previewIdPOST cancel; o cartão desaparece da fila do usuário como uma proposta expirada

Todas as propostas de escrita exigem um reason de texto livre para que o usuário veja a justificativa do agente no modal de aprovação. Todas reutilizam o mesmo ciclo de vida durável do gateway (pending → approved → executing → completed|failed, com ramificações de rejeição/cancelamento/expiração) e a mesma ponte Tauri na UI. Seis shims cobrem pendente, recuperável, aprovar, reivindicar, rejeitar e concluir. Após reinicialização, propostas Aprovadas podem ser retomadas apenas após revalidação de repo/ref e reivindicação; propostas em Execução são mostradas para reconciliação explícita e nunca são reexecutadas cegamente. Quando uma operação aprovada captura um ponto de restauração, o result de conclusão expõe esses metadados de recuperação para que o agente possa relatá-los sem adivinhar.

O limite é deliberadamente fail-closed no momento da aprovação. O FluxGit resolve o repoPath da proposta para seu id canônico de repositório aberto e exige que ele corresponda ao repositório que o humano está revisando; um caminho não resolvido, incompatibilidade, ou troca de repositório bloqueia a execução. Os argumentos da ferramenta são validados antes do despacho e novamente pelo gateway. Uma política de agente declarativa opcional pode negar propostas antes de um cartão abrir. Suas regras correspondem ao agentId que o sidecar encaminha (o clientInfo.name sanitizado e autodeclarado, como claude-code) e podem limitar esse agente a operações, refs e, com pathConstraints, prefixos de caminho de repositório e worktree. Se FLUXGIT_MCP_AGENT_POLICY estiver configurado mas o arquivo estiver ausente, ilegível, malformado ou não suportado, o gateway não inicia. Sem política configurada, a compatibilidade permanece permissiva, mas a aprovação humana por operação ainda é obrigatória.

Outros agentes no mesmo repositório (dicas de colisão)

Cada resultado operation.preview.* pode carregar um objeto otherAgents opcional: os outros agentes agents.presence encontra no repositório da proposta e, quando ambos os lados nomeiam seus arquivos (descarte e commit paths, cabeçalhos de patch, etapas do plano, o diretório de submódulo de submodulePointer), o overlappingPaths. É apenas informativo: é adicionado após a decisão do gateway, nunca bloqueia uma proposta e nunca muda como ela é aprovada. Está ausente quando a detecção de agente está desabilitada.

"otherAgents": {
  "informational": true,
  "agents": [{ "agent": "codex", "state": "working", "sources": ["process", "session"],
               "branch": "codex/fix-login", "lastTool": "apply_patch",
               "files": ["src/login.rs"], "overlappingPaths": ["src/login.rs"],
               "pid": 4242, "lastActivityMs": 1790000000000, "mcpClient": null,
               "sameAgentAsCaller": false }],
  "agentCount": 1, "overlappingAgentCount": 1, "proposalPathsKnown": true,
  "omittedLikelyCaller": 1, "note": "Informational only: ..."
}

A detecção é local e somente leitura: os armazenamentos SQLite de outros agentes são abertos somente leitura e apenas caminhos relativos ao repositório, nomes de ferramentas, branches e horários saem do detector. FLUXGIT_MCP_AGENT_DETECTION_DISABLED (qualquer valor) desativa isso: agents.presence então retorna 10011 e as prévias não trazem nenhuma dica.

Cada sidecar também registra quais repositórios seu cliente usou, para que o desktop e outros sidecars possam ver: <run_dir>/presence/mcp/<pid>.json (0600) com o nome e versão autodeclarados de clientInfo e, por repositório, o caminho canônico, horário e último nome de ferramenta. Apenas chamadas aceitas são registradas (uma proposta que a política do agente ou um FluxGit ausente recusou não é); o arquivo é removido na saída limpa. FLUXGIT_MCP_PRESENCE_DISABLED desativa isso.

Detalhes do protocolo de escrita

Toda chamada operation.preview.* segue o mesmo protocolo de rede. Exemplo para operation.preview.merge:

1. O sidecar faz POST da proposta:

POST /v1/mcp/operation/preview/merge HTTP/1.1
Host: 127.0.0.1:59647
Content-Type: application/json

{
  "previewId": "1f3c5b9a-...-uuid",
  "agentId": "external-mcp-sidecar",
  "operationType": "merge",
  "repoPath": "/Users/dev/projects/checkout",
  "sourceRef": "feature/cart-redesign",
  "targetRef": "main",
  "reason": "Cart redesign work is complete; tests pass on the feature branch.",
  "strategy": "merge",
  "requestedAt": "2026-05-28T11:42:09.512Z"
}

2. O gateway responde 202 Accepted:

{ "previewId": "1f3c5b9a-...-uuid", "status": "pending", "expiresAt": "2026-05-28T11:47:09.512Z" }

3. O sidecar realiza uma leitura de status limitada:

GET /v1/mcp/operation/status/1f3c5b9a-...-uuid HTTP/1.1
Host: 127.0.0.1:59647

Se a proposta ainda estiver ativa, a ferramenta de prévia retorna prontamente:

{
  "tool": "operation.preview.merge",
  "readOnly": false,
  "accepted": true,
  "previewId": "1f3c5b9a-...-uuid",
  "status": "pending",
  "nextAction": {
    "tool": "operation.status",
    "data": { "previewId": "1f3c5b9a-...-uuid" }
  }
}

Isso é um envio de proposta bem-sucedido, não uma operação Git bem-sucedida.

4. O cliente consulta operation.status até o gateway reportar um estado terminal:

{
  "previewId": "1f3c5b9a-...-uuid",
  "operationType": "merge",
  "status": "completed",
  "result": {
    "commitSha": "9a8b7c6d...",
    "restorePointId": "rp_2026_05_28_1142",
    "conflicts": []
  }
}

completed retorna isError: false. Uma proposta pending ou approved ativa também retorna como um resultado aceito bem-sucedido, mas não afirma que o Git mudou. Qualquer estado terminal não concluído (rejected, failed, expired, cancelled) retorna isError: true com o payload estruturado, para que o agente possa reportar o resultado real em vez de inventar um.

O mesmo padrão se aplica a todas as 12 ferramentas operation.preview.*. Apenas os campos do corpo da requisição e o formato do resultado diferem; o envio da proposta, a leitura imediata única, a continuação assíncrona operation.status e a semântica de erro são compartilhados. O resumo do contrato público é mantido em fluxgit.com/features/mcp-agent-git.


Limite: shell livre vs. com FluxGit

O sidecar fala MCP sem o FluxGit instalado. A inspeção Git padrão funciona (status, refs, histórico, reflog, diff.text, etc.). As ferramentas que exigem FluxGit retornam o código de erro JSON-RPC 10001 com um upgradeHint apontando o agente para o fluxo de instalação/configuração.

Classificação por camadas:

  • Shell livre — trabalha apenas com git local: repo.brief, repo.scope, repo.status, repo.refs, repo.branchStack, repo.history, repo.reflog, commit.details, worktree.changes, worktree.list, submodule.status, diff.text, conflict.read, fleet.digest. agents.presence também não precisa de FluxGit: lê o estado local do agente (e registra a presença MCP do FluxGit quando presente).
  • Híbrido — trabalha localmente com fallback documentado, enriquecido pelo FluxGit: fleet.radar, diff.semantic, diff.semanticFallbacks, repo.conflictPreflight.
  • Exige FluxGit — retorna gateway_not_configured sem FluxGit porque sintetizá-los apenas a partir de refs locais enganaria o agente: safety.timeline, safety.eventDetails, flux.latestRestorePoint, flux.restorePoints, flux.restorePointDetails.
  • Handshake de escrita — roteia pela aprovação da UI do FluxGit via servidor de handshake do gateway. As 12 ferramentas operation.preview.* retornam uma proposta ativa aceita prontamente e continuam via operation.status; operation.cancel retira uma proposta pendente de propriedade do mesmo agente. O código 10003 é usado apenas quando a ponte não consegue aceitar ou servir o handshake.

Início rápido

Instale o crate publicado (coloca fluxgit-mcp-sidecar no seu PATH):

cargo install fluxgit-mcp-sidecar --locked

Para instalar o branch de código-fonte atual:

cargo install --git https://github.com/fluxgit-hq/fluxgit-mcp-server fluxgit-mcp-sidecar --locked

Ou compile a partir de um clone:

# Build
cargo build --release

# Run as MCP server (stdin/stdout transport)
./target/release/fluxgit-mcp-sidecar

Conecte qualquer agente compatível com MCP

Cole o bloco genérico abaixo em qualquer configuração de host MCP. Nenhuma instalação específica de cliente é necessária.

{
  "mcpServers": {
    "fluxgit": {
      "type": "stdio",
      "command": "/absolute/path/to/fluxgit-mcp-sidecar",
      "env": {
        "FLUXGIT_MCP_HANDSHAKE_ADDR": "127.0.0.1:59647",
        "FLUXGIT_MCP_AUDIT_LOG": "/optional/path/to/audit.jsonl"
      }
    }
  }
}

FLUXGIT_MCP_HANDSHAKE_ADDR é o endereço canônico da ponte gerado pelo FluxGit Quick Connect. FLUXGIT_GATEWAY_ADDR e FLUXGIT_GATEWAY_URL permanecem como fallbacks de compatibilidade. O sidecar aceita apenas HTTP simples em um host de loopback com uma porta explícita; um host remoto, credenciais, caminho, consulta, fragmento, HTTPS, ou porta ausente é rejeitado. Sem uma ponte local válida, a camada de shell livre ainda funciona.

FLUXGIT_MCP_AUDIT_LOG habilita um log de auditoria JSONL somente anexação de cada tools/call. Os argumentos são hashados; caminhos brutos e identificadores nunca são gravados literalmente.


Contrato de diff semântico

diff.semantic é a ferramenta mais usada por agentes de IA e a mais fácil de usar incorretamente. A regra é estrita:

Um resultado só pode ser chamado de semântico se data.supported for exatamente true.

Quando o mecanismo semântico do FluxGit não está disponível (app FluxGit não está em execução, endereço do gateway não configurado, ou o repositório não registrado no FluxGit), diff.semantic retorna:

{
  "tool": "diff.semantic",
  "readOnly": true,
  "data": {
    "supported": false,
    "fallback": "diff.text",
    "reason": "Semantic diff is not available in local sidecar fallback mode.",
    "textDiffArguments": { "repoPath": "...", "base": "...", "head": "...", "path": "..." }
  }
}

Com o app FluxGit em execução e o repositório registrado no FluxGit, a mesma chamada é atendida pelo mecanismo de diff do FluxGit através da ponte somente leitura do gateway e retorna supported: true com hunks semânticos por arquivo:

{
  "tool": "diff.semantic",
  "readOnly": true,
  "source": "fluxgit-gateway",
  "data": {
    "supported": true,
    "engine": "fluxgit-diff-engine",
    "files": [
      {
        "path": "src/main.rs",
        "fallbackToText": false,
        "hunks": [{
          "header": "fn main",
          "lines": [{
            "type": "modified", "oldLine": 3, "newLine": 3,
            "content": "let x = 2;", "oldContent": "let x = 1;",
            "changedTokens": ["2"], "oldChangedTokens": ["1"]
          }]
        }]
      },
      {
        "path": "logo.bin",
        "fallbackToText": true,
        "hunks": [],
        "reason": "The semantic engine could not parse this file (unsupported language, binary or unreadable source); use a text diff for it.",
        "textDiffArguments": { "repoPath": "...", "base": "...", "head": "...", "path": "logo.bin" }
      }
    ],
    "changedFiles": 2,
    "filesTruncated": false
  }
}

A honestidade é por arquivo, não apenas por chamada: arquivos que o mecanismo não conseguiu analisar chegam com fallbackToText: true, um motivo e textDiffArguments prontos para uso — nunca como hunks semânticos sintetizados. diff.semanticFallbacks segue a mesma divisão e, quando conectado, lista os registros reais de fallback por arquivo do mecanismo.

Agentes conectados devem:

  1. Chamar diff.semantic.
  2. Ler data.supported.
  3. Se true, usar o payload semântico e rotular os resultados como semânticos — exceto entradas com fallbackToText: true, que devem ser apresentadas como fallbacks de texto.
  4. Se false, chamar diff.text com data.textDiffArguments e apresentar os resultados como fallback de diff de texto.
  5. Nunca inferir movimentos de função ou classe apenas a partir de um patch de texto.

Redação permitida: "O FluxGit relatou um fallback de diff de texto para este arquivo". Redação proibida: "Este é um diff semântico" quando supported=false.


Arquivo de presença (qual agente está trabalhando onde)

A menos que FLUXGIT_MCP_PRESENCE_DISABLED esteja definido, cada processo sidecar mantém um arquivo local, <FluxGit run dir>/presence/mcp/<pid>.json, para que o app desktop do FluxGit possa mostrar qual agente de codificação está conectado e em qual repositório está trabalhando. Ele contém apenas o nome e a versão do cliente que o agente declarou em initialize, e por repositório (no máximo 16) o repoPath verificado, o horário da última chamada e o nome da ferramenta. Nenhum outro argumento, nenhum resultado. Diferente do log de auditoria, o caminho do repositório é armazenado como está para que o desktop possa correspondê-lo; o arquivo é privado (0600 em um diretório 0700), reescrito atomicamente, excluído na saída limpa, varrido após 24 horas, e escrevê-lo nunca afeta uma chamada de ferramenta. O nome do cliente é autodeclarado, não uma identidade autenticada.


Log de auditoria

A menos que FLUXGIT_MCP_AUDIT_DISABLED esteja definido, o sidecar tenta anexar cada tools/call ao ledger JSONL compartilhado. O gateway tenta anexos de decisão humana através do mesmo gravador. FLUXGIT_MCP_AUDIT_LOG substitui o caminho; caso contrário, ambos os processos usam <FluxGit run dir>/audit/mcp.jsonl (incluindo FLUXGIT_RUN_DIR):

{
  "id": "bdeca765-488c-4e2a-b86b-25cd734f2988",
  "timestamp": 1712345678901,
  "auditSchemaVersion": 1,
  "auditChainVersion": 1,
  "sequence": 42,
  "segmentId": "7ab6fa7a-c5bf-4d82-86a8-26b4728b5acd",
  "previousHash": "sha256:...",
  "entryHash": "sha256:...",
  "tool": "repo.status",
  "event_type": "tool_call",
  "repo_scope": "repoPath:sha256:...",
  "args_fingerprint": "sha256:...",
  "risk": "read",
  "approval": "none",
  "result": "success",
  "session_id": "my-agent",
  "duration_ms": 12,
  "summary": "...",
  "readOnly": true,
  "sidecarReadOnly": true,
  "signature": "base64url-ed25519",
  "signatureKeyId": "1a2b3c4d5e6f7a8b",
  "signatureVersion": 3
}

Caminhos e identificadores sensíveis são hashados, nunca armazenados literalmente. Um bloqueio estável entre processos protege validação, rotação e a anexação completa mais sincronização. As linhas são limitadas a 256 KiB. O segmento ativo rotaciona em 4 MiB e no máximo quatro segmentos rotacionados são retidos, com um checkpoint assinado quando a assinatura está configurada.

Assinaturas Ed25519 por entrada (enviado em 2026-05-28)

A assinatura de auditoria é opcional. Quando FLUXGIT_MCP_AUDIT_SIGN_KEY aponta para uma chave privada Ed25519 PEM PKCS8, cada entrada anexada é assinada com essa chave. Entradas assinadas adicionam:

  • signature — assinatura Ed25519 base64url (sem preenchimento) sobre o JSON canônico da entrada sem o campo de assinatura.
  • signatureKeyId — prefixo hex de 16 caracteres da chave pública correspondente, para que chaves rotacionadas possam coexistir no mesmo JSONL.
  • signatureVersion: 3 — domínio de assinatura encadeado atual; o id da chave, sequência, hash anterior e hash da entrada são incluídos nos bytes assinados.

Regra de JSON canônico (o verificador deve corresponder exatamente): classificar recursivamente as chaves de cada objeto lexicograficamente por ordem de bytes UTF-8; arrays preservam ordem; remover signature; serializar compactamente. Para versões 2 e 3, manter signatureKeyId e signatureVersion no objeto assinado. Para entradas assinadas legadas sem versão, o verificador também remove signatureKeyId.

Se a variável de ambiente não estiver definida, novas entradas são encadeadas mas não assinadas para compatibilidade retroativa. Se estiver explicitamente definida, uma chave vazia, ausente, insegura, superdimensionada ou inválida falha a inicialização da auditoria de forma fechada; nunca degrada para saída não assinada.

Verificando um log de auditoria

O binário do sidecar também funciona como verificador:

fluxgit-mcp-sidecar verify-audit /path/to/mcp.jsonl --pubkey /path/to/install.pub.pem

A CLI transmite o arquivo ativo e as rotações retidas com memória limitada. Ela valida sequência, hashes, nomes de segmentos, checkpoints e assinaturas, depois relata apenas contadores limitados (entries, chained, legacy, signed, unsigned, segments e o intervalo de sequência retido). Registros legados por entrada permanecem legíveis e verificáveis, mas são relatados como legacy, nunca como parte da cadeia à prova de adulteração. Para um portão de evidência estrito, execute:

fluxgit-mcp-sidecar verify-audit /path/to/mcp.jsonl --pubkey /path/to/install.pub.pem --require-signed

O código de saída é 0 em sucesso, 3 para dados malformados, cadeia/rotação quebrada, uma assinatura ruim e, em modo estrito, qualquer entrada não assinada; erros de uso retornam 2.

A verificação programática do ledger completo usa verify_audit_ledger; o mais antigo verify_audit_event_signature permanece disponível para verificações compatíveis por entrada. Uma cadeia local não pode provar exclusão ou substituição de todo o histórico retido (ou seu checkpoint local) sem uma âncora externa independentemente confiável. Entradas retidas assinadas impedem que um atacante sem a chave privada recalcule uma cadeia modificada.

A configuração de auditoria (incluindo uma chave de assinatura explícita) falha de forma fechada na inicialização. Uma falha posterior de anexação no sistema de arquivos/disco cheio é registrada como degradada, mas não desfaz uma resposta de ferramenta ou uma transição de ciclo de vida do gateway já durável; o diário do ciclo de vida do gateway permanece autoritativo para recuperação.


Detalhes do protocolo

O servidor suporta duas eras de protocolo:

  • 2026-07-28 (preferido, sem estado): chame server/discover, depois inclua params._meta.io.modelcontextprotocol/protocolVersion e params._meta.io.modelcontextprotocol/clientCapabilities em cada requisição. Resultados modernos carregam resultType: "complete" e metadados do servidor; resultados de lista adicionam ttlMs e cacheScope. tools/list inclui title, inputSchema, outputSchema e anotações. tools/call inclui tanto content apresentacional quanto o mesmo payload em structuredContent. Apenas as ferramentas de proposta e operation.status anunciam previewId, status, accepted e nextAction em seu outputSchema; objetos de esquema são abertos a menos que digam "additionalProperties": false.
  • 2024-11-05 (compatibilidade legada): hosts mais antigos continuam usando initialize. Campos apenas modernos são omitidos dos resultados legados. A saída Stdio é JSON-RPC 2.0 padrão delimitado por novas linhas: exatamente um valor JSON compacto por linha. O JSON no content[0].text de um resultado também é compacto (sem indentação), com as mesmas chaves e valores que structuredContent. O enquadramento Content-Length pré-padrão permanece aceito como entrada apenas para clientes FluxGit antigos; o servidor nunca o emite. Os quadros são limitados a 8 MiB. Notificações JSON-RPC não recebem resposta, e métodos de solicitação enviados sem um id não são executados.

Existem 38 ferramentas no tools/list moderno: 25 anunciam annotations.readOnlyHint: true; as 12 ferramentas operation.preview.* e operation.cancel anunciam readOnlyHint: false. Essas anotações descrevem efeitos para o host; elas não são autorização.

Códigos de erro:

CódigoSignificado
-32700Erro de análise
-32600Solicitação inválida (JSON-RPC malformado)
-32601Método não encontrado
-32602Parâmetros inválidos ou ferramenta desconhecida
-32603Erro interno
-32022Versão MCP moderna não suportada; data contém supported e requested
10001Gateway não configurado — instale/inicie o FluxGit para usar as ferramentas exigidas pelo FluxGit
10002Uma ponte FluxGit configurada não tinha payload para servir (por exemplo, um fallback local não tinha um repoPath absoluto)
10003A ponte local de handshake de escrita está ausente, inválida ou inacessível; nenhuma proposta aceita deve ser inferida
10004A proposta terminou sem conclusão (rejected, failed, expired ou cancelled)
10005O gateway não conhece o previewId solicitado (id errado/nunca aceito ou poda após retenção terminal). Apenas reiniciar não justifica uma nova proposta: registros Aprovado/Executando se recuperam de forma durável e um resultado Git possivelmente iniciado deve ser reconciliado primeiro.
10006O gateway recusou a proposta antes de abrir um cartão (política, validação ou cota)
10007O gateway retornou um previewId canônico malformado/inseguro; o sidecar se recusa a segui-lo
10010Comando Git local somente leitura falhou
10011A detecção de agente está desabilitada (FLUXGIT_MCP_AGENT_DETECTION_DISABLED); agents.presence não pode responder

Status

Este é um servidor MCP funcional. A superfície somente leitura e todas as 12 rotas operation.preview.* estão implementadas; operation.cancel gerencia apenas uma proposta pendente de propriedade do mesmo id de agente auto-relatado. O handshake de escrita renderiza um cartão de aprovação no FluxGit e completa através do pipeline protegido do aplicativo. Os clientes recebem resultados de ciclo de vida estruturados em vez de um sucesso sintético. clientInfo.name é atribuição saneada para política, cota e auditoria; é auto-relatado e nunca deve ser tratado como identidade autenticada.

Roadmap

  • Vídeo de demonstração ponta a ponta — gravação pública do loop agente-propõe → usuário-aprova → FluxGit-executa, capturado de uma instalação ao vivo.
  • Log de auditoria exportável em CSV/JSON — enviado: assinatura Ed25519 por entrada (2026-05-28). Restante: CSV/JSON exportável e política de retenção para o painel de auditoria do aplicativo FluxGit.
  • Transporte HTTP / SSE — para implantações em nuvem / hosts MCP compartilhados.
  • Registro MCP oficial — io.github.fluxgit-hq/fluxgit-mcp-server está ativo e resolve para o crate fluxgit-mcp-sidecar publicado.

Licença

Apache-2.0. Veja LICENSE.

Relacionados