@rethunk/mcp-multi-root-git 2.3.4 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/AGENTS.md +29 -3
  2. package/CHANGELOG.md +43 -0
  3. package/HUMANS.md +54 -5
  4. package/README.md +15 -1
  5. package/dist/server/batch-commit-tool.js +244 -19
  6. package/dist/server/git-diff-tool.js +132 -0
  7. package/dist/server/git-fetch-tool.js +131 -0
  8. package/dist/server/git-push-tool.js +8 -1
  9. package/dist/server/git-show-tool.js +148 -0
  10. package/dist/server/git-stash-tool.js +131 -0
  11. package/dist/server/git-tag-tool.js +162 -0
  12. package/dist/server/git.js +18 -2
  13. package/dist/server/roots.js +8 -4
  14. package/dist/server/test-harness.js +68 -5
  15. package/dist/server/tool-parameter-schemas.js +21 -1
  16. package/dist/server/tools.js +11 -0
  17. package/docs/install.md +19 -2
  18. package/docs/mcp-tools.md +214 -5
  19. package/package.json +7 -5
  20. package/schemas/batch_commit.json +125 -0
  21. package/schemas/git_cherry_pick.json +63 -0
  22. package/schemas/git_diff.json +62 -0
  23. package/schemas/git_diff_summary.json +75 -0
  24. package/schemas/git_fetch.json +52 -0
  25. package/schemas/git_inventory.json +74 -0
  26. package/schemas/git_log.json +75 -0
  27. package/schemas/git_merge.json +79 -0
  28. package/schemas/git_parity.json +74 -0
  29. package/schemas/git_push.json +50 -0
  30. package/schemas/git_reset_soft.json +42 -0
  31. package/schemas/git_show.json +39 -0
  32. package/schemas/git_stash_apply.json +44 -0
  33. package/schemas/git_stash_list.json +30 -0
  34. package/schemas/git_status.json +49 -0
  35. package/schemas/git_tag.json +50 -0
  36. package/schemas/git_worktree_add.json +52 -0
  37. package/schemas/git_worktree_list.json +30 -0
  38. package/schemas/git_worktree_remove.json +48 -0
  39. package/schemas/index.json +108 -0
  40. package/schemas/list_presets.json +44 -0
  41. package/tool-parameters.schema.json +317 -4
package/docs/mcp-tools.md CHANGED
@@ -17,14 +17,20 @@ MCP clients expose tools as `{serverName}_{toolName}`. With the server registere
17
17
  | `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 (includes `absoluteGitRoots`). **Read-only.** |
18
18
  | `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 (`absoluteGitRoots` for sibling clones) + `format`. **Read-only.** |
