Skip to content

Latest commit

 

History

History
359 lines (289 loc) · 20.6 KB

File metadata and controls

359 lines (289 loc) · 20.6 KB

MCP tools and resources (canonical reference)

Single source of truth for registered tool ids, client naming, JSON output shape, resource URI, and workspace root resolution.
Install and MCP clients (only canonical location): install.md. Preset file, dev, CI, publishing: HUMANS.md. Implementation layout (src/server/ + entry server.ts), contract bumps: AGENTS.md.

Naming

MCP clients expose tools as {serverName}_{toolName}. With the server registered as rethunk-git, examples use the prefix rethunk-git_.

Tools

Short id Client id (server rethunk-git) Purpose
git_status rethunk-git_git_status git status --short -b per MCP root and optional submodules (includeSubmodules); parallel submodule status. Args include allWorkspaceRoots, rootIndex, workspaceRoot, format.
git_inventory rethunk-git_git_inventory Status + ahead/behind per path; default upstream each repo’s @{u}; pass both remote and branch for fixed tracking. nestedRoots, preset, presetMerge, maxRoots, format, plus workspace pick args.
git_parity rethunk-git_git_parity Compare git rev-parse HEAD for path pairs. pairs, preset, presetMerge, format, plus workspace pick args.
list_presets rethunk-git_list_presets List preset names/counts from .rethunk/git-mcp-presets.json; invalid JSON/schema surface as errors. Workspace pick + format only.
git_log rethunk-git_git_log Path-filtered, time-windowed git log across one or more workspace roots. Returns commit history with author, date, subject, and shortstat. Args: since, paths, grep, author, maxCommits, branch, plus workspace pick args + format.
git_diff_summary rethunk-git_git_diff_summary Structured, token-efficient diff viewer. Returns per-file diffs with additions/deletions counts, truncated to configurable line limits, with lock files/dist/vendor excluded by default. Args: range, fileFilter, maxLinesPerFile, maxFiles, excludePatterns, plus workspace pick args + format. Read-only.
batch_commit rethunk-git_batch_commit Create multiple sequential git commits in a single call. Each entry stages the listed files then commits with the given message. Stops on first failure. Optional push: "after" pushes the current branch to its upstream once every commit lands. Args: commits (array of {message, files}), push?, plus workspace pick args + format. Mutating — not idempotent.
git_merge rethunk-git_git_merge Merge one or more source branches into a destination. Default strategy auto cascades fast-forward → rebase → merge-commit per source, preferring linear history. Refuses on dirty tree; stops on first conflict with structured path report. Optional deleteMergedBranches / deleteMergedWorktrees cascade cleanup, always skipping protected names (main/master/dev/develop/stable/trunk/prod/production/release*/hotfix*). Args: sources, into?, strategy?, message?, cleanup flags + workspace pick + format. Mutating.
git_cherry_pick rethunk-git_git_cherry_pick Play commits from one or more sources onto a destination. Sources may be SHAs, A..B ranges, or branch names (expanded to onto..<branch>, oldest-first). Uses --empty=drop so patch-equivalent re-applies add nothing. Refuses on dirty tree; stops on first conflict, aborting cleanly. Same cleanup flags as git_merge (branch-kind sources only, protected names skipped). Args: sources, onto?, cleanup flags + workspace pick + format. Mutating.

Pass format: "json" on any tool for structured JSON instead of markdown (default).

JSON responses

Tool JSON bodies are minified and contain only the payload — no rethunkGitMcp envelope. Current MCP_JSON_FORMAT_VERSION is "2"; server + format version are discoverable via MCP initialize. Payload keys (groups, inventories, parity, roots) are stable within a given format version. Preset-related responses may include presetSchemaVersion.

v2 field omission (consumer contract)

To keep responses compact, optional fields are omitted when they would be empty, null, or false — they are not emitted as null. Consumers must test for presence, not compare to null.

git_inventoryinventories[*]

  • Always present: workspace_root, entries.
  • Omitted when not applicable: presetSchemaVersion, nestedRootsTruncated, nestedRootsOmittedCount, and the whole upstream object (emitted only when a fixed remote/branch pair was supplied; in auto mode it is absent).

git_inventoryentries[*] (InventoryEntryJson)

  • Always present: label, path, upstreamMode ("auto" or "fixed").
  • Optional (omitted when empty/absent): branchStatus, headAbbrev, upstreamRef, ahead, behind, upstreamNote, detached (only emitted as true), skipReason (only on skipped entries).
  • Removed in v2: shortStatus. The porcelain entries now live inside branchStatus (the full git status --short -b body — branch header line followed by porcelain lines).

