Skip to content

Git Tools

The git tool provides filesystem-aware Git operations, fully integrated with the MCP server’s security model (allowed paths), hook system, and audit logging.

Requires: Git CLI installed and accessible in PATH. All actions except init must run inside a git repository (the repo root is auto-detected from path).


Actions (9): status, diff, log, show, add, commit, restore, branch, init

Annotations:

AnnotationValue
readOnlyfalse
destructivetrue (restore, branch delete)
idempotentfalse

Parameters:

ParameterRequiredTypeDescription
actionYesstringOne of the 9 actions above
pathNostringWorking directory or file path (default: auto-detect repo root). A file path acts as implicit pathspec for diff/log/status
pathsNoarray of stringsPathspec limiting diff/log/status/add/restore. Native array, equivalent to git <cmd> -- <paths>
outputNostringOutput format. diff/show: stat (default) | name-only | full. status: name-only (default) | full. log: oneline (default) | full
max_linesNonumberMax output lines before truncation with hint footer (default: 200)
limitNonumberlog: max commits (default: 10)
revNostringRevision or range (HEAD~3, abc123..def456, main). For diff/log/show/restore
stagedNobooldiff: compare index vs HEAD (--cached). restore: unstage-only variant
messageYes (commit)stringCommit message
nameNostringbranch: branch name to create/delete
checkoutNoboolbranch: with name, also switch to the new branch (git switch -c)
forceNoboolrestore (working-tree): required. branch delete: escalate -d-D

Removed in v4.5.25: commit_range and source (use rev), max_count (use limit), branch_action/branch_name (use name), all, auto_message, dry_run. paths changed from JSON string to native array.


git({ action: "status" })
git({ action: "status", paths: ["src/"], output: "full" })
  • output:"name-only" (default): git status --porcelain=v1 -b
  • output:"full": porcelain v2 with branch tracking info
  • Compact server mode: one-liner repo (branch) | +staged ~unstaged ?untracked | clean|dirty

git({ action: "diff" }) // stat of unstaged
git({ action: "diff", staged: true }) // stat of staged
git({ action: "diff", rev: "HEAD~3..HEAD" }) // range
git({ action: "diff", paths: ["src/main.go"], output: "full" }) // full patch, scoped

4-layer guardrail (prevents context blow-up on huge diffs):

  1. Default output is stat, never full patch
  2. output:"full" without paths and more than 20 changed files → downgraded to stat with a banner (not an error)
  3. output:"full" with explicit paths is always honored
  4. max_lines (default 200) truncates all output with a footer

git({ action: "log" }) // last 10, oneline+decorate
git({ action: "log", limit: 5, rev: "main" })
git({ action: "log", paths: ["src/"], output: "full" }) // hash|subject|author|relative-date

rev is required.

git({ action: "show", rev: "HEAD" }) // commit metadata + stat
git({ action: "show", rev: "abc1234", output: "full" })
git({ action: "show", rev: "HEAD~1", paths: ["core/"], output: "name-only" })

paths is required — there is no implicit add . / -A fallback (refused by design since v4.5.20).

git({ action: "add", paths: ["src/main.go", "core/engine.go"] })

A -- separator is always inserted before paths, so a file named -A cannot be parsed as an option.

Hooks: HookPreWrite / HookPostWrite.


message is required. Optional paths commits only a subset of staged changes.

git({ action: "commit", message: "fix: resolve null pointer in handler" })
git({ action: "commit", message: "wip", paths: ["src/"] })

Risk assessment (reported in the response, never blocks):

LevelCondition
LOW≤15 files and ≤800 insertions
MEDIUM>15 files or >800 insertions
HIGH>40 files, >3000 insertions, or >500 deletions

Nothing staged → usage error with an add example. Hooks: HookPreWrite / HookPostWrite (hook can deny the commit).


paths is required — no implicit whole-tree restore.

git({ action: "restore", paths: ["src/main.go"], staged: true }) // unstage only (safe)
git({ action: "restore", paths: ["src/main.go"], force: true }) // discard working-tree changes
git({ action: "restore", paths: ["src/main.go"], rev: "HEAD~1", force: true }) // from a prior commit
  • staged:true — unstage-only (equivalent to git reset HEAD <path>), non-destructive, no force needed
  • Working-tree restore or restore-with-rev discards changes → requires force:true
  • rev is passed as --source=<rev>

Hooks: HookPreDelete / HookPostDelete.


Behavior is driven by name and whether the branch exists:

CallResult
no nameList all branches (git branch -a)
name (doesn’t exist)Create branch; with checkout:truegit switch -c
name (exists)Delete with -d; force:true escalates to -D
git({ action: "branch" })
git({ action: "branch", name: "feature/new-ui", checkout: true })
git({ action: "branch", name: "feature/old" }) // -d: git refuses unmerged
git({ action: "branch", name: "feature/old", force: true }) // -D

Plain -d is not gated behind force — git itself refuses to delete unmerged branches.


git({ action: "init", path: "C:/path/to/new-project" })

The only action that works outside a repository. Respects --allowed-paths. Hooks: HookPreCreate / HookPostCreate.


  • No shell interpretation: arguments go straight to the git process via exec.Command — never through cmd.exe/sh — so metacharacters (& | % ^ ") in messages, branch names or paths are inert. The old cmd /c Windows fallback was removed (v4.5.29).
  • Option-injection guard: rev and name values starting with - are rejected before reaching git (rejectOptionLike), closing the --output=<file> injection vector.
  • -- separator before every user pathspec in add/diff/log/status/restore.

Errors include a usage: example with the correct call shape. Common cases:

ErrorResolution
path is not inside a git repositoryRun git(action:"init", path:...) or use a path inside a repo
git add requires explicit 'paths'Pass paths:["file"] — no implicit add .
nothing staged to commitRun git(action:"add", ...) first
destructive git operation 'restore' requires force:trueAdd force:true, or use staged:true for the safe unstage variant
invalid rev "-x": value must not start with '-'Option-injection guard — pass a real revision

For the full parameter schema with examples, call help(tool:"git") from any MCP client.


  • v4.5.20git add requires explicit paths; -- separator before user paths
  • v4.5.21 — Windows stderr propagation fixed
  • v4.5.22restore validation order; --staged no longer requires force
  • v4.5.23restore command construction; branch -d/-D safety inversion corrected
  • v4.5.25 — agent-usable refactor: show action (9 total), rev replaces commit_range/source, paths becomes native array, output enum, 4-layer diff guardrail, usage:-example errors, help(tool:"git")
  • v4.5.29cmd.exe fallback removed (command-injection surface); govulncheck hardening

The audit trail is in CHANGELOG.md.