19
19
  | `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 (optional single-entry `absoluteGitRoots`) + `format`. **Read-only.** |
20
+ | `git_diff` | `rethunk-git_git_diff` | Raw diff text for a single repo. Supports unstaged, staged, or `base..head` ranges, optionally scoped to one path. Args: `base?`, `head?`, `path?`, `staged?`, plus single-repo workspace pick + `format`. **Read-only.** |
21
+ | `git_show` | `rethunk-git_git_show` | Inspect one commit or ref. Returns commit message plus diff, or file content at `path` for that ref. Args: `ref`, `path?`, plus single-repo workspace pick + `format`. **Read-only.** |
20
22
  | `git_worktree_list` | `rethunk-git_git_worktree_list` | List all worktrees (`git worktree list --porcelain`). Workspace pick + `format`. **Read-only.** |
23
+ | `git_stash_list` | `rethunk-git_git_stash_list` | List `git stash` entries for one repo. Args: single-repo workspace pick + `format`. **Read-only.** |
24
+ | `git_fetch` | `rethunk-git_git_fetch` | Fetch from a remote without modifying the working tree. Updates refs only and reports updated/new refs. Args: `remote?`, `branch?`, `prune?`, `tags?`, plus single-repo workspace pick + `format`. **Mutating — refs only.** |
21
25
  | `git_push` | `rethunk-git_git_push` | Push the current branch to its upstream. Optional `remote`, `branch`, `setUpstream` (passes `-u`). Refuses on detached HEAD; never force-pushes. Workspace pick + `format`. **Mutating.** |
26
+ | `git_tag` | `rethunk-git_git_tag` | Create/delete annotated or lightweight tags for one repo. Args: `tag`, `message?`, `ref?`, `delete?`, plus single-repo workspace pick + `format`. **Mutating.** |
22
27
  | `git_worktree_add` | `rethunk-git_git_worktree_add` | Create a new linked worktree, creating the branch from `baseRef` if it does not yet exist. Refuses on protected branch names. Args: `path`, `branch`, `baseRef?`, plus workspace pick + `format`. **Mutating.** |
23
28
  | `git_worktree_remove` | `rethunk-git_git_worktree_remove` | Remove a registered worktree; refuses to remove the main worktree. Optional `force: true` for dirty trees. Args: `path`, `force?`, plus workspace pick + `format`. **Mutating.** |
24
29
  | `git_reset_soft` | `rethunk-git_git_reset_soft` | Soft-reset the current branch to a ref (`HEAD~N`, SHA, branch). Rewound changes land in the staging index; requires a clean working tree. Args: `ref`, plus workspace pick + `format`. **Mutating — not idempotent.** |
25
- | `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.** |
30
+ | `batch_commit` | `rethunk-git_batch_commit` | Create multiple sequential git commits in a single call. Each entry stages the listed files or line-ranged file hunks, then commits with the given message. Stops on first failure. Optional `push: "after"` pushes once every commit lands; optional `dryRun: true` previews staged content without writing commits. Args: `commits` (array of `{message, files}`), `push?`, `dryRun?`, plus workspace pick args + `format`. **Mutating — not idempotent.** |
26
31
  | `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.** |
27
32
  | `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.** |
33
+ | `git_stash_apply` | `rethunk-git_git_stash_apply` | Apply or pop a stash entry for one repo. Args: `index?`, `pop?`, plus single-repo workspace pick + `format`. **Mutating.** |
28
34
 
29
35
  Pass **`format: "json"`** on any tool for structured JSON instead of markdown (default).
30
36
 
