FluxGit MCP Server

Servidor MCP de Git con 23 herramientas de solo lectura. Las propuestas de escritura se ejecutan solo después de que una persona revise el impacto específico de la operación y las apruebe en FluxGit Desktop.

Documentación

fluxgit-mcp-sidecar

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

License Glama score MCP

Servidor de Protocolo de Contexto de Modelo (MCP) con prioridad en la seguridad para Git.

Los agentes de IA inspeccionan. FluxGit mantiene el control.

Un servidor MCP en Rust con 38 contratos para agentes de código de IA: 25 herramientas de solo lectura y 13 herramientas de operación con aprobación humana (12 propuestas más la cancelación de una propuesta pendiente). El sidecar nunca ejecuta una escritura de Git; conecta propuestas aprobadas a la aplicación de escritorio FluxGit.

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

Para comparaciones de presupuesto de contexto, consulte el benchmark público de tokens de contexto de Git. Publica el fixture, las salidas sin procesar, los scripts y las sumas de verificación, incluyendo tanto el barrido amplio de CLI como un contraejemplo más pequeño ajustado manualmente.


Por qué existe esto

Cada vez se pide más a los agentes de codificación de IA que naveguen por repositorios reales: explicar el estado de las ramas, resumir diffs, encontrar commits perdidos, recomendar pasos seguros a seguir. Para hacerlo bien, un agente necesita un contexto de Git más rico que git status y lo suficientemente estructurado para razonar sobre él. Para hacerlo de forma segura, un agente nunca debe poder mutar refs silenciosamente, hacer force-push, descartar trabajo o aplicar parches sin que un humano apruebe la consecuencia.

Otros servidores MCP de Git enfrentan una elección: mantenerse estrictamente de solo lectura (utilidad limitada) o exponer herramientas de escritura directamente (peligroso — los agentes alucinan, las indicaciones pueden ser envenenadas, los errores son destructivos). Este sidecar no elige ninguna de las dos. La inspección está validada por esquema y acotada; las operaciones pasan por un manejo de escritura con confirmación en la interfaz: el agente propone, FluxGit muestra la vista previa, el usuario aprueba en la aplicación, y FluxGit ejecuta a través de su pipeline de seguridad con puntos de restauración y auditoría.


Qué se expone

25 herramientas de solo lectura

HerramientaPropósito
repo.briefConciencia situacional en una sola llamada — rama, adelante/atrás, operación en curso, resumen del árbol de trabajo, stashes, deriva agregada de submódulos, commits recientes, convenciones detectadas y sugerencias de próximos pasos. La primera llamada recomendada en una sesión de agente; reemplaza 6-10 llamadas crudas de git y está presupuestada en tokens por diseño
repo.scopeDelimitación de monorepo — cambios del árbol de trabajo de un subárbol, commits recientes, churn (commits + autores en una ventana) y propietarios de CODEOWNERS en una sola llamada
repo.statusÁrbol de trabajo, rama actual, rutas sucias
repo.refsRamas, etiquetas, remotos, stashes
repo.branchStackRama actual vs upstream / base / relacionada
repo.historyHistorial de commits paginado
repo.reflogLínea de tiempo de movimientos con sugerencias de recuperación
repo.conflictPreflightPredecir el resultado de merge/rebase antes de ejecutarlo
conflict.readConflicto activo como datos estructurados — operación en curso, commits productores nuestro/suyo, clasificación de etapas por archivo, contenidos base/nuestro/suyo (con límite de tamaño, marcado binario) y rangos de líneas de la región de marcadores. No más análisis de sopa <<<<<<<
commit.detailsMetadatos de un solo commit + archivos modificados
worktree.changesResumen de cambios del árbol de trabajo por ruta
worktree.listTodos los worktrees (principal + vinculados) con rama/detached, SHA de HEAD y banderas de bloqueado/podable — la base de solo lectura para worktrees paralelos de agentes
submodule.statusLista y estado de submódulos
diff.textParche de texto estándar (compatible con git diff)
diff.semanticExplicación semántica negociada por capacidades
diff.semanticFallbacksRutas que retrocedieron de semántico a texto
fleet.radarCola de atención multi-repositorio
fleet.digestQué cambió en la flota desde un momento — movimientos de HEAD y reflog de ramas locales de muchos repositorios, más recientes primero, limitados por maxEvents (predeterminado 200, máximo 1000). repoPaths, o los repositorios registrados de FluxGit dentro de las raíces permitidas cuando se omite. identity es exactamente lo que Git registró (la identidad configurada, no prueba de una persona o un agente); rewrote marca movimientos que descartaron el tip anterior (reset, amend, rebase, movimientos forzados). Solo lee archivos de reflog; no se obtiene ni escribe nada
agents.presenceQué otros agentes de codificación están trabajando en este repositorio — solo de fuentes locales (procesos de agentes en ejecución y sus hijos, los almacenes de sesión de los propios agentes, archivos que mantienen en el repositorio, editores con agentes integrados y registros de presencia de FluxGit MCP). Por agente: state (trabajando/abierto/reciente), sources, rama, última herramienta y archivos relativos al repositorio cuando se conocen. Los nombres son lo que cada herramienta o cliente MCP declara sobre sí mismo. Su propio registro MCP está excluido; los hallazgos que probablemente sean de su propia sesión se marcan como likelyCaller. Nunca devuelve indicaciones, mensajes o contenidos de archivos
safety.timelineEventos de seguridad sintetizados a partir de puntos de restauración + reflog
safety.eventDetailsProfundización en un evento de la línea de tiempo
flux.latestRestorePointPunto de restauración más reciente de FluxGit
flux.restorePointsLista de puntos de restauración
flux.restorePointDetailsUn punto de restauración con refs antes/después
operation.statusEstado asíncrono autoritativo por previewId; consulte después de que una vista previa devuelva accepted: true y no informe un resultado de Git antes de que sea terminal

