Git Tools
Git Version Control
Section titled “Git Version Control”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:
| Annotation | Value |
|---|---|
| readOnly | false |
| destructive | true (restore, branch delete) |
| idempotent | false |
Parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
action | Yes | string | One of the 9 actions above |
path | No | string | Working directory or file path (default: auto-detect repo root). A file path acts as implicit pathspec for diff/log/status |
paths | No | array of strings | Pathspec limiting diff/log/status/add/restore. Native array, equivalent to git <cmd> -- <paths> |
output | No | string | Output format. diff/show: stat (default) | name-only | full. status: name-only (default) | full. log: oneline (default) | full |
max_lines | No | number | Max output lines before truncation with hint footer (default: 200) |
limit | No | number | log: max commits (default: 10) |
rev | No | string | Revision or range (HEAD~3, abc123..def456, main). For diff/log/show/restore |
staged | No | bool | diff: compare index vs HEAD (--cached). restore: unstage-only variant |
message | Yes (commit) | string | Commit message |
name | No | string | branch: branch name to create/delete |
checkout | No | bool | branch: with name, also switch to the new branch (git switch -c) |
force | No | bool | restore (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.
Actions
Section titled “Actions”status — Repository Status
Section titled “status — Repository Status”git({ action: "status" })git({ action: "status", paths: ["src/"], output: "full" })output:"name-only"(default):git status --porcelain=v1 -boutput:"full": porcelain v2 with branch tracking info- Compact server mode: one-liner
repo (branch) | +staged ~unstaged ?untracked | clean|dirty
diff — Show Changes
Section titled “diff — Show Changes”git({ action: "diff" }) // stat of unstagedgit({ action: "diff", staged: true }) // stat of stagedgit({ action: "diff", rev: "HEAD~3..HEAD" }) // rangegit({ action: "diff", paths: ["src/main.go"], output: "full" }) // full patch, scoped4-layer guardrail (prevents context blow-up on huge diffs):
- Default
outputisstat, never full patch output:"full"withoutpathsand more than 20 changed files → downgraded tostatwith a banner (not an error)output:"full"with explicitpathsis always honoredmax_lines(default 200) truncates all output with a footer
log — Commit History
Section titled “log — Commit History”git({ action: "log" }) // last 10, oneline+decorategit({ action: "log", limit: 5, rev: "main" })git({ action: "log", paths: ["src/"], output: "full" }) // hash|subject|author|relative-dateshow — Show a Commit
Section titled “show — Show a Commit”rev is required.
git({ action: "show", rev: "HEAD" }) // commit metadata + statgit({ action: "show", rev: "abc1234", output: "full" })git({ action: "show", rev: "HEAD~1", paths: ["core/"], output: "name-only" })add — Stage Files
Section titled “add — Stage Files”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.
commit — Commit Staged Changes
Section titled “commit — Commit Staged Changes”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):
| Level | Condition |
|---|---|
| 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).
restore — Restore Files
Section titled “restore — Restore Files”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 changesgit({ action: "restore", paths: ["src/main.go"], rev: "HEAD~1", force: true }) // from a prior commitstaged:true— unstage-only (equivalent togit reset HEAD <path>), non-destructive, noforceneeded- Working-tree restore or restore-with-
revdiscards changes → requiresforce:true revis passed as--source=<rev>
Hooks: HookPreDelete / HookPostDelete.
branch — List, Create, Delete
Section titled “branch — List, Create, Delete”Behavior is driven by name and whether the branch exists:
| Call | Result |
|---|---|
no name | List all branches (git branch -a) |
name (doesn’t exist) | Create branch; with checkout:true → git 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 unmergedgit({ action: "branch", name: "feature/old", force: true }) // -DPlain -d is not gated behind force — git itself refuses to delete unmerged branches.
init — Initialize Repository
Section titled “init — Initialize Repository”git({ action: "init", path: "C:/path/to/new-project" })The only action that works outside a repository. Respects --allowed-paths. Hooks: HookPreCreate / HookPostCreate.
Security
Section titled “Security”- No shell interpretation: arguments go straight to the git process via
exec.Command— never throughcmd.exe/sh— so metacharacters (& | % ^ ") in messages, branch names or paths are inert. The oldcmd /cWindows fallback was removed (v4.5.29). - Option-injection guard:
revandnamevalues starting with-are rejected before reaching git (rejectOptionLike), closing the--output=<file>injection vector. --separator before every user pathspec inadd/diff/log/status/restore.
Error Handling
Section titled “Error Handling”Errors include a usage: example with the correct call shape. Common cases:
| Error | Resolution |
|---|---|
path is not inside a git repository | Run 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 commit | Run git(action:"add", ...) first |
destructive git operation 'restore' requires force:true | Add 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.
Hardening History
Section titled “Hardening History”- v4.5.20 —
git addrequires explicitpaths;--separator before user paths - v4.5.21 — Windows stderr propagation fixed
- v4.5.22 —
restorevalidation order;--stagedno longer requiresforce - v4.5.23 —
restorecommand construction;branch -d/-Dsafety inversion corrected - v4.5.25 — agent-usable refactor:
showaction (9 total),revreplacescommit_range/source,pathsbecomes native array,outputenum, 4-layer diff guardrail,usage:-example errors,help(tool:"git") - v4.5.29 —
cmd.exefallback removed (command-injection surface); govulncheck hardening
The audit trail is in CHANGELOG.md.
See Also
Section titled “See Also”- Core Tools — All 20 MCP tools
- Backup Tools — Persistent backup and recovery
- Tool Selection Guide — Which tool for your task