@@ -32,7 +38,7 @@ Pass **`format: "json"`** on any tool for structured JSON instead of markdown (d
32
38
 
33
39
  Tool JSON bodies are minified and contain only the payload — no `rethunkGitMcp` envelope. Current `MCP_JSON_FORMAT_VERSION` is **`"3"`**; 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`**.
34
40
 
35
- The package also ships **`tool-parameters.schema.json`**, generated from the registered Zod parameter schemas via `bun run schema:tools`. Connected MCP clients should still prefer live schema discovery from `initialize` / tool listing; the artifact is for offline inspection and drift checks.
41
+ The package also ships **`tool-parameters.schema.json`**, generated from the registered Zod parameter schemas via `bun run schema:tools`, plus the published **`schemas/`** directory (`schemas/index.json` + one JSON Schema per tool) via `bun run schema:individual`. Connected MCP clients should still prefer live schema discovery from `initialize` / tool listing; the shipped artifacts are for offline inspection, drift checks, and code generation.
36
42
 
37
43
  ### v2/v3 field omission (consumer contract)
38
44
 
@@ -179,12 +185,151 @@ The response contains one **`parity[]`** entry per resolved git toplevel. `absol
179
185
 
180
186
  ---
181
187
 
188
+ ### `git_diff` — parameters
189
+
190
+ | Parameter | Type | Default | Notes |
191
+ |-----------|------|---------|-------|
192
+ | `base` | string | — | Base ref for a revision diff. When omitted with no `staged`, the tool shows unstaged changes. |
193
+ | `head` | string | `HEAD` | Head ref for a revision diff. Used only when `base` is provided. |
194
+ | `path` | string | — | Optional single file path to scope the diff. |
195
+ | `staged` | boolean | `false` | When `true`, runs `git diff --staged`. Ignored when `base` is provided. |
196
+ | `workspaceRoot`, `rootIndex`, `format` | — | Standard single-repo workspace pick + output format. |
197
+
198
+ ### `git_diff` — JSON shape (`format: "json"`)
199
+
200
+ ```json
201
+ {
202
+ "range": "HEAD~1..HEAD (src/server.ts)",
203
+ "diff": "diff --git a/src/server.ts b/src/server.ts\n..."
204
+ }
205
+ ```
206
+
207
+ ### `git_diff` — error codes
208
+
209
+ | Code | Meaning |
210
+ |------|---------|
211
+ | `unsafe_range_token` | `base` or `head` contains characters outside the argv-safe subset. |
212
+ | `git_diff_failed` | `git diff` exited non-zero. |
213
+ | `not_a_git_repository` | The resolved workspace root is not inside a git repository. |
214
+
215
+ ---
216
+
217
+ ### `git_show` — parameters
218
+
219
+ | Parameter | Type | Notes |
220
+ |-----------|------|-------|
221
+ | `ref` | string | Commit, branch, tag, or other git rev-spec to inspect. |
222
+ | `path` | string | Optional single path. When provided, the response shows that path's content at `ref` instead of the full commit diff. |
223
+ | `workspaceRoot`, `rootIndex`, `format` | — | Standard single-repo workspace pick + output format. |
224
+
225
+ ### `git_show` — JSON shape (`format: "json"`)
226
+
227
+ ```json
228
+ {
229
+ "ref": "HEAD",
230
+ "message": "feat: add tool",
231
+ "path": "src/server.ts",
232
+ "diff": "diff --git a/src/server.ts b/src/server.ts\n..."
233
+ }
234
+ ```
235
+
236
+ `path` is omitted when not requested. `diff` is omitted when `git show` returns only a commit message.
237
+
238
+ ### `git_show` — error codes
239
+
240
+ | Code | Meaning |
241
+ |------|---------|
242
+ | `git_show_failed` | `git show` exited non-zero (e.g. unknown ref). |
243
+ | `not_a_git_repository` | The resolved workspace root is not inside a git repository. |
244
+
245
+ ---
246
+
247
+ ### `git_stash_list` — parameters
248
+
249
+ | Parameter | Type | Notes |
250
+ |-----------|------|-------|
251
+ | `workspaceRoot`, `rootIndex`, `format` | — | Standard single-repo workspace pick + output format. |
252
+
253
+ ### `git_stash_list` — JSON shape (`format: "json"`)
254
+
255
+ ```json
256
+ {
257
+ "stashes": [
258
+ { "index": 0, "message": "WIP on main: abc1234 feat: add tool", "sha": "abc1234" }
259
+ ]
260
+ }
261
+ ```
262
+
263
+ ### `git_stash_list` — error codes
264
+
265
+ | Code | Meaning |
266
+ |------|---------|
267
+ | `stash_list_failed` | `git stash list` failed unexpectedly. |
268
+ | `not_a_git_repository` | The resolved workspace root is not inside a git repository. |
269
+
270
+ ---
271
+
272
+ ### `git_fetch` — parameters
273
+
274
+ | Parameter | Type | Default | Notes |
275
+ |-----------|------|---------|-------|
276
+ | `remote` | string | `"origin"` | Remote to fetch from. |
277
+ | `branch` | string | — | Optional branch/ref to fetch from that remote. |
278
+ | `prune` | boolean | `false` | Pass `--prune` to remove deleted remote-tracking refs. |
279
+ | `tags` | boolean | `false` | Pass `--tags` to also fetch all tags. |
280
+ | `workspaceRoot`, `rootIndex`, `format` | — | Standard single-repo workspace pick + output format. |
281
+
282
+ ### `git_fetch` — JSON shape (`format: "json"`)
283
+
284
+ ```json
285
+ {
286
+ "ok": true,
287
+ "remote": "origin",
288
+ "updatedRefs": ["abc1234..def5678 main -> origin/main"],
289
+ "newRefs": ["[new tag] v2.0.0 -> v2.0.0"],
290
+ "output": "From origin\n..."
291
+ }
292
+ ```
293
+
294
+ Fetch failures are reported as `ok: false` with the captured git output in `output`.
295
+
296
+ ### `git_fetch` — error codes
297
+
298
+ | Code | Meaning |
299
+ |------|---------|
300
+ | `not_a_git_repository` | The resolved workspace root is not inside a git repository. |
301
+
302
+ ---
303
+
304
+ ### `batch_commit` — atomic staging semantics
305
+
306
+ **Critical for AI agents:** Each call to `batch_commit` is **self-contained and atomic per-commit entry**.
307
+
308
+ - **All files in a single entry are staged together.** When you list `files: ["src/foo.ts", "src/bar.ts"]` in one commit entry, both are staged atomically as a unit with a single `git add` before the commit is created.
309
+ - **Each commit entry is processed sequentially within the call.** The tool stages files, commits, then moves to the next entry. All entries within a single `batch_commit` call happen in one atomic MCP transaction.
310
+ - **A single `batch_commit` call cannot be split across multiple MCP calls.** Do NOT attempt incremental staging like "call 1 with file A, then call 2 with file B hoping they stage together." Each call is independent — call 1's commit lands immediately; call 2's changes are a separate transaction.
311
+ - **Failed entry stops the batch.** If staging or commit fails on entry N, the tool aborts and skips remaining entries. However, **entries that succeeded before the failure remain committed** — they are not rolled back.
312
+ - **Include all files for a logical change in a single `batch_commit` call.** Group related files in each commit entry, list them all in the `files` array, and include all necessary entries in the `commits` array.
313
+
314
+ Example: to commit two related changes atomically, pass both entries in one call:
315
+ ```json
316
+ {
317
+ "commits": [
318
+ { "message": "feat: add foo module", "files": ["src/foo.ts", "tests/foo.test.ts"] },
319
+ { "message": "feat: integrate foo into bar", "files": ["src/bar.ts", "docs/foo.md"] }
320
+ ]
321
+ }
322
+ ```
323
+
324
+ Do NOT do this: make two separate calls hoping to stage files incrementally. That breaks the contract.
325
+
182
326
  ### `batch_commit` — parameters
183
327
 
184
328
  | Parameter | Type | Notes |
185
329
  |-----------|------|-------|
186
- | `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. |
330
+ | `commits` | `{message: string, files: (string \| {path: string, lines: {from: number, to: number}})[]}[]` | Commits to create in order. 1–50 entries. Each `files` entry is either a path relative to the git root or a `{path, lines}` object for hunk-level staging. All paths must stay within the git toplevel. |
187
331
  | `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"`. |
332
+ | `dryRun` | boolean | Default `false`. When `true`, stages each entry, reports what would be committed (`staged`, `diffStat`), then unstages everything without writing commits. |
188
333
  | `workspaceRoot` | string | Explicit root; highest priority. |
189
334
  | `rootIndex` | int | Pick one of several MCP roots (0-based). |
190
335
  | `format` | `"markdown"` \| `"json"` | Output format. Default: `"markdown"`. |
@@ -219,6 +364,8 @@ The response contains one **`parity[]`** entry per resolved git toplevel. `absol
219
364
 
220
365
  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`.
221
366
 
367
+ When `dryRun: true`, the top-level response includes `dryRun: true`; successful `results[*]` entries omit `sha` and instead include `staged` and `diffStat`.
368
+
222
369
  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.
223
370
 
224
371
  ### `batch_commit` — error codes (per-result `error` field)
@@ -399,6 +546,39 @@ For already-committed work, call **`git_push`** directly instead of creating an
399
546
 
400
547
  ---
401
548
 
549
+ ### `git_tag` — parameters
550
+
551
+ | Parameter | Type | Default | Notes |
552
+ |-----------|------|---------|-------|
553
+ | `tag` | string | — | Tag name to create or delete. |
554
+ | `message` | string | — | When provided, creates an annotated tag; otherwise creates a lightweight tag. |
555
+ | `ref` | string | `HEAD` | Commit/ref to tag. Ignored when `delete: true`. |
556
+ | `delete` | boolean | `false` | Delete the named tag instead of creating it. |
557
+ | `workspaceRoot`, `rootIndex`, `format` | — | Standard single-repo workspace pick + output format. |
558
+
559
+ ### `git_tag` — JSON shape (`format: "json"`)
560
+
561
+ ```json
562
+ { "tag": "v2.3.5", "type": "annotated", "sha": "a1b2c3d4e5f6..." }
563
+ ```
564
+
565
+ For deletions, `type` is `"deleted"` and `sha` is an empty string.
566
+
567
+ ### `git_tag` — error codes
568
+
569
+ | Code | Meaning |
570
+ |------|---------|
571
+ | `tag_empty` | `tag` trimmed to an empty string. |
572
+ | `tag_unsafe` | `tag` contains disallowed characters. |
573
+ | `ref_unsafe` | `ref` contains disallowed characters. |
574
+ | `ref_not_found` | `ref` did not resolve to a commit. |
575
+ | `tag_create_failed` | `git tag` failed while creating the tag. |
576
+ | `tag_delete_failed` | `git tag -d` failed. |
577
+ | `tag_verification_failed` | The tag could not be read back after creation. |
578
+ | `not_a_git_repository` | The resolved workspace root is not inside a git repository. |
579
+
580
+ ---
581
+
402
582
  ### `git_reset_soft` — parameters
403
583
 
404
584
  | Parameter | Type | Notes |
@@ -424,6 +604,35 @@ For already-committed work, call **`git_push`** directly instead of creating an
424
604
 
425
605
  ---
426
606
 
607
+ ### `git_stash_apply` — parameters
608
+
609
+ | Parameter | Type | Default | Notes |
610
+ |-----------|------|---------|-------|
611
+ | `index` | int | `0` | Stash index to apply/pop (`stash@{index}`). |
612
+ | `pop` | boolean | `false` | When `true`, runs `git stash pop` instead of `git stash apply`. |
613
+ | `workspaceRoot`, `rootIndex`, `format` | — | Standard single-repo workspace pick + output format. |
614
+
615
+ ### `git_stash_apply` — JSON shape (`format: "json"`)
616
+
617
+ ```json
618
+ {
619
+ "applied": true,
620
+ "stashIndex": 0,
621
+ "popped": false,
622
+ "output": "On branch main\nChanges not staged for commit:\n..."
623
+ }
624
+ ```
625
+
626
+ `output` is omitted when git produced no stdout/stderr text.
627
+
628
+ ### `git_stash_apply` — error codes
629
+
630
+ | Code | Meaning |
631
+ |------|---------|
632
+ | `not_a_git_repository` | The resolved workspace root is not inside a git repository. |
633
+
634
+ ---
635
+
427
636
  ### `git_worktree_list` — JSON shape (`format: "json"`)
428
637
 
429
638
  ```json
@@ -515,7 +724,7 @@ Order applied when resolving which directory(ies) tools run against:
515
724
  2. **`rootIndex`** (0-based) — one `file://` MCP root when several exist.
516
725
  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.
517
726
  4. **`preset`** set and multiple roots — first root whose git toplevel defines that preset (respecting **`workspaceRootHint`** on the preset entry when present).
518
- 5. Otherwise the first `file://` root from MCP **`initialize`** / **`roots/list_changed`**.
727
+ 5. Otherwise the first `file://` root reported by the MCP client through **`roots/list`**.
519
728
  6. **`process.cwd()`** if no file roots (e.g. CI with explicit `workspaceRoot`).
520
729
 
521
- Roots come from the MCP session (**`FastMCP` with `roots: { enabled: true }`** in code); there is no fixed `cwd` in server config.
730
+ Roots come from active MCP sessions (**`FastMCP` with `roots: { enabled: true }`** in code); there is no fixed `cwd` in server config. This is what allows one globally installed server to follow the workspace opened in VS Code, Claude Code, Cursor, or any other roots-capable MCP client.
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@rethunk/mcp-multi-root-git",
3
- "version": "2.3.4",
3
+ "version": "2.4.0",
4
4
  "description": "MCP stdio server: multi-root git status, inventory, and HEAD parity checks. Generic tools usable by any workspace.",
5
5
  "type": "module",
6
6
  "private": false,
7
- "packageManager": "bun@1.3.11",
7
+ "packageManager": "bun@1.3.13",
8
8
  "engines": {
9
9
  "node": ">=22.0.0"
10
10
  },
@@ -12,6 +12,7 @@
12
12
  "dist",
13
13
  "git-mcp-presets.schema.json",
14
14
  "tool-parameters.schema.json",
15
+ "schemas",
15
16
  "docs/install.md",
16
17
  "docs/mcp-tools.md",
17
18
  "AGENTS.md",
@@ -35,10 +36,11 @@
35
36
  "coverage:check": "bun scripts/check-coverage.ts",
36
37
  "schema:tools": "bun scripts/generate-tool-parameters-schema.ts",
37
38
  "schema:tools:check": "bun scripts/generate-tool-parameters-schema.ts --check",
39
+ "schema:individual": "bun scripts/generate-individual-schemas.ts",
38
40
  "publish:preflight": "bun scripts/publish-preflight.ts",
39
41
  "test": "bun test src/",
40
42
  "test:coverage": "bun test src/ --coverage",
41
- "prepublishOnly": "bun run schema:tools:check && bun run build && bun run check && bun run test",
43
+ "prepublishOnly": "bun run schema:tools:check && bun run schema:individual && bun run build && bun run check && bun run test",
42
44
  "setup-hooks": "git config core.hooksPath .githooks"
43
45
  },