13 herramientas de escritura con confirmación en la interfaz

Las 12 propuestas de operation.preview.* se envían a través de la puerta de enlace de FluxGit cuando está configurada. El sidecar publica la propuesta, realiza una lectura de estado acotada, y normalmente regresa de inmediato con accepted: true, el previewId canónico, el estado actual y nextAction.tool: "operation.status". La aplicación FluxGit muestra una tarjeta de aprobación "Solicitado por agente de IA" mientras la revisión humana continúa de forma asíncrona. El código 10003 está reservado para un puente que está ausente, inválido o inalcanzable; no es un tiempo de espera de aprobación humana.

Los 12 esquemas de vista previa aceptan un idempotencyKey acotado opcional. Reutilícelo solo al reintentar la misma intención lógica; el sidecar lo delimita al tipo de operación para que el reintento se resuelva a la propuesta de puerta de enlace existente. Omítalo para una intención nueva—incluso cuando los otros argumentos coincidan—y el sidecar envía una clave nueva respaldada por UUID. Las herramientas de vista previa por lo tanto continúan anunciando idempotentHint: false.

HerramientaPropósitoEnvío a puerta de enlace
operation.preview.mergeProponer un merge para revisión humanaPOST /v1/mcp/operation/preview/merge → tarjeta de aprobación en FluxGit
operation.preview.rebaseProponer un rebase no interactivointeractive: true falla la validación de esquema antes del POST/creación de tarjeta; las solicitudes aceptadas hacen POST /v1/mcp/operation/preview/rebase y abren una tarjeta de advertencia de reescritura de historial
operation.preview.discardProponer descartar cambios del árbol de trabajoPOST /v1/mcp/operation/preview/discard → advertencia específica de ruta; FluxGit requiere un stash de seguridad antes de descartar cambios coincidentes
operation.preview.resetProponer reset suave / mixto / duroPOST /v1/mcp/operation/preview/reset → tarjeta consciente del modo (el modo duro fuerza confirmación fuerte)
operation.preview.patchProponer aplicar un parche generado por agentePOST /v1/mcp/operation/preview/patch → vista previa de parche en monoespacio + alternancia applyToIndex
operation.preview.planProponer una secuencia de 1-10 pasos usando los cinco tipos de pasos de plan compatibles (merge, rebase, discard, reset, patch)POST /v1/mcp/operation/preview/plan → tarjeta de pasos numerados; los pasos destructivos requieren una casilla de verificación explícita. Un paso rebase con interactive: true es rechazado por validación de esquema antes del envío; la ejecución se detiene en el primer fallo. Su punto de control previo al plan ancla solo el commit de la rama: la recuperación protegida restaura HEAD/archivos rastreados, mientras que el índice original, el árbol de trabajo y los archivos no rastreados requieren las superficies de recuperación separadas de snapshots/Safety Timeline
operation.preview.worktreeProponer crear un worktree aislado para una tarea paralela (no destructivo; nunca toca el historial)POST /v1/mcp/operation/preview/worktree → tarjeta de aprobación con rama + ruta de destino + motivo; se ejecuta a través de la misma acción de creación de worktree que usa un clic manual
operation.preview.commitProponer staging + commit con un mensaje (no destructivo; amend no compatible)POST /v1/mcp/operation/preview/commit → la tarjeta de aprobación lista los archivos exactos que se agregarán al staging y se confirmarán; se ejecuta a través del pipeline de commit normal (hooks, firma, política); la finalización devuelve el nuevo SHA
operation.preview.pushProponer push de una rama a un remoto (set-upstream opcional; force-with-lease muestra una advertencia de ALTO riesgo)POST /v1/mcp/operation/preview/push → tarjeta de aprobación con remoto + rama + advertencia de fuerza cuando corresponda; ejecuta el flujo de push protegido
operation.preview.branchProponer crear (y opcionalmente hacer checkout de) una rama desde un punto de inicioPOST /v1/mcp/operation/preview/branch → tarjeta de aprobación con nombre + punto de inicio + elección de checkout
operation.preview.branchDeleteProponer eliminar ramas locales fusionadas en uno o más repositorios (targets, hasta 20 repositorios × 20 ramas, 100 en total). El agente nombra las ramas; FluxGit decide cuáles son eliminables. Las ramas remotas nunca se tocanPOST /v1/mcp/operation/preview/branchDelete → la tarjeta inspecciona cada rama de forma nativa y conserva cualquier rama con commits que no estén en HEAD o su upstream, con checkout en cualquier lugar, o cuyo tip se haya movido; cada tip eliminado se registra en el historial de eliminación de ramas de Fleet, donde Restore lo recrea. La finalización devuelve resultados por rama deleted/failed/skipped
operation.preview.submodulePointerProponer registrar (record, requiere message) o volver a (return) un puntero de submódulo a cualquier profundidad (parentPath + relativePath). Pines opcionales expectedRecordedOid / expectedCheckedOutOid, según se leen de submodule.statusPOST /v1/mcp/operation/preview/submodulePointer → record confirma solo el gitlink en el padre a través del propio commit de Git (los hooks y la firma se aplican; no se empuja nada); return hace checkout del commit registrado en modo detached, registrando el checkout anterior como punto de restauración. El submódulo debe estar inicializado, limpio y diferir de su puntero registrado
operation.cancelCancelar la propuesta aún pendiente del propio agente por previewIdPOST cancel; la tarjeta desaparece de la cola del usuario como una propuesta caducada

