MCP setup · 2026-07-15

Wire any MCP client to Git, safely.

Most Git MCP servers make you choose between an agent that can only watch and an agent that can run git reset unsupervised. I built one that does neither, and this post is the practical setup: ten minutes from install to your first approval-gated write. The server is open source (Apache-2.0) and the read-only half works against plain local git with nothing else installed. The write half never executes anything; it sends proposals to the FluxGit desktop app, where you approve or reject each one with the full diff in front of you.

Install the server.

One line, straight from the public repo:

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

That puts fluxgit-mcp-sidecar on your PATH. It speaks MCP over stdin/stdout, which is what almost every MCP host expects.

Connect your MCP host.

Any MCP-compatible host, Claude Code included, takes the same generic config block. Paste it into your MCP config:

{
  "mcpServers": {
    "fluxgit": {
      "command": "/absolute/path/to/fluxgit-mcp-sidecar",
      "env": {
        "FLUXGIT_GATEWAY_ADDR": "127.0.0.1:14660",
        "FLUXGIT_MCP_AUDIT_LOG": "/optional/path/to/audit.jsonl"
      }
    }
  }
}

FLUXGIT_GATEWAY_ADDR unlocks the FluxGit-powered tools and the approval loop; without it, the free read-only tier still works. FLUXGIT_MCP_AUDIT_LOG is optional and turns on an append-only JSONL log of every tool call; arguments are hashed, so raw paths and identifiers never appear verbatim in the log. If you install the FluxGit desktop app, its Settings, Agents / MCP panel generates this whole block for you, including the app-connection settings.

What you get for free, with no app.

Restart your host and ask the agent about any local repository. The free tier is 23 read-only tools. The ones you will see used most:

repo.brief is the one to know about. It answers "where am I, what is dirty, what is ahead or behind" in a single call. That matters because an agent normally burns a sweep of raw git commands just orienting itself: on a 44-commit test repo I measured the typical ten-command sweep at 1,886 output tokens, counted with a standard tokenizer, while one repo.brief call returned the same picture in 607. That is 3.1x fewer tokens and one round trip instead of ten. Then there are the classics as structured data: repo.status, repo.refs, repo.history, repo.reflog, commit.details, diff.text.

One contract worth understanding before you trust it: diff.semantic. The tool has two honest modes. Standalone, without the desktop app (the semantic engine lives behind it), it does not fake anything: it returns "supported": false with a fallback pointing at diff.text and the exact arguments to call it with. A well-behaved agent must then present results as a text diff, not a semantic one. If your agent claims "semantic diff" on a fallback response, that is a prompt problem worth fixing on your side. With FluxGit running, the same tool returns the real structural payload: per-file hunks with the changed tokens, an honest per-file fallbackToText with the reason and text-diff arguments for files the engine cannot parse, and explicit truncation flags (25 files, 1,500 lines per file) so a huge diff cannot flood the context. diff.semanticFallbacks reports the same per-file fallback picture on its own.

Everything so far runs against plain git. No license, no account, no app.

Your first write proposal.

Now the interesting part. The server advertises 11 write tools: operation.preview.branch, .commit, .push, .merge, .rebase, .discard, .reset, .patch, .worktree, and .plan, plus operation.cancel. Note the naming: every write is a preview. There is no execute tool anywhere in the catalog, so there is nothing a confused or prompt-injected agent can call to skip the human.

Without the desktop app running, a write proposal returns error code 10003 (write_handshake_pending) with instructions the agent relays to you. That is deliberate: no silent failure, no fake success.

With FluxGit running and connected, here is what happens when you tell your agent something like "commit the config change with a sensible message". The agent calls:

{
  "name": "operation.preview.commit",
  "arguments": {
    "repoPath": "/path/to/repo",
    "message": "config: raise connection pool to 32",
    "paths": ["config/pool.toml"],
    "reason": "You asked me to commit the pool-size change; only pool.toml is touched and tests passed locally."
  }
}

The reason field is required on every proposal, and it is not decoration: it is rendered in the approval card you read. In practice the quality of the reason tells you a lot about whether the model understood the task.

FluxGit opens an approval card showing the exact diff to be committed, the files being staged, the risk level, and the agent's reason. You click Approve or Reject. On approval, FluxGit stages and commits through its normal pipeline (hooks, signing and commit policy included) and the agent receives the new commit SHA. On rejection, the agent is told, with your reason, and nothing touched the repository.

Destructive proposals get more scrutiny, not less. A reset proposal shows the commits at risk and captures a restore point first; hard resets always require strong confirmation. A push with forceWithLease renders as HIGH risk with an explicit force warning. A discard shows exactly what would be lost. And a proposal does not hang forever: it stays open in FluxGit for up to five minutes, and the agent can check a pending one later with the read-only operation.status tool, or withdraw it with operation.cancel.

For multi-step work, operation.preview.plan bundles up to ten operations (merge, rebase, discard, reset, patch) into one reviewable plan with a single approval and stop-on-first-failure execution, so a routine rebase-then-merge costs you one decision instead of two.

Prove what happened afterward.

If you set the audit log env var earlier, every call is already on disk. Two more steps make that log tamper-evident. Point FLUXGIT_MCP_AUDIT_SIGN_KEY at a PEM PKCS8 Ed25519 private key and every entry is signed. Then verification is offline and needs only the public key:

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

The output counts verified, failed, unsigned and malformed entries and exits non-zero if any signed entry fails. Signing is opt-in, and unsigned entries are counted separately rather than hidden, so you can roll it out gradually.

Where the line sits.

To be plain about what is free and what is not: the MCP server and its read-only tier are Apache-2.0 and yours regardless. The approval side is the FluxGit desktop app, currently in paid private beta (free for public repositories, macOS the most polished platform, Windows and Linux by invite). The split is enforced at runtime, not by trust: the write tools physically cannot execute without the app's approval loop.

If you wire this into a setup I have not thought of, or find a place where the contract surprises you, I want to hear it: [email protected]. The repo is github.com/fluxgit-hq/fluxgit-mcp-server and issues are open.