44
46
  "keywords": [
@@ -63,10 +65,10 @@
63
65
  },
64
66
  "dependencies": {
65
67
  "fastmcp": "^4.0.1",
66
- "zod": "^4.3.6"
68
+ "zod": "^4.4.3"
67
69
  },
68
70
  "devDependencies": {
69
- "@biomejs/biome": "^2.4.13",
71
+ "@biomejs/biome": "^2.4.14",
70
72
  "@types/node": "^25.6.0",
71
73
  "rimraf": "^6.1.3",
72
74
  "typescript": "^6.0.3"
@@ -0,0 +1,125 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "@rethunk/mcp-multi-root-git: batch_commit",
4
+ "description": "Parameter schema for the 'batch_commit' MCP tool.",
5
+ "type": "object",
6
+ "properties": {
7
+ "workspaceRoot": {
8
+ "description": "Highest-priority override.",
9
+ "type": "string"
10
+ },
11
+ "rootIndex": {
12
+ "description": "0-based index into the MCP file roots list; ignored when workspaceRoot is set.",
13
+ "type": "integer",
14
+ "minimum": 0,
15
+ "maximum": 9007199254740991
16
+ },
17
+ "allWorkspaceRoots": {
18
+ "default": false,
19
+ "description": "Fan out across all MCP file roots.",
20
+ "type": "boolean"
21
+ },
22
+ "format": {
23
+ "default": "markdown",
24
+ "type": "string",
25
+ "enum": [
26
+ "markdown",
27
+ "json"
28
+ ]
29
+ },
30
+ "commits": {
31
+ "minItems": 1,
32
+ "maxItems": 50,
33
+ "type": "array",
34
+ "items": {
35
+ "type": "object",
36
+ "properties": {
37
+ "message": {
38
+ "type": "string",
39
+ "minLength": 1,
40
+ "description": "Commit message."
41
+ },
42
+ "files": {
43
+ "minItems": 1,
44
+ "type": "array",
45
+ "items": {
46
+ "anyOf": [
47
+ {
48
+ "type": "string",
49
+ "minLength": 1
50
+ },
51
+ {
52
+ "type": "object",
53
+ "properties": {
54
+ "path": {
55
+ "type": "string",
56
+ "minLength": 1,
57
+ "description": "File path relative to git root."
58
+ },
59
+ "lines": {
60
+ "type": "object",
61
+ "properties": {
62
+ "from": {
63
+ "type": "integer",
64
+ "minimum": 1,
65
+ "maximum": 9007199254740991,
66
+ "description": "Start line number (1-indexed)."
67
+ },
68
+ "to": {
69
+ "type": "integer",
70
+ "minimum": 1,
71
+ "maximum": 9007199254740991,
72
+ "description": "End line number (1-indexed, inclusive)."
73
+ }
74
+ },
75
+ "required": [
76
+ "from",
77
+ "to"
78
+ ],
79
+ "additionalProperties": false,
80
+ "description": "Line range to stage. Only hunks overlapping [from, to] are staged."
81
+ }
82
+ },
83
+ "required": [
84
+ "path",
85
+ "lines"
86
+ ],
87
+ "additionalProperties": false
88
+ }
89
+ ]
90
+ },
91
+ "description": "Paths to stage, relative to the git root. Each can be a string path or { path, lines } for hunk-level staging."
92
+ }
93
+ },
94
+ "required": [
95
+ "message",
96
+ "files"
97
+ ],
98
+ "additionalProperties": false
99
+ },
100
+ "description": "Commits to create, applied in order."
101
+ },
102
+ "push": {
103
+ "default": "never",
104
+ "description": "`never` (default): no push. `after`: push the current branch to its upstream once all commits succeed; fails with `push_no_upstream` if the branch has no upstream (commits are NOT rolled back). Enum reserved for future modes such as `force-with-lease`.",
105
+ "type": "string",
106
+ "enum": [
107
+ "never",
108
+ "after"
109
+ ]
110
+ },
111
+ "dryRun": {
112
+ "default": false,
113
+ "description": "When true, stage files, collect preview (files staged, commit messages), return preview response without writing commits. Unstages any files that were staged for the preview. Response indicates DRY RUN mode.",
114
+ "type": "boolean"
115
+ }
116
+ },
117
+ "required": [
118
+ "allWorkspaceRoots",
119
+ "format",
120
+ "commits",
121
+ "push",
122
+ "dryRun"
123
+ ],
124
+ "additionalProperties": false
125
+ }
@@ -0,0 +1,63 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "@rethunk/mcp-multi-root-git: git_cherry_pick",
4
+ "description": "Parameter schema for the 'git_cherry_pick' MCP tool.",
5
+ "type": "object",
6
+ "properties": {
7
+ "workspaceRoot": {
8
+ "description": "Highest-priority override.",
9
+ "type": "string"
10
+ },
11
+ "rootIndex": {
12
+ "description": "0-based index into the MCP file roots list; ignored when workspaceRoot is set.",
13
+ "type": "integer",
14
+ "minimum": 0,
15
+ "maximum": 9007199254740991
16
+ },
17
+ "allWorkspaceRoots": {
18
+ "default": false,
19
+ "description": "Fan out across all MCP file roots.",
20
+ "type": "boolean"
21
+ },
22
+ "format": {
23
+ "default": "markdown",
24
+ "type": "string",
25
+ "enum": [
26
+ "markdown",
27
+ "json"
28
+ ]
29
+ },
30
+ "sources": {
31
+ "minItems": 1,
32
+ "maxItems": 50,
33
+ "type": "array",
34
+ "items": {
35
+ "type": "string",
36
+ "minLength": 1
37
+ },
38
+ "description": "Sources to cherry-pick: SHA, `A..B` range, or branch name. Branch sources resolve to `onto..<branch>` (only commits missing from destination)."
39
+ },
40
+ "onto": {
41
+ "description": "Destination branch. Defaults to the currently checked-out branch.",
42
+ "type": "string"
43
+ },
44
+ "deleteMergedBranches": {
45
+ "default": false,
46
+ "description": "After all commits apply, delete each branch-kind source locally (`git branch -d`) when it is fully merged into the destination. Protected names always skipped; never touches remote refs.",
47
+ "type": "boolean"
48
+ },
49
+ "deleteMergedWorktrees": {
50
+ "default": false,
51
+ "description": "After success, remove any local worktree attached to a branch-kind source (`git worktree remove`). Protected tails always skipped.",
52
+ "type": "boolean"
53
+ }
54
+ },
55
+ "required": [
56
+ "allWorkspaceRoots",
57
+ "format",
58
+ "sources",
59
+ "deleteMergedBranches",
60
+ "deleteMergedWorktrees"
61
+ ],
62
+ "additionalProperties": false
63
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "@rethunk/mcp-multi-root-git: git_diff",
4
+ "description": "Parameter schema for the 'git_diff' MCP tool.",
5
+ "type": "object",
6
+ "properties": {
7
+ "workspaceRoot": {
8
+ "description": "Highest-priority override.",
9
+ "type": "string"
10
+ },
11
+ "rootIndex": {
12
+ "description": "0-based index into the MCP file roots list; ignored when workspaceRoot is set.",
13
+ "type": "integer",
14
+ "minimum": 0,
15
+ "maximum": 9007199254740991
16
+ },
17
+ "allWorkspaceRoots": {
18
+ "default": false,
19
+ "description": "Fan out across all MCP file roots.",
20
+ "type": "boolean"
21
+ },
22
+ "absoluteGitRoots": {
23
+ "description": "Absolute paths to git repo roots. Use for many sibling clones under a non-git parent directory.",
24
+ "maxItems": 256,
25
+ "type": "array",
26
+ "items": {
27
+ "type": "string"
28
+ }
29
+ },
30
+ "format": {
31
+ "default": "markdown",
32
+ "type": "string",
33
+ "enum": [
34
+ "markdown",
35
+ "json"
36
+ ]
37
+ },
38
+ "base": {
39
+ "description": "Base ref (e.g. \"main\", \"HEAD~3\"). Required for range diffs. If omitted and `staged: false`, shows unstaged changes.",
40
+ "type": "string"
41
+ },
42
+ "head": {
43
+ "description": "Head ref (e.g. \"feature-branch\"). If omitted, defaults to HEAD. Only used if `base` is provided.",
44
+ "type": "string"
45
+ },
46
+ "path": {
47
+ "description": "Scope diff to a single file path (e.g. \"src/main.ts\").",
48
+ "type": "string"
49
+ },
50
+ "staged": {
51
+ "default": false,
52
+ "description": "If true, show staged changes (git diff --staged). Ignored if `base` is provided.",
53
+ "type": "boolean"
54
+ }
55
+ },
56
+ "required": [
57
+ "allWorkspaceRoots",
58
+ "format",
59
+ "staged"
60
+ ],
61
+ "additionalProperties": false
62
+ }
@@ -0,0 +1,75 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "@rethunk/mcp-multi-root-git: git_diff_summary",
4
+ "description": "Parameter schema for the 'git_diff_summary' MCP tool.",
5
+ "type": "object",
6
+ "properties": {
7
+ "workspaceRoot": {
8
+ "description": "Highest-priority override.",
9
+ "type": "string"
10
+ },
11
+ "rootIndex": {
12
+ "description": "0-based index into the MCP file roots list; ignored when workspaceRoot is set.",
13
+ "type": "integer",
14
+ "minimum": 0,
15
+ "maximum": 9007199254740991
16
+ },
17
+ "allWorkspaceRoots": {
18
+ "default": false,
19
+ "description": "Fan out across all MCP file roots.",
20
+ "type": "boolean"
21
+ },
22
+ "absoluteGitRoots": {
23
+ "description": "Absolute paths to git repo roots. Use for many sibling clones under a non-git parent directory.",
24
+ "maxItems": 256,
25
+ "type": "array",
26
+ "items": {
27
+ "type": "string"
28
+ }
29
+ },
30
+ "format": {
31
+ "default": "markdown",
32
+ "type": "string",
33
+ "enum": [
34
+ "markdown",
35
+ "json"
36
+ ]
37
+ },
38
+ "range": {
39
+ "description": "Diff range. Examples: \"staged\", \"HEAD~3..HEAD\", \"main...feature\". Default: unstaged changes.",
40
+ "type": "string"
41
+ },
42
+ "fileFilter": {
43
+ "description": "Glob pattern to restrict output to matching files, e.g. \"*.ts\", \"src/**\".",
44
+ "type": "string"
45
+ },
46
+ "maxLinesPerFile": {
47
+ "default": 50,
48
+ "description": "Max diff lines to include per file. Default: 50.",
49
+ "type": "integer",
50
+ "minimum": 1,
51
+ "maximum": 2000
52
+ },
53
+ "maxFiles": {
54
+ "default": 30,
55
+ "description": "Max files to include in output. Default: 30.",
56
+ "type": "integer",
57
+ "minimum": 1,
58
+ "maximum": 500
59
+ },
60
+ "excludePatterns": {
61
+ "description": "Glob patterns to exclude. Defaults to common noise: lock files, dist, vendor, etc.",
62
+ "type": "array",
63
+ "items": {
64
+ "type": "string"
65
+ }
66
+ }
67
+ },
68
+ "required": [
69
+ "allWorkspaceRoots",
70
+ "format",
71
+ "maxLinesPerFile",
72
+ "maxFiles"
73
+ ],
74
+ "additionalProperties": false
75
+ }