Todas las propuestas de escritura requieren un reason de texto libre para que el usuario vea la justificación del agente en el modal de aprobación. Todas reutilizan el mismo ciclo de vida de puerta de enlace duradero (pending → approved → executing → completed|failed, con ramas de rechazo/cancelación/caducidad) y el mismo puente Tauri en la interfaz. Seis shims cubren pendiente, recuperable, aprobar, reclamar, rechazar y completar. Después de un reinicio, las propuestas Aprobadas pueden reanudarse solo después de la revalidación de repo/ref y la reclamación; las propuestas en Ejecución se muestran para reconciliación explícita y nunca se re-ejecutan a ciegas. Cuando una operación aprobada captura un punto de restauración, el result de finalización expone esos metadatos de recuperación para que el agente pueda informarlos sin adivinar.

El límite está deliberadamente cerrado por fallo en el momento de la aprobación. FluxGit resuelve el repoPath de la propuesta a su id canónico de repositorio abierto y requiere que coincida con el repositorio que el humano está revisando; una ruta no resuelta, discrepancia o cambio de repositorio bloquea la ejecución. Los argumentos de la herramienta se validan antes del envío y nuevamente por la puerta de enlace. Una política de agente declarativa opcional puede denegar propuestas antes de que se abra una tarjeta. Sus reglas coinciden con el agentId que el sidecar reenvía (el clientInfo.name saneado y autodeclarado, como claude-code) y puede limitar a ese agente a operaciones, refs y, con pathConstraints, prefijos de ruta de repositorio y worktree. Si FLUXGIT_MCP_AGENT_POLICY está configurado pero el archivo falta, es ilegible, está malformado o no es compatible, la puerta de enlace no se inicia. Sin política configurada, la compatibilidad sigue siendo permisiva, pero la aprobación humana por operación sigue siendo obligatoria.

