Skip to content

Commit f70222c

Browse files
committed
docs: update mcp-tools contract, compress AGENTS.md
docs/mcp-tools.md - Document v2 field-omission contract: which inventory fields are required vs optional, that empty/null/false fields are omitted (not emitted as null), and that shortStatus is gone. - Note that the upstream object is only emitted in fixed mode. - List which error payloads lost their prose `message` field. - Fix stale reference to `---` separator between roots in markdown (git_inventory uses `### {gitTop}` subsections since 24b4d5e). - Rename the stale `jsonFormatVersion` link text to the real constant `MCP_JSON_FORMAT_VERSION`. AGENTS.md - Compress prose; drop duplicated cross-link language; tighten the changing-contracts bullets; keep the implementation map intact (technical substance — file paths, exported symbols — stays). - Inline the v2 note next to `MCP_JSON_FORMAT_VERSION` in the json.ts row so readers see the current state without scrolling.
1 parent 1930b37 commit f70222c

File tree

2 files changed

+54
-36
lines changed

2 files changed

+54
-36
lines changed

AGENTS.md

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,56 @@
1-
# AGENTS.md — LLM and developer onboarding
1+
# AGENTS.md — LLM + dev onboarding
22

3-
Note for IDEs that inject this file as project context: do not re-link it from rules.
3+
IDEs injecting this as context: do not re-link from rules.
44