Errors (any tool)

  • Error payloads carry an error code string and any structured context (e.g. preset, presetFile). The old free-text message field is removed for self-describing codes (git_not_found, remote_branch_mismatch, invalid_remote_or_branch, no_pairs, preset_not_found missing case). It is retained only where it carries parse output (the invalid_json preset branch).

When to bump MCP_JSON_FORMAT_VERSION or change payload shape: AGENTS.mdChanging contracts.

git_log — parameters

Parameter Type Default Notes
since string "7.days" Passed to git log --since=. Accepts ISO timestamps (2026-04-01T00:00:00Z) or git relative forms (48.hours, 2.weeks.ago).
paths string[] (all) Restrict to commits touching these paths (appended after --).
grep string Filter by commit message regex (git --grep, always case-insensitive).
author string Filter by author name or email (--author=).
maxCommits int 50 Max commits per root. Hard cap: 500.
branch string HEAD Ref/branch to log from.
workspaceRoot string Explicit root; highest priority.
rootIndex int Pick one of several MCP roots (0-based).
allWorkspaceRoots boolean false Fan out across all MCP roots.
format "markdown" | "json" "markdown" Output format.

git_log — JSON shape (format: "json")

{
  "groups": [{
    "workspace_root": "/abs/path",
    "repo": "my-repo",
    "branch": "main",
    "commits": [{
      "sha7": "a1bf184",
      "shaFull": "a1bf184c3d...",
      "subject": "feat(satcom): upgrade to PROTOCOL_VERSION 4",
      "author": "Damon Blais",
      "email": "damon@example.com",
      "date": "2026-04-12T18:32:01-07:00",
      "ageRelative": "42m ago",
      "filesChanged": 4,
      "insertions": 16,
      "deletions": 5
    }],
    "truncated": true,
    "omittedCount": 12
  }]
}

v2 field-omission rules: filesChanged, insertions, deletions are omitted when zero/absent (new file with no shortstat). truncated and omittedCount are omitted when false/0. A group emits error instead of commits when git fails for that root.

git_log — error codes

Code Meaning
git_not_found git binary not on PATH.
not_a_git_repo The resolved workspace root is not inside a git repository.
invalid_since The since string contains shell metacharacters and was rejected.
invalid_paths One of the paths entries contains shell metacharacters and was rejected.
git_log_failed git log exited non-zero (e.g. unknown branch ref).
root_index_out_of_range rootIndex exceeds the number of MCP file roots.

git_diff_summary — parameters