Otros agentes en el mismo repositorio (sugerencias de colisión)

Every operation.preview.* result may carry an optional otherAgents object: the other agents agents.presence finds in the proposal's repository and, when both sides name their files (discard and commit paths, patch headers, plan steps, the submodule directory of submodulePointer), the overlappingPaths. It is informational only: it is added after the gateway decided, never blocks a proposal and never changes how it is approved. It is absent when agent detection is disabled.

"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: ..."
}

La detección es local y de solo lectura: los almacenes SQLite de otros agentes se abren en modo de solo lectura y solo las rutas relativas al repositorio, nombres de herramientas, ramas y tiempos salen del detector. FLUXGIT_MCP_AGENT_DETECTION_DISABLED (cualquier valor) lo desactiva: agents.presence entonces devuelve 10011 y las vistas previas no llevan ninguna pista.

Cada sidecar también registra qué repositorios usó su cliente, para que el escritorio y otros sidecars puedan verlo: <run_dir>/presence/mcp/<pid>.json (0600) con el nombre y la versión autodeclarados de clientInfo y, por repositorio, la ruta canónica, la hora y el último nombre de herramienta. Solo se registran las llamadas que fueron aceptadas (una propuesta que la política del agente o un FluxGit ausente rechazó no se registra); el archivo se elimina al salir limpiamente. FLUXGIT_MCP_PRESENCE_DISABLED lo desactiva.

Detalles del protocolo de escritura

Cada llamada a operation.preview.* sigue el mismo protocolo de cable. Ejemplo para operation.preview.merge:

1. El sidecar envía la propuesta por POST:

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. La puerta de enlace responde 202 Aceptado:

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

3. El sidecar realiza una lectura de estado acotada:

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

Si la propuesta sigue activa, la herramienta de vista previa responde rápidamente:

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

Esto es un envío de propuesta exitoso, no una operación Git exitosa.

4. El cliente consulta operation.status hasta que la puerta de enlace informa un estado terminal:

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

completed devuelve isError: false. Una propuesta activa de pending o approved también se devuelve como un resultado aceptado exitoso, pero no afirma que Git haya cambiado. Cualquier estado terminal no completado (rejected, failed, expired, cancelled) devuelve isError: true con la carga estructurada, para que el agente pueda informar el resultado real en lugar de inventar uno.

El mismo patrón se aplica a las 12 herramientas de operation.preview.*. Solo los campos del cuerpo de la solicitud y la forma del resultado difieren; el envío de propuestas, la única lectura inmediata, la continuación asíncrona de operation.status y la semántica de errores son compartidos. El resumen del contrato público se mantiene en fluxgit.com/features/mcp-agent-git.


Límite: shell libre vs. impulsado por FluxGit

El sidecar habla MCP sin FluxGit instalado. La inspección estándar de Git funciona (estado, refs, historial, reflog, diff.text, etc.). Las herramientas que requieren FluxGit devuelven el código de error JSON-RPC 10001 con un upgradeHint que apunta al agente al flujo de instalación/configuración.

Clasificación por niveles:

  • Shell libre — trabaje solo con 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 tampoco necesita FluxGit: lee el estado local del agente (y los registros de presencia MCP de FluxGit cuando están presentes).
  • Híbrido — trabaje localmente con respaldo documentado, enriquecido por FluxGit: fleet.radar, diff.semantic, diff.semanticFallbacks, repo.conflictPreflight.
  • Requiere FluxGit — devuelve gateway_not_configured sin FluxGit porque sintetizarlos solo a partir de refs locales engañaría al agente: safety.timeline, safety.eventDetails, flux.latestRestorePoint, flux.restorePoints, flux.restorePointDetails.
  • Protocolo de escritura — se enruta a través de la aprobación de la interfaz de FluxGit mediante el servidor de protocolo de la puerta de enlace. Las 12 herramientas de operation.preview.* devuelven una propuesta activa aceptada rápidamente y continúan a través de operation.status; operation.cancel retira una propuesta pendiente propiedad del mismo agente. El código 10003 se usa solo cuando el puente no puede aceptar o servir el protocolo.