5-
**Scope:** [`@rethunk/mcp-multi-root-git`](https://www.npmjs.com/package/@rethunk/mcp-multi-root-git) is an MCP **stdio** server: entry [`src/server.ts`](src/server.ts) (FastMCP + `registerRethunkGitTools`), supporting modules under [`src/server/`](src/server/), build output [`dist/server.js`](dist/server.js) (see `package.json` `bin` / `exports`; publish ships the full `dist/` tree).
5+
**Package:** [`@rethunk/mcp-multi-root-git`](https://www.npmjs.com/package/@rethunk/mcp-multi-root-git). MCP **stdio** server. Entry [`src/server.ts`](src/server.ts) FastMCP + `registerRethunkGitTools`. Build output [`dist/server.js`](dist/server.js) (publish ships full `dist/`).
66

7-
**Operators and integrators:** **[docs/install.md](docs/install.md)** is the **only** place for prerequisites, how to launch the server, and per-client MCP configuration — do not duplicate that in README, HUMANS, rules, or here. Preset file, dev workflow, CI, and publishing: **[HUMANS.md](HUMANS.md)**.
8-
9-
**Tool ids, client naming, `format` / JSON envelopes, resource URI, workspace root order:** **[docs/mcp-tools.md](docs/mcp-tools.md)** — canonical; do not duplicate those tables in this file or HUMANS.
7+
**Canonical docs — do not duplicate:**
8+
- Install + per-client wiring → [docs/install.md](docs/install.md)
9+
- Tools, JSON shape, resources, root resolution → [docs/mcp-tools.md](docs/mcp-tools.md)
10+
- Presets, dev, CI, publish → [HUMANS.md](HUMANS.md)
1011

1112
## Implementation map
1213

13-
| File | Symbols / notes |
14-
|------|-------------------|
14+
| File | Symbols |
15+
|------|---------|
1516
| [`src/server.ts`](src/server.ts) | `FastMCP` + `roots: { enabled: true }`; `readMcpServerVersion()`; `registerRethunkGitTools` |
16-
| [`src/server/json.ts`](src/server/json.ts) | `MCP_JSON_FORMAT_VERSION`, `jsonRespond()`, `spreadWhen`, `spreadDefined` — tool JSON is minified payload only (no envelope since v2) |
17-
| [`src/server/git.ts`](src/server/git.ts) | `gateGit()` — lazy `git --version`; `spawnGitAsync`, `asyncPool`, `GIT_SUBPROCESS_PARALLELISM`; `gitTopLevel`, `gitRevParseGitDir`, `gitRevParseHead`, `parseGitSubmodulePaths`, `hasGitMetadata`; `gitStatusSnapshotAsync`, `gitStatusShortBranchAsync`, `fetchAheadBehind`, `isSafeGitUpstreamToken` |
18-
| [`src/server/roots.ts`](src/server/roots.ts) | `uriToPath`, `listFileRoots`, `pathMatchesWorkspaceRootHint`, `resolveWorkspaceRoots`, `resolveRootsForPreset`, `requireGitAndRoots` — session roots only (client wiring: [docs/install.md](docs/install.md)) |
19-
| [`src/server/presets.ts`](src/server/presets.ts) | `PRESET_FILE_PATH`, `splitPresetFileRaw`, `loadPresetsFromGitTop`, `getPresetEntry`, `presetLoadErrorPayload`, `applyPresetNestedRoots`, `applyPresetParityPairs`; Zod `PresetEntrySchema` / `PresetFileSchema` must match [`git-mcp-presets.schema.json`](git-mcp-presets.schema.json) |
17+
| [`src/server/json.ts`](src/server/json.ts) | `MCP_JSON_FORMAT_VERSION="2"`, `jsonRespond()` (minified, no envelope), `spreadWhen`, `spreadDefined` |
18+
| [`src/server/git.ts`](src/server/git.ts) | `gateGit`, `spawnGitAsync`, `asyncPool`, `GIT_SUBPROCESS_PARALLELISM`, `gitTopLevel`, `gitRevParseGitDir`, `gitRevParseHead`, `parseGitSubmodulePaths`, `hasGitMetadata`, `gitStatusSnapshotAsync`, `gitStatusShortBranchAsync`, `fetchAheadBehind`, `isSafeGitUpstreamToken` |
19+
| [`src/server/roots.ts`](src/server/roots.ts) | `uriToPath`, `listFileRoots`, `pathMatchesWorkspaceRootHint`, `resolveWorkspaceRoots`, `resolveRootsForPreset`, `requireGitAndRoots` — session roots only |
20+
| [`src/server/presets.ts`](src/server/presets.ts) | `PRESET_FILE_PATH`, `splitPresetFileRaw`, `loadPresetsFromGitTop`, `getPresetEntry`, `presetLoadErrorPayload`, `applyPresetNestedRoots`, `applyPresetParityPairs`; Zod schemas must match [`git-mcp-presets.schema.json`](git-mcp-presets.schema.json) |
2021
| [`src/server/schemas.ts`](src/server/schemas.ts) | `WorkspacePickSchema`, `MAX_INVENTORY_ROOTS_DEFAULT` |
21-
| [`src/server/inventory.ts`](src/server/inventory.ts) | `validateRepoPath`, `makeSkipEntry`, `buildInventorySectionMarkdown`, `collectInventoryEntry` (uses repo-paths + git) |
22-
| [`src/server/tools.ts`](src/server/tools.ts) | `registerRethunkGitTools`calls per-surface `register*` below |
23-
| [`src/server/git-status-tool.ts`](src/server/git-status-tool.ts) | `registerGitStatusTool``git_status` |
24-
| [`src/server/git-inventory-tool.ts`](src/server/git-inventory-tool.ts) | `registerGitInventoryTool``git_inventory` |
25-
| [`src/server/git-parity-tool.ts`](src/server/git-parity-tool.ts) | `registerGitParityTool``git_parity` |
26-
| [`src/server/list-presets-tool.ts`](src/server/list-presets-tool.ts) | `registerListPresetsTool``list_presets` |
27-
| [`src/server/presets-resource.ts`](src/server/presets-resource.ts) | `registerPresetsResource``rethunk-git://presets` resource |
22+
| [`src/server/inventory.ts`](src/server/inventory.ts) | `InventoryEntryJson`, `validateRepoPath`, `makeSkipEntry`, `buildInventorySectionMarkdown`, `collectInventoryEntry` |
23+
| [`src/server/tools.ts`](src/server/tools.ts) | `registerRethunkGitTools`dispatches to `register*` below |
24+
| [`src/server/git-status-tool.ts`](src/server/git-status-tool.ts) | `git_status` |
25+
| [`src/server/git-inventory-tool.ts`](src/server/git-inventory-tool.ts) | `git_inventory` |
26+
| [`src/server/git-parity-tool.ts`](src/server/git-parity-tool.ts) | `git_parity` |
27+
| [`src/server/list-presets-tool.ts`](src/server/list-presets-tool.ts) | `list_presets` |
28+
| [`src/server/presets-resource.ts`](src/server/presets-resource.ts) | `rethunk-git://presets` resource |
2829
| [`src/repo-paths.ts`](src/repo-paths.ts) | `resolvePathForRepo`, `assertRelativePathUnderTop`, `isStrictlyUnderGitTop`, `realPathOrSelf` |
2930

3031
## Changing contracts
3132

32-
- **Documentation layout:** do not add top-of-file **banner** paragraphs (bold blocks such as “Canonical doc for… / link here only”) to `docs/install.md` or other shipped docs. Use normal titles, TOC, and cross-links from README / this file / HUMANS.
33-
- **`MCP_JSON_FORMAT_VERSION`:** bump the constant and document the migration here and in [docs/mcp-tools.md](docs/mcp-tools.md) when JSON field names, nesting, or emitted-fields change incompatibly. Current value: **`"2"`** (v2 removed the `rethunkGitMcp` envelope; payloads are minified).
34-
- **Preset file:** keep **`splitPresetFileRaw`** + Zod parsing aligned with **`git-mcp-presets.schema.json`**; update the schema when adding keys or shapes.
35-
- **Public tool surface:** if you add/rename tools, update [docs/mcp-tools.md](docs/mcp-tools.md) and [README.md](README.md) if the landing page still mentions tools; update [docs/install.md](docs/install.md) if install or client-specific wiring changes — **never** copy install steps into other docs; update [.cursor/rules/rethunk-git-mcp.mdc](.cursor/rules/rethunk-git-mcp.mdc) only if *when-to-use MCP vs shell* wording must change (that rule links `docs/install.md`, [HUMANS.md](HUMANS.md), and `docs/mcp-tools.md` without duplicating them).
33+
- **No banner paragraphs** in shipped docs. Use normal titles + cross-links.
34+
- **`MCP_JSON_FORMAT_VERSION`** (currently `"2"`): bump on incompatible JSON changes (renamed/nested/omitted fields). Document migration here + [docs/mcp-tools.md](docs/mcp-tools.md). v2 removed the `rethunkGitMcp` envelope; payloads are minified; optional fields omitted when empty/null/false.
35+
- **Preset file:** keep `splitPresetFileRaw` + Zod aligned with [`git-mcp-presets.schema.json`](git-mcp-presets.schema.json).
36+
- **Public tool surface:** rename/add → update [docs/mcp-tools.md](docs/mcp-tools.md) + [README.md](README.md) (if mentioned). Install/client wiring → [docs/install.md](docs/install.md) only. `.cursor/rules/rethunk-git-mcp.mdc`only when *MCP-vs-shell* guidance changes.
3637

37-
## Validation and CI
38+
## Validate + CI
3839

39-
Local: `bun run build` (`rimraf dist && tsc`), `bun run check` (Biome), `bun run test` (`bun test` for [`src/repo-paths.test.ts`](src/repo-paths.test.ts)). GitHub Actions runs the same after `bun install --frozen-lockfile` on PRs and `main` ([`.github/workflows/ci.yml`](.github/workflows/ci.yml)), then uploads a **prerelease `npm pack` artifact**. Pushes of tag **`v*.*.*`** matching `package.json` `version` run [`.github/workflows/release.yml`](.github/workflows/release.yml) (**GitHub Packages** npm publish under **`@rethunk-ai/mcp-multi-root-git`** + **GitHub Release** with tarball); **npmjs** is manual only — see [HUMANS.md](HUMANS.md) Publishing.
40+
Local: `bun run build` | `bun run check` | `bun run test`. CI ([`ci.yml`](.github/workflows/ci.yml)) runs same on PRs + `main` after `bun install --frozen-lockfile`, uploads prerelease `npm pack` artifact. Tag `v*.*.*` matching `package.json` version [`release.yml`](.github/workflows/release.yml) publishes to GitHub Packages as `@rethunk-ai/mcp-multi-root-git` + cuts GitHub Release. npmjs publish is manual (see [HUMANS.md](HUMANS.md)).
4041

41-
Optional [`.githooks/`](.githooks): run **`bun run setup-hooks`** once per clone (`core.hooksPath``.githooks`). **pre-commit** = `check`; **pre-push** = frozen install + build + check. See [HUMANS.md](HUMANS.md) Development.
42+
Optional [`.githooks/`](.githooks): `bun run setup-hooks` once per clone. pre-commit=`check`; pre-push=frozen install + build + check.
4243

43-
Path confinement helpers live in [`src/repo-paths.ts`](src/repo-paths.ts); extend tests when changing that logic.
44+
Path confinement: [`src/repo-paths.ts`](src/repo-paths.ts)extend tests when changing.
4445

45-
## Repository MCP entry (contributors)
46+
## Repo MCP entry (contributors)
4647

47-
Dogfooding from a clone: **[docs/install.md](docs/install.md)***From source (this repository)* only.
48+
Dogfood from clone: [docs/install.md](docs/install.md)*From source*.
4849

49-
This repo may ship **`.cursor/`** config (example MCP entry + **alwaysApply** rule [`.cursor/rules/rethunk-git-mcp.mdc`](.cursor/rules/rethunk-git-mcp.mdc)). The rule covers *when* to call these tools vs shell git and links **`docs/install.md`**, **[HUMANS.md](HUMANS.md)**, and **`docs/mcp-tools.md`** without duplicating their bodies; it does not re-link this file when it is already injected as project context.
50+
Repo ships `.cursor/` with alwaysApply rule [`.cursor/rules/rethunk-git-mcp.mdc`](.cursor/rules/rethunk-git-mcp.mdc) covering MCP-vs-shell usage. Rule does not re-link this file (already injected).
5051

51-
User-level skills may still mention the GitHub **README** for discovery. Canonical references: **tools / JSON****[docs/mcp-tools.md](docs/mcp-tools.md)**; **install / client wiring****[docs/install.md](docs/install.md)** (link it; do not paste per-client JSON into skills); **preset file****[HUMANS.md](HUMANS.md)**.
52+
User-level skills may mention README for discovery. Canonical refs: tools/JSON[docs/mcp-tools.md](docs/mcp-tools.md); install [docs/install.md](docs/install.md); presets → [HUMANS.md](HUMANS.md).
5253

5354
## Commits
5455

55-
Use the team’s **conventional commits + batching** skill (or equivalent): small themed commits, why-focused messages, `git add` + `git commit` in one shell invocation per batch.
56+
Conventional Commits. Small themed commits. Why-focused messages. Stage + commit in one invocation per batch.

docs/mcp-tools.md

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,28 @@ Pass **`format: "json"`** on any tool for structured JSON instead of markdown (d
2020

2121
## JSON responses
2222

23-
Tool JSON bodies are minified and contain only the payload — no `rethunkGitMcp` envelope. Current `MCP_JSON_FORMAT_VERSION` is **`"2"`** (envelope removed); server + format version are discoverable via MCP `initialize`. Payload keys (e.g. `groups`, `inventories`, `parity`, `roots`) are stable within a given format version. Preset-related responses may include **`presetSchemaVersion`**.
23+
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`**.
2424

25-
For **`git_inventory`** with `format: "json"`, each object inside **`inventories`** may include **`nestedRootsTruncated`** (boolean) and **`nestedRootsOmittedCount`** (number) when **`nestedRoots`** was longer than **`maxRoots`**.
25+
### v2 field omission (consumer contract)
2626

27-
**When to bump `jsonFormatVersion` or change payload shape:** [AGENTS.md](../AGENTS.md)*Changing contracts*.
27+
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`.
28+
29+
**`git_inventory``inventories[*]`**
30+
31+
- Always present: `workspace_root`, `entries`.
32+
- 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).
33+
34+
**`git_inventory``entries[*]` (`InventoryEntryJson`)**
35+
36+
- Always present: `label`, `path`, `upstreamMode` (`"auto"` or `"fixed"`).
37+
- Optional (omitted when empty/absent): `branchStatus`, `headAbbrev`, `upstreamRef`, `ahead`, `behind`, `upstreamNote`, `detached` (only emitted as `true`), `skipReason` (only on skipped entries).
38+
- **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).
39+
40+
**Errors** (any tool)
41+
42+
- 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).
43+
44+
**When to bump `MCP_JSON_FORMAT_VERSION` or change payload shape:** [AGENTS.md](../AGENTS.md)*Changing contracts*.
2845

2946
## Resource
3047

@@ -38,7 +55,7 @@ Order applied when resolving which directory(ies) tools run against:
3855

3956
1. Explicit **`workspaceRoot`** on the tool call (highest priority).
4057
2. **`rootIndex`** (0-based) — one `file://` MCP root when several exist.
41-
3. **`allWorkspaceRoots`: true** — every `file://` root; markdown sections separated by `---`, or combined JSON.
58+
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.
4259
4. **`preset`** set and multiple roots — first root whose git toplevel defines that preset (respecting **`workspaceRootHint`** on the preset entry when present).
4360
5. Otherwise the first `file://` root from MCP **`initialize`** / **`roots/list_changed`**.
4461
6. **`process.cwd()`** if no file roots (e.g. CI with explicit `workspaceRoot`).

0 commit comments

Comments
 (0)