Parameter Type Default Notes
range string unstaged Diff range. "staged" / "cached" for index; "HEAD" for last commit; "A..B" or "A...B" for revision ranges; single ref. Default: unstaged working-tree changes.
fileFilter string Glob pattern to restrict output to matching files (e.g. "*.ts", "src/**").
maxLinesPerFile int 50 Max diff lines to include per file (1–2000).
maxFiles int 30 Max files to include in output (1–500).
excludePatterns string[] lock files, dist, vendor Glob patterns to exclude. Defaults to *.lock, *.lockb, bun.lock, package-lock.json, yarn.lock, pnpm-lock.yaml, *.min.js, *.min.css, vendor/**, node_modules/**, dist/**. Pass an empty array to disable.
workspaceRoot string Explicit root; highest priority.
rootIndex int Pick one of several MCP roots (0-based).
format "markdown" | "json" "markdown" Output format.

git_diff_summary — JSON shape (format: "json")

{
  "range": "unstaged changes",
  "totalFiles": 2,
  "totalAdditions": 10,
  "totalDeletions": 5,
  "files": [{
    "path": "src/foo.ts",
    "status": "modified",
    "additions": 8,
    "deletions": 3,
    "truncated": false,
    "diff": "@@ -1,3 +1,8 @@\n-const x = 1;\n+const x = 2;"
  }],
  "truncatedFiles": 1,
  "excludedFiles": ["yarn.lock"]
}

status is one of "modified", "added", "deleted", "renamed". oldPath is present only for renamed files. truncatedFiles and excludedFiles are omitted when zero/empty (v2 field-omission contract).

git_diff_summary — error codes

Code Meaning
git_not_found git binary not on PATH.
not_a_git_repository The resolved workspace root is not inside a git repository.
unsafe_range_token The range string contains characters outside the safe token set.
git_diff_failed git diff exited non-zero.

batch_commit — parameters

Parameter Type Notes
commits {message: string, files: string[]}[] Commits to create in order. 1–50 entries. Each files entry is a path relative to the git root; all must stay within the git toplevel.
push "never" | "after" Default "never". "after" pushes the current branch to its upstream once all commits succeed. Never auto-sets upstream — branches without an upstream fail with push_no_upstream. Commits are not rolled back on push failure. Enum reserved for future modes such as "force-with-lease".
workspaceRoot string Explicit root; highest priority.
rootIndex int Pick one of several MCP roots (0-based).
format "markdown" | "json" Output format. Default: "markdown".

batch_commit — JSON shape (format: "json")

{
  "ok": true,
  "committed": 2,
  "total": 2,
  "results": [{
    "index": 0,
    "ok": true,
    "sha": "a1b2c3d",
    "message": "feat: add foo",
    "files": ["src/foo.ts"]
  }, {
    "index": 1,
    "ok": true,
    "sha": "b2c3d4e",
    "message": "chore: update config",
    "files": ["config.json"]
  }],
  "push": {
    "ok": true,
    "branch": "main",
    "upstream": "origin/main"
  }
}

On first failure ok is false, committed reflects only the entries that succeeded before the error, and the failing entry includes error and detail fields. Remaining entries are skipped and not included in results.

The push object is present only when push: "after" was requested and every commit landed. On push failure the top-level ok stays true (the commits themselves succeeded) while push.ok is false and push.error carries the code.

batch_commit — error codes (per-result error field)

Code Meaning
path_escapes_repository One of the listed file paths resolves outside the git toplevel.
stage_failed git add failed (e.g. untracked path or permission error).
commit_failed git commit failed (e.g. nothing staged, hooks rejected).
not_a_git_repository The resolved workspace root is not inside a git repository.

batch_commit — push error codes (push.error field)

Code Meaning
push_detached_head HEAD is detached; no branch to push.
push_no_upstream Current branch has no configured upstream. batch_commit will not auto-set one — do git push -u origin <branch> yourself (or re-run without push).
push_failed git push exited non-zero (network error, non-fast-forward, hook rejection). detail carries the stderr/stdout from git.

git_merge — parameters

Parameter Type Notes
sources string[] Source branches to merge, in order. 1–20 entries. Each must be a valid git ref token.
into string Destination branch. Defaults to the currently checked-out branch. Rejected when HEAD is detached.
strategy "auto" | "ff-only" | "rebase" | "merge" Default "auto": cascade fast-forward → rebase → merge-commit per source. "ff-only" fails on divergence. "rebase" rebases source onto destination and fast-forwards; no merge-commit fallback. "merge" always creates a merge commit (--no-ff).
message string Merge commit message, used only when a merge commit is created. Defaults to Merge branch '<source>' into <into>.
deleteMergedBranches boolean Default false. After all sources land cleanly, delete each source branch locally (git branch -d). Protected names always skipped (main, master, dev, develop, stable, trunk, prod, production, release/*, release-*, hotfix/*, hotfix-*). Never touches remote refs.
deleteMergedWorktrees boolean Default false. After success, remove any local worktree currently checked out on a source branch (git worktree remove). Protected tails always skipped.
workspaceRoot, rootIndex, format Standard workspace pick + output format.

git_merge — JSON shape (format: "json")

{
  "ok": true,
  "into": "main",
  "strategy": "auto",
  "headSha": "a1b2c3d4e5f6…",
  "applied": 2,
  "total": 2,
  "results": [
    {
      "source": "feature/a",
      "ok": true,
      "outcome": "fast_forward",
      "mergedSha": "a1b2c3d4e5f6…",
      "branchDeleted": true,
      "worktreeRemoved": "/tmp/agent-a"
    },
    {
      "source": "feature/b",
      "ok": true,
      "outcome": "rebase_then_ff",
      "mergedSha": "b2c3d4e5f6a1…"
    }
  ]
}

outcome (per source): fast_forward, rebase_then_ff, merge_commit, up_to_date, or conflicts. Cleanup fields (branchDeleted, worktreeRemoved) are only emitted when the corresponding flag was set and the operation actually ran — both are omitted for up-to-date sources and are never populated on partial-failure runs.

On conflict: top-level ok is false, the conflicting entry has ok: false with conflictStage ("rebase" or "merge"), conflictPaths (array of paths with unresolved markers), and an error code. Remaining sources are not attempted.

git_merge — error codes

Code Meaning
unsafe_ref_token A source or into contains characters outside the argv-safe subset (spaces, shell meta, .., @{, leading -, trailing .lock).
into_detached_head HEAD is detached and no into was given — the tool needs a concrete destination branch.
working_tree_dirty Uncommitted changes present. Commit, stash, or discard before merging.
checkout_failed Could not switch to into. detail carries git's stderr.
destination_not_found into does not resolve to a commit.
not_a_git_repository The resolved workspace root is not inside a git repository.
source_not_found (per source) A source branch name does not resolve.
cannot_fast_forward (per source) strategy: "ff-only" refused because branches have diverged.
rebase_conflicts (per source) Rebase encountered conflicts. Repo state is cleaned before returning.
merge_conflicts (per source) Merge commit encountered conflicts. Repo state is cleaned before returning.
merge_failed (per source) git merge --ff-only failed unexpectedly. detail carries stderr.
merge_base_failed (per source) git merge-base failed (usually unrelated histories).

git_cherry_pick — parameters

Parameter Type Notes
sources string[] Source specs. 1–50 entries. Each entry is one of: a full/short SHA, an A..B / A...B range, or a branch name. Branch names expand to onto..<branch> (oldest-first).
onto string Destination branch. Defaults to the currently checked-out branch. Rejected when HEAD is detached.
deleteMergedBranches boolean Default false. After all commits apply, delete each branch-kind source locally (git branch -d) when it is fully merged into the destination by SHA-reachability (not patch-equivalence). Protected names always skipped; never touches remote refs.
deleteMergedWorktrees boolean Default false. After success, remove any local worktree attached to a branch-kind source (git worktree remove). Protected tails always skipped.
workspaceRoot, rootIndex, format Standard workspace pick + output format.

git_cherry_pick — JSON shape (format: "json")

{
  "ok": true,
  "onto": "main",
  "headSha": "a1b2c3d…",
  "picked": 3,
  "applied": 2,
  "results": [
    { "source": "feature/a", "kind": "branch", "resolvedCommits": 2, "keptCommits": 2 },
    { "source": "abcdef1",    "kind": "sha",    "resolvedCommits": 1, "keptCommits": 1 }
  ]
}

picked is the number of unique SHAs fed to git cherry-pick after SHA-reachability filtering. applied is the number of new commits actually added to HEAD — may be less than picked because the tool passes --empty=drop to git, so patch-equivalent commits are skipped at apply time without error.

kind is "sha", "range", or "branch". resolvedCommits is how many commits the source expanded to; keptCommits is how many survived SHA-reachability dedupe. Cleanup fields (branchDeleted, worktreeRemoved) are only emitted for branch-kind sources when the corresponding flag was set and the operation succeeded.

On conflict, the response has ok: false and a top-level conflict object:

{
  "ok": false,
  "onto": "main",
  "picked": 2,
  "applied": 0,
  "results": [ ... ],
  "conflict": {
    "stage": "cherry-pick",
    "commit": "abcdef1",
    "paths": ["src/foo.ts"],
    "detail": "…git stderr…"
  }
}

Repo state is cleaned (git cherry-pick --abort) before returning — no partially-applied index.

git_cherry_pick — error codes

Code Meaning
unsafe_ref_token A source or onto contains characters outside the argv-safe subset.
onto_detached_head HEAD is detached and no onto was given.
working_tree_dirty Uncommitted changes present. Commit, stash, or discard before cherry-picking.
checkout_failed Could not switch to onto.
destination_not_found onto does not resolve to a commit.
source_not_found A source spec resolves to neither a branch, a range, nor a commit.
range_resolution_failed git rev-list failed to expand a range spec.
not_a_git_repository The resolved workspace root is not inside a git repository.

Resource

URI Purpose
rethunk-git://presets JSON snapshot of .rethunk/git-mcp-presets.json at the resolved git toplevel (or structured errors).

Workspace root resolution

Order applied when resolving which directory(ies) tools run against:

  1. Explicit workspaceRoot on the tool call (highest priority).
  2. rootIndex (0-based) — one file:// MCP root when several exist.
  3. allWorkspaceRoots: true — every file:// root; markdown output emits one # {tool} header with per-root subsections (git_inventory uses ### {gitTop}; git_status uses ### MCP root: ...), or combined JSON.
  4. preset set and multiple roots — first root whose git toplevel defines that preset (respecting workspaceRootHint on the preset entry when present).
  5. Otherwise the first file:// root from MCP initialize / roots/list_changed.
  6. process.cwd() if no file roots (e.g. CI with explicit workspaceRoot).

Roots come from the MCP session (FastMCP with roots: { enabled: true } in code); there is no fixed cwd in server config.