Inicio rápido

Instale el crate publicado (coloca fluxgit-mcp-sidecar en su PATH):

cargo install fluxgit-mcp-sidecar --locked

Para instalar la rama fuente actual en su lugar:

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

O compile desde un clon:

# Build
cargo build --release

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

Conecte cualquier agente compatible con MCP

Pegue el bloque genérico a continuación en cualquier configuración de host MCP. No se requiere instalación específica del cliente.

{
  "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 es la dirección de puente canónica generada por FluxGit Quick Connect. FLUXGIT_GATEWAY_ADDR y FLUXGIT_GATEWAY_URL siguen siendo resguardos de compatibilidad. El sidecar acepta solo HTTP simple en un host de bucle local con un puerto explícito; un host remoto, credenciales, ruta, consulta, fragmento, HTTPS, o un puerto faltante se rechaza. Sin un puente local válido, el nivel de shell libre sigue funcionando.

FLUXGIT_MCP_AUDIT_LOG habilita un registro de auditoría JSONL de solo agregar de cada tools/call. Los argumentos se codifican con hash; las rutas e identificadores sin procesar nunca se escriben textualmente.


Contrato de diff semántico

diff.semantic es la herramienta más utilizada para agentes de IA y la más fácil de usar incorrectamente. La regla es estricta:

Un resultado solo puede llamarse semántico si data.supported es exactamente true.

Cuando el motor semántico de FluxGit no está disponible (la aplicación FluxGit no se está ejecutando, la dirección de la puerta de enlace no está configurada o el repositorio no está registrado en FluxGit), diff.semantic devuelve:

{
  "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": "..." }
  }
}

Con la aplicación FluxGit ejecutándose y el repositorio registrado en FluxGit, la misma llamada es atendida por el motor de diff de FluxGit a través del puente de solo lectura de la puerta de enlace y devuelve supported: true con fragmentos semánticos por archivo:

{
  "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
  }
}

La honestidad es por archivo, no solo por llamada: los archivos que el motor no pudo analizar llegan con fallbackToText: true, una razón y textDiffArguments listo para usar — nunca como fragmentos semánticos sintetizados. diff.semanticFallbacks sigue la misma división y, cuando está conectado, enumera los registros de respaldo reales por archivo del motor.

Los agentes conectados deben:

  1. Llamar a diff.semantic.
  2. Leer data.supported.
  3. Si true, usar la carga semántica y etiquetar los resultados como semánticos — excepto las entradas con fallbackToText: true, que deben presentarse como respaldos de texto.
  4. Si false, llamar a diff.text con data.textDiffArguments y presentar los resultados como un respaldo de diff de texto.
  5. Nunca inferir movimientos a nivel de función o clase solo a partir de un parche de texto.

Redacción permitida: "FluxGit informó un respaldo de diff de texto para este archivo". Redacción prohibida: "Este es un diff semántico" cuando supported=false.


Archivo de presencia (qué agente trabaja dónde)

A menos que FLUXGIT_MCP_PRESENCE_DISABLED esté configurado, cada proceso de sidecar mantiene un archivo local, <FluxGit run dir>/presence/mcp/<pid>.json, para que la aplicación de escritorio de FluxGit pueda mostrar qué agente de codificación está conectado y en qué repositorio está trabajando. Contiene solo el nombre y la versión del cliente que el agente declaró en initialize, y por repositorio (como máximo 16) el repoPath verificado, la hora de la última llamada y el nombre de la herramienta. Sin otros argumentos, sin resultados. A diferencia del registro de auditoría, la ruta del repositorio se almacena tal cual para que el escritorio pueda coincidir; el archivo es privado (0600 en un directorio 0700), se reescribe atómicamente, se elimina al salir limpiamente, se barre después de 24 horas, y escribirlo nunca afecta una llamada de herramienta. El nombre del cliente es autodeclarado, no una identidad autenticada.


Registro de auditoría

A menos que FLUXGIT_MCP_AUDIT_DISABLED esté configurado, el sidecar intenta agregar cada tools/call al libro mayor JSONL compartido. La puerta de enlace intenta agregar decisiones humanas a través del mismo escritor. FLUXGIT_MCP_AUDIT_LOG anula la ruta; de lo contrario, ambos procesos usan <FluxGit run dir>/audit/mcp.jsonl (incluyendo 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
}

Las rutas e identificadores sensibles se codifican con hash, nunca se almacenan textualmente. Un bloqueo estable entre procesos protege la validación, la rotación y la adición completa más la sincronización. Las líneas están limitadas a 256 KiB. El segmento activo rota a 4 MiB y se retienen como máximo cuatro segmentos rotados, con un punto de control firmado cuando la firma está configurada.

Firmas Ed25519 por entrada (enviado el 2026-05-28)

La firma de auditoría es opcional. Cuando FLUXGIT_MCP_AUDIT_SIGN_KEY apunta a una clave privada Ed25519 PEM PKCS8, cada entrada agregada se firma con esa clave. Las entradas firmadas agregan:

  • signature — firma Ed25519 en base64url (sin relleno) sobre el JSON canónico de la entrada sin el campo de firma.
  • signatureKeyId — prefijo hex de 16 caracteres de la clave pública correspondiente, para que las claves rotadas puedan coexistir en el mismo JSONL.
  • signatureVersion: 3 — dominio de firma encadenado actual; el id de clave, la secuencia, el hash anterior y el hash de entrada se incluyen en los bytes firmados.

Regla de JSON canónico (el verificador debe coincidir exactamente): ordenar recursivamente las claves de cada objeto lexicográficamente por orden de bytes UTF-8; las matrices preservan el orden; eliminar signature; serializar de forma compacta. Para las versiones 2 y 3, mantener signatureKeyId y signatureVersion en el objeto firmado. Para entradas firmadas heredadas sin versión, el verificador también elimina signatureKeyId.

Si la variable de entorno no está configurada, las nuevas entradas se encadenan pero no se firman por compatibilidad hacia atrás. Si está configurada explícitamente, una clave vacía, faltante, insegura, demasiado grande o inválida hace que el inicio de la auditoría falle de forma cerrada; nunca degrada a salida sin firmar.

Verificación de un registro de auditoría

El binario del sidecar también funciona como verificador:

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

La CLI transmite el archivo activo y las rotaciones retenidas con memoria acotada. Valida secuencia, hashes, nombres de segmentos, puntos de control y firmas, luego informa solo contadores acotados (entries, chained, legacy, signed, unsigned, segments y el rango de secuencia retenido). Los registros heredados por entrada siguen siendo legibles y verificables, pero se informan como legacy, nunca como parte de la cadena a prueba de manipulación. Para una puerta de evidencia estricta, ejecute:

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

El código de salida es 0 en éxito, 3 para datos malformados, cadena/rotación rota, una firma incorrecta y, en modo estricto, cualquier entrada sin firmar; los errores de uso devuelven 2.

La verificación programática del libro mayor completo usa verify_audit_ledger; el más antiguo verify_audit_event_signature sigue disponible para verificaciones compatibles por entrada. Una cadena local no puede probar la eliminación o el reemplazo de todo el historial retenido (o su punto de control local) sin un ancla externa independientemente confiable. Las entradas retenidas firmadas sí impiden que un atacante sin la clave privada recalcule una cadena modificada.

La configuración de auditoría (incluida una clave de firma explícita) falla de forma cerrada al inicio. Una falla posterior de agregado en el sistema de archivos/disco completo se registra como degradada pero no deshace una respuesta de herramienta ni una transición de ciclo de vida de la puerta de enlace ya duradera; el diario del ciclo de vida de la puerta de enlace sigue siendo autoritativo para la recuperación.


Detalles del protocolo

El servidor admite dos eras de protocolo:

  • 2026-07-28 (preferido, sin estado): llame a server/discover, luego incluya params._meta.io.modelcontextprotocol/protocolVersion y params._meta.io.modelcontextprotocol/clientCapabilities en cada solicitud. Los resultados modernos llevan resultType: "complete" y metadatos del servidor; los resultados de lista agregan ttlMs y cacheScope. tools/list incluye title, inputSchema, outputSchema y anotaciones. tools/call incluye tanto content presentacional como la misma carga en structuredContent. Solo las herramientas de propuesta y operation.status anuncian previewId, status, accepted y nextAction en su outputSchema; los objetos de esquema están abiertos a menos que digan "additionalProperties": false.
  • 2024-11-05 (compatibilidad heredada): los hosts más antiguos continúan usando initialize. Los campos solo modernos se omiten de los resultados heredados. La salida estándar es JSON-RPC 2.0 delimitado por nuevas líneas: exactamente un valor JSON compacto por línea. El JSON en el content[0].text de un resultado también es compacto (sin indentación), con las mismas claves y valores que structuredContent. El enmarcado Content-Length pre-estándar sigue siendo aceptado como entrada únicamente para clientes FluxGit antiguos; el servidor nunca lo emite. Los marcos están limitados a 8 MiB. Las notificaciones JSON-RPC no reciben respuesta, y los métodos de solicitud enviados sin un id no se ejecutan.

Hay 38 herramientas en el tools/list moderno: 25 anuncian annotations.readOnlyHint: true; las 12 herramientas operation.preview.* y operation.cancel anuncian readOnlyHint: false. Estas anotaciones describen efectos para el host; no son autorización.

Códigos de error:

CódigoSignificado
-32700Error de análisis
-32600Solicitud no válida (JSON-RPC malformado)
-32601Método no encontrado
-32602Parámetros no válidos o herramienta desconocida
-32603Error interno
-32022Versión MCP moderna no compatible; data contiene supported y requested
10001Gateway no configurado — instale/inicie FluxGit para usar las herramientas requeridas por FluxGit
10002Un puente FluxGit configurado no tenía carga útil que servir (por ejemplo, una alternativa local carecía de un repoPath absoluto)
10003El puente local de handshake de escritura está ausente, no es válido o es inalcanzable; no se debe inferir ninguna propuesta aceptada
10004La propuesta terminó sin completarse (rejected, failed, expired o cancelled)
10005El gateway no conoce el previewId solicitado (id incorrecto/nunca aceptado o poda después de la retención terminal). Reiniciar solo no justifica una nueva propuesta: los registros Aprobado/En ejecución se recuperan de forma duradera y un resultado de Git posiblemente iniciado debe reconciliarse primero.
10006El gateway rechazó la propuesta antes de abrir una tarjeta (política, validación o cuota)
10007El gateway devolvió un previewId canónico malformado/inseguro; el sidecar se niega a seguirlo
10010El comando Git local de solo lectura falló
10011La detección de agentes está deshabilitada (FLUXGIT_MCP_AGENT_DETECTION_DISABLED); agents.presence no puede responder

Estado

Este es un servidor MCP funcional. La superficie de solo lectura y las 12 rutas operation.preview.* están implementadas; operation.cancel gestiona únicamente una propuesta pendiente propiedad del mismo id de agente autoinformado. El handshake de escritura renderiza una tarjeta de aprobación en FluxGit y se completa a través del pipeline protegido de la aplicación. Los clientes reciben resultados de ciclo de vida estructurados en lugar de un éxito sintético. clientInfo.name es atribución saneada para política, cuota y auditoría; es autoinformado y nunca debe tratarse como identidad autenticada.

Hoja de ruta

  • Video de demostración de extremo a extremo — grabación pública del ciclo agente-propone → usuario-aprueba → FluxGit-ejecuta, capturada desde una instalación en vivo.
  • Registro de auditoría exportable CSV/JSON — enviado: firma Ed25519 por entrada (2026-05-28). Pendiente: CSV/JSON exportable y política de retención para el panel de auditoría de la aplicación FluxGit.
  • Transporte HTTP / SSE — para implementaciones en la nube / hosts MCP compartidos.
  • Registro MCP oficial — io.github.fluxgit-hq/fluxgit-mcp-server está activo y resuelve al crate fluxgit-mcp-sidecar publicado.

Licencia

Apache-2.0. Ver LICENSE.

Relacionado