# Changelog All notable changes to this project will be documented in this file. ## v2.15.3 - 2026-08-24 Fixes a regression shipped in v2.15.2. The strict git flag allow-list introduced there never covered the `git rev-parse` probes the pre-flight validators emit, so `git_set_working_dir` — whose `validateGitRepo` input defaults to `true` — failed on every path with `Unsafe git flag rejected: --is-inside-work-tree`. The same allow-list rejected a commit, merge, stash, or tag message beginning with `-`, which the input schemas accept. ### Fixed - **`git rev-parse` probes rejected by the allow-list**: `--is-inside-work-tree`, `--show-toplevel`, and `--verify` are now in `SAFE_GIT_OPTIONS`. The pre-flight validators in `src/services/git/providers/cli/utils/git-validators.ts` emit all three — `validateGitRepository`, `getGitRoot`, `validateBranchExists`, `validateCommitRef` — and none of them could reach git while those flags were missing. - **A message beginning with `-` rejected at runtime**: `git_commit`, `git_merge`, `git_stash`, and `git_tag` accept such a message at the schema, but the operations emitted it as a standalone argv entry after `-m` — where the validator must reject it, since git would otherwise parse the message as options. The four operations now emit `--message=`, which is allow-listed and reaches git as data. - **A failed probe reported as "not a git repository"**: `git_set_working_dir` wrapped every `validateRepository` failure in `Path is not a git repository` with the `initializeIfNotPresent` hint, and with `initializeIfNotPresent: true` would have run `git init` after a probe that never returned an answer. Only a genuine not-a-repository or missing-path result takes that branch now; anything else — a rejected flag, git missing from `PATH`, a timeout — is rethrown untouched. ### Internal - **Every tool's real argv is exercised over stdio**: `tests/mcp-server/transports/stdio/tool-argv.e2e.test.ts` spawns the real server over stdio with an SDK client and drives all 28 tools against temporary repositories and a local bare remote, so each tool's actual argv passes through the real `validateGitArgs` — the layer mocked-`execGit` unit tests cannot see. A closing assertion compares the set of tools exercised against `allToolDefinitions`, so a new tool cannot land without argv coverage, and leading-dash messages are pinned end to end on `git_commit`, `git_merge`, `git_stash`, and `git_tag`. - **Pre-flight validators tested against a real git binary**: `tests/services/git/providers/cli/utils/git-validators.test.ts` runs `validateGitRepository`, `getGitRoot`, `validateBranchExists`, and `validateCommitRef` on temp repositories with no `execGit` mock, and asserts a plain directory reports as not a repository rather than as a rejected flag. - **Allow-list sweep widened past `operations/`**: `tests/services/git/providers/cli/utils/allow-list-coverage.test.ts` scraped flag literals only out of `src/services/git/providers/cli/operations/`, which is why the validators' probes were never checked. It now sweeps the whole `src/services/git/providers/cli/` tree — the validators and `CliGitProvider` included, skipping the allow-list file itself — and asserts no operation emits a message as a standalone argv entry after `-m`. ## v2.15.2 - 2026-08-24 Closes [#57](https://github.com/cyanheads/git-mcp-server/issues/57): every tool's advertised `inputSchema` and `outputSchema` now declares JSON Schema 2020-12 instead of draft-07. The MCP SDK's built-in `tools/list` handler converts Zod schemas with a hardcoded `draft-7` target and no override, so a client whose validator registers only the 2020-12 meta-schema refused the dialect label before reading the schema body and disabled every tool at registration. The schema bodies were never the problem — only the label. The other half of this release closes the argument-injection surface: any caller-supplied value that reaches `git` as a positional argument and starts with `-` is parsed by git as an option flag, which turns "clone this URL" or "check out this ref" into arbitrary command execution through flags like `--upload-pack=`, `--config=core.sshCommand=`, or `--exec=`. Three independent layers now stand in the way — schema validation, a strict flag allow-list in the command builder, and `--end-of-options` in the argv the service emits. Thank you to everyone who has taken the time to send in security reports and advisories for this project. That feedback prompted the review behind the hardening in this release. ### Fixed - **`tools/list` advertised the draft-07 dialect**: `ToolRegistry.registerAll` now installs its own `tools/list` handler (`server.server.setRequestHandler(ListToolsRequestSchema, …)`) after the registration loop, building each entry with `z.toJSONSchema(schema, { target: 'draft-2020-12', io })` — `io: 'input'` for inputs, `io: 'output'` for outputs, mirroring the SDK's own conversion parameters so defaults and optionality serialize identically. `registerTool` still receives the Zod schemas, so `tools/call` argument and result validation are untouched; only the advertised listing changes. New `src/mcp-server/tools/utils/toolListing.ts` owns the conversion and exports `buildToolListing` plus the `deriveToolTitle` fallback that moved out of `ToolRegistry`. ### Security - **Leading-dash values rejected at the tool boundary**: `BranchNameSchema`, `CommitRefSchema`, `RemoteNameSchema`, and `TagNameSchema` now reject a leading `-`. Two new shared schemas cover the rest: `GitUrlSchema` requires a recognized source form (`https://`, `http://`, `ssh://`, `git://`, `file://`, scp-style `user@host:path`, or an absolute filesystem path) and additionally rejects a leading `-` on the host or path component, so `ssh://-oProxyCommand=…` and `user@host:-flag` are refused; `GitFilePathSchema` rejects a leading `-` while staying permissive about the path syntaxes git accepts. Fourteen tool definitions adopt them — `git_add`, `git_blame`, `git_changelog_analyze`, `git_checkout`, `git_clone`, `git_commit`, `git_diff`, `git_log`, `git_reflog`, `git_remote`, `git_reset`, `git_show`, `git_stash`, `git_worktree` — replacing the bare `z.string()` fields that previously accepted anything. A filename that genuinely starts with a dash is still reachable as `./-name`. - **`validateGitArgs` enforces a strict flag allow-list**: The validator previously waved through any argument containing `=`, with the strict branch left commented out — so `--config=core.sshCommand=…` passed. Now every `-`-prefixed argument must be a single-letter short flag, one of the two attached-value short forms the operations emit (`-n`, `-L,`), or a long flag whose name before any `=value` is in `SAFE_GIT_OPTIONS`. Anything else throws. The allow-list was expanded to cover the flags the CLI operations actually emit, and the file documents which flags must never be added (`--upload-pack`, `--exec`, `--config`, `--receive-pack`, `--server-option`). - **`--end-of-options` before user-controlled positionals**: `executeClone` now builds its option flags first and emits `--end-of-options` before the remote URL and destination path; `executeRemote` does the same before the name and URL of both `add` and `set-url`. Git stops parsing options at that marker, so even a value that bypasses the schema layer is treated as data. ### Changed - **Dependency refresh**: `@cloudflare/workers-types` `^4.20260506.1 → 5.20260730.1` (pinned exact — 5.20260817.1 and later declare a global `Buffer: any` that collapses every Node `Buffer` type into `any` and trips the type-aware `no-unsafe-*` lint rules), `@hono/mcp` `^0.2.5 → ^0.3.2`, `@hono/node-server` `^2.0.1 → ^2.1.1`, `@modelcontextprotocol/sdk` `^1.29.0 → ^1.30.0`, `@opentelemetry/exporter-metrics-otlp-http` / `exporter-trace-otlp-http` / `sdk-node` `^0.217.0 → ^0.221.0`, `@opentelemetry/resources` / `sdk-metrics` / `sdk-trace-node` `^2.7.1 → ^2.10.0`, `@opentelemetry/auto-instrumentations-node` `^0.75.0 → ^0.79.0`, `@opentelemetry/instrumentation-pino` `^0.63.0 → ^0.67.0`, `@opentelemetry/semantic-conventions` `^1.40.0 → ^1.43.0`, `@supabase/supabase-js` `^2.105.3 → ^2.112.4`, `@types/bun` / `bun-types` `^1.3.13 → ^1.4.0`, `@types/node` `^25.6.0 → ^26.3.0`, `@vitest/coverage-v8` / `vitest` `^4.1.5 → ^4.1.11`, `eslint` `^10.3.0 → ^10.9.1`, `execa` `^9.6.1 → ^10.0.1`, `globals` `^17.6.0 → ^17.11.0`, `hono` `^4.12.18 → ^4.13.4`, `ignore` `^7.0.5 → ^7.0.6`, `jose` `^6.2.3 → ^6.2.10`, `msw` `^2.14.3 → ^2.15.0`, `prettier` `^3.8.3 → ^3.9.6`, `repomix` `^1.14.0 → ^1.18.0`, `typedoc` `^0.28.19 → ^0.28.20`, `typescript-eslint` `^8.59.2 → ^8.68.0`, `vite` `^8.0.10 → ^8.2.2`. New devDependency `ajv` `^8.20.0`, used by the schema tests to compile the advertised listing on a 2020-12-only validator. `packageManager` moves to `bun@1.4.0`. `bun audit` reports zero advisories after the refresh, down from 94. - **`typescript` and `zod` held**: `typescript` stays `^6.0.3` because `typescript-eslint` peers `<6.1.0`; `zod` stays `~4.3.6`, the patch pin introduced in v2.15.1 to keep JSON Schema emission stable across Zod 4 minors. - **`devcheck` outdated step takes a held-package list**: The check used to special-case `zod` by substring. It now matches a `heldPackages` array (`zod`, `typescript`, `@cloudflare/workers-types`) against the package column, and the tip names all three with a pointer to the inline reasons. ### Internal - **Regression tests for the advertised listing**: `tests/mcp-server/tools/utils/toolListing.test.ts` asserts the 2020-12 dialect on every tool, checks the payload contains no `draft-07` reference, compiles every schema on an Ajv 2020 instance (with a control case proving that same validator rejects a draft-07-tagged schema), and diffs each converted schema against the SDK's own `toJsonSchemaCompat` output to prove the bodies are identical apart from `$schema`. `tests/mcp-server/tools/tool-registration.test.ts` pins the wiring — every definition reaches `registerTool` with its Zod schemas intact and the listing handler is installed exactly once, after the loop. - **End-to-end stdio coverage**: `tests/mcp-server/transports/stdio/tool-listing.e2e.test.ts` spawns the real server over stdio with a real SDK client, lists the tools, compiles every advertised schema on a 2020-12-only validator, and round-trips a `git_status` call against a temporary repository so the client's `structuredContent` validation is exercised against the advertised `outputSchema`. - **Argument-injection test suite**: `tests/security/argument-injection.test.ts` covers all three defense layers — schema rejection, `validateGitArgs`, and argv ordering — against known payloads. `tests/mcp-server/tools/schemas/positional-fields.test.ts` is a fleet-wide pin: it enumerates every tool's input fields and requires each one that accepts a leading dash to be named in an explicit exception list, so a new string field cannot be added without classifying it. `tests/services/git/providers/cli/utils/allow-list-coverage.test.ts` scrapes every flag literal out of the CLI operations and asserts the allow-list accepts each one, catching the case where an operation emits a flag the validator would reject at runtime but mocked `execGit` unit tests never see. ## v2.15.1 - 2026-05-06 Closes [#47](https://github.com/cyanheads/git-mcp-server/issues/47): `git_remote.url` was emitted as `format: "uri"` in the JSON Schema, which OpenAI's tool validator rejects (`'uri' is not a valid format`). The provider already accepted SSH (`git@host:path`), `git://`, `file://`, and bare paths — only the schema was rejecting them, and only OpenAI clients surfaced it. Mirrors the same `.url()` → `.min(1)` change applied to `git_clone.url` in v2.15.0. Sweeps the remaining `format`-emitting Zod call (`git_commit.author.email`'s `.email()`) at the same time so a stricter client doesn't surface the next variant of this bug. Also pins `zod` to `~4.3.6` (patch-only) to keep JSON Schema emission stable across minor releases — the `format` keyword behavior has shifted between Zod 4 minors before, and this is exactly the kind of surface that breaks downstream validators when it drifts. ### Fixed - **`git_remote.url` rejected as invalid OpenAI schema**: Was `z.string().url()`, which serialized to `{ "type": "string", "format": "uri" }`. OpenAI's `tools[].parameters` validator only accepts a narrow set of `format` values; `uri` isn't one of them, so `gpt-5-codex` (and any other strict-validating client) refused the entire `git_remote` tool with `Invalid schema for function 'git_git_remote'`. Now `z.string().min(1)` with a description that names every accepted form. - **`git_commit.author.email` emitted `format: "email"` for cross-client portability**: Was `z.string().email()`, which serializes to `{ "type": "string", "format": "email" }`. OpenAI's documented allowlist (date-time, time, date, duration, email, hostname, ipv4, ipv6, uuid) does accept `email`, so this wasn't actively breaking on OpenAI — but other clients publish narrower lists and waiting for the next report is the wrong default. Now `z.string().min(1)` with a description that names the expected form. The corresponding schema test pivoted from "rejects invalid author email" to "rejects empty author email" so the assertion still matches the actual contract. ### Changed - **`zod` constrained to `~4.3.6`**: Patch-only range instead of caret. JSON Schema `format` emission has changed between Zod 4 minors before; pinning prevents a transitive Zod bump from re-introducing the kind of validator-rejected schema this release fixes. - **Dependency refresh**: `@cloudflare/workers-types`, `@hono/node-server`, `@opentelemetry/*` (auto-instrumentations-node, exporter-metrics-otlp-http, exporter-trace-otlp-http, instrumentation-pino, resources, sdk-metrics, sdk-node, sdk-trace-node), `@supabase/supabase-js`, `eslint`, `globals`, `hono`, `msw`, `typescript-eslint`. No code changes required. ### Internal - **Shell-injection regression tests for `spawnGitCommand`**: Stages a fake `git` shim on `PATH` that records argv to a sandbox file, then sends payloads containing `$(...)`, backticks, `;`, `&&`, and `|` as a `--branch` value. Each test asserts the marker file is never created (no shell evaluation occurred) and the payload appears in argv verbatim. Locks in the argv-based spawning contract — a future regression to `shell: true` would break every assertion. ## v2.15.0 - 2026-04-28 MCP surface tightening pass: every tool's Zod input schema is now `.strict()`, so unknown fields raise `ZodError` instead of being silently stripped — the same failure mode behind v2.14.1, where service-layer additions reached the executor but vanished at the MCP boundary because nobody noticed the schema hadn't been updated. While the surface was already breaking, also normalized the input names that drift between tools (`mode`/`branchName`/`paths`/`filePath`/`path`) so multi-mode tools speak the same language and `git_show` now actually populates its `metadata` field — previously always `{}` despite being part of the output schema. **Breaking**: Renamed inputs and outputs on `git_add`, `git_blame`, `git_branch`, and `git_clone`. Strict schemas reject unknown fields across every tool. `git_clone.url` no longer requires URL syntax (SSH, `file://`, and bare paths now work). `git_reflog.ref` and `git_reset.target` default to `'HEAD'` instead of being optional. ### Added - **`git_show.metadata` is populated for commit objects**: A third parallel query (`git log -1 --format=`) runs alongside the existing `cat-file -t` and `show` calls via `Promise.allSettled`. Parses `%H`, `%h`, author/committer name+email+date (ISO 8601), parents, subject, and body into the metadata object. Best-effort: failures or non-commit objects (blob/tree/tag) leave `metadata` as `{}` rather than failing the whole operation. Closes the schema-vs-implementation gap that has been there since the field was first added. - **`git_cherry_pick.message` and `git_rebase.message` output fields (optional)**: Human-readable next-step guidance set only when the operation paused on conflicts (e.g. `Rebase paused with conflicts in 3 file(s). Resolve them, then run git_rebase with mode='continue' (or mode='abort' to cancel, mode='skip' to drop the current commit).`). LLM callers shouldn't have to reverse-engineer the recovery path from `conflicts: true`. - **Strict-mode rejection tests**: Added explicit "passing the old name fails" assertions on `git_add`, `git_blame`, `git_branch`, `git_clone` so future schema renames don't silently regress to permissive behavior. ### Changed - **All tool input schemas now use `.strict()`**: Unknown fields raise a Zod validation error instead of being silently dropped. Catches the v2.14.1 regression class at validation time. Affects every tool — callers passing extra keys will now get a clear error pointing at the unrecognized field. - **`git_add.files` → `git_add.paths`**: The argument accepts both file and directory paths; `paths` is more accurate and matches the service layer's `paths` field. - **`git_blame.file` → `git_blame.filePath`** (input and output): Matches `git_log.filePath` and `git_show.filePath`. Bare `file` was the only outlier. - **`git_branch` input/output renames**: `operation` → `mode`, `name` → `branchName`, `newName` → `newBranchName` on the input; `operation` → `mode` on the output. Aligns with every other multi-mode tool (`git_remote`, `git_stash`, `git_tag`, `git_worktree`, `git_rebase`, `git_reset`). - **`git_clone.localPath` → `git_clone.path`** (input and output): Matches every other tool's destination/working-tree input. Output `localPath` field renamed in lockstep. - **`git_clone.url` accepts non-URL sources**: Was `z.string().url()`, which rejected SSH (`git@host:path`), `git://`, `file://`, and bare filesystem paths — all valid clone sources. Now `z.string().min(1)` with a description that names every accepted form. The provider already handled them; only the schema was rejecting. - **`git_reflog.ref` defaults to `'HEAD'`**: Was optional with `undefined` meaning HEAD. The provider treated absent and `'HEAD'` identically, so the default makes the contract explicit and the executor receives a string in every case. - **`git_reset.target` defaults to `'HEAD'`**: Same rationale — was optional, now defaults to the value the executor was using anyway. - **`git_worktree.branch` and `commitish` descriptions**: Now explicitly call out the create-vs-checkout distinction. `branch` creates a NEW branch and fails if it already exists; `commitish` checks out an existing branch/commit/tag without creating anything. Passing an existing branch name to `branch` previously returned a confusing raw git error. ### Removed - **Unused exports from `src/mcp-server/tools/schemas/common.ts`**: `ConfirmSchema`, `AuthorSchema`, `SuccessResponseSchema`, `FilePathSchema`, `VerboseSchema`, `QuietSchema`, `RecursiveSchema`. None were imported anywhere — dead code from earlier iterations. Schemas that are still in use (`PathSchema`, `BranchNameSchema`, `CommitRefSchema`, `RemoteNameSchema`, `TagNameSchema`, `LimitSchema`, `SkipSchema`, `AllSchema`, `ForceSchema`, `DepthSchema`, `DryRunSchema`, `NoVerifySchema`, `MergeStrategySchema`, `PruneSchema`, `CommitMessageSchema`) are unchanged. ### Internal - **Test coverage — `git_show` metadata**: Added three service-layer tests covering metadata parsing for commit objects, the empty-metadata fallback for non-commit object types, and the empty-metadata fallback when the third (log) call rejects. - **Test coverage — schema strictness**: One "rejects unknown fields (strict)" test per renamed tool, paired with renamed-field acceptance tests so the contract change is visible in the suite. ## v2.14.2 - 2026-04-23 Closes [#46](https://github.com/cyanheads/git-mcp-server/issues/46): `git_tag` gains a `verify` mode so callers can confirm a tag signature without falling back to a raw `git tag -v` shell call. Runs `git tag -v ` at the service layer with `allowNonZeroExit` and parses the stderr into a structured result that distinguishes the five real outcomes — valid signature, unsigned tag, missing local trust configuration (e.g. `gpg.ssh.allowedSignersFile`), bad signature, and tag-not-found. Only the last throws; the other four return `verified: false` with a `warning` explaining why, so verification drift never disappears into an exception. ### Added - **`git_tag.mode: 'verify'` — new operation**: Accepts `tagName` (required) and returns `verified`, `signatureType` (`'gpg' | 'ssh' | 'x509'`), `signerIdentity`, `signerKey`, `warning`, `rawOutput`, and echoes the input as `verifiedTag`. Parsed patterns: `gpg: Good signature from "..."` and SSH `Good "git" signature for X with TYPE key SHA256:...` for success; `gpg: BAD signature from "..."`, `error: no signature found`, `gpg.ssh.allowedSignersFile needs to be configured`, and `error: tag '...' not found` for the four failure branches. Unparseable-but-exit-0 output is still trusted as verified, so future git output variants don't silently regress to `verified: false`. - **`GitTagResult` verify fields (service layer)**: `verifiedTag`, `verified`, `signatureType`, `signerIdentity`, `signerKey`, `warning`, `rawOutput`. Absent on list/create/delete results. - **Service-layer executor signature extended**: `executeTag`'s `execGit` parameter now accepts an optional `{ allowNonZeroExit?: boolean }` and returns an optional `exitCode`, mirroring the pattern already used by `executeMerge` and `executeCherryPick`. Required for the verify branch to distinguish "tag not found" (throws) from "verification failed but output was captured" (returns `verified: false`). ### Changed - **`git_tag` description and schema**: Tool description now names all four modes. `tagName` description updated to note create/delete/verify all require it. `readOnlyHint` stays `false` because create/delete remain on the tool — MCP annotations are tool-scoped, not per-mode. - **`git_tag` response formatter verbosity**: Default (standard) output now drops `rawOutput` — it's verbose stderr intended for full-verbosity inspection only. `verified` and `warning` always surface at every verbosity level alongside `signed` and `signingWarning`, because verify outcomes are load-bearing. ### Internal - **Test coverage — service layer**: Added nine verify-mode tests in `tag.test.ts` covering all five issue-mandated cases (valid GPG, valid SSH, unsigned, missing SSH trust config, bad signature, tag-not-found) plus executor argument shape, missing `tagName`, and the exit-0 fallback path. - **Test coverage — tool layer**: Added input-schema acceptance, verify-requires-tagName rejection, provider pass-through (mode + tagName), warning surfacing, and `rawOutput` stripping at standard verbosity in `git-tag.tool.test.ts`. ## v2.14.1 - 2026-04-23 Follow-up to v2.14.0: the service layer for `git_tag` grew `limit` (list mode) and split the annotation `message` / `annotationBody` fields, but the tool-layer Zod schema was never extended to match. Zod silently stripped `limit` from inputs and the `annotationBody` field never surfaced on responses — the documented v2.14.0 features only reached the CLI executor, not callers. Realigned the tool schema with the service contract. ### Fixed - **`git_tag.limit` input surfaced to callers**: Added `LimitSchema`-backed `limit` to the tool's `InputSchema` (list mode) and forwarded it through to the provider call. Without this wire-up, `--count=N` was unreachable from the MCP boundary despite the provider accepting it. - **`git_tag` list response includes `annotationBody`**: Added the optional `annotationBody` field to `TagInfoSchema` and refined the `message` description to clarify it carries only the subject line. The provider was already populating `GitTagInfo.annotationBody` via `GIT_RECORD_DELIMITER` parsing; the tool's output schema was dropping it on the way out. ### Internal - **Test coverage**: Added two tool-layer tests in `git-tag.tool.test.ts` — one asserting `limit` pass-through to `provider.tag(...)`, one asserting `annotationBody` surfaces on list results. Closes the tool-layer gap left by v2.14.0, which only covered the new parse paths at the service layer. ## v2.14.0 - 2026-04-23 Session-orientation pass: tools that set up or wrap up a session now return a consistent, best-effort "repository snapshot" (status with upstream tracking, recent commits, recent tags, optional remotes) so callers have the context they need on the first response instead of round-tripping through `git_status`, `git_log`, and `git_tag` separately. Extracted the gathering logic into a shared `gatherRepoSnapshot` helper so the shape stays identical across `git_set_working_dir` and `git_wrapup_instructions`. Added a `limit` input to every list-style tool (`git_branch`, `git_tag`, `git_stash`, plus `maxTags` on `git_changelog_analyze`) so large catalogs don't bloat responses. **Breaking**: `git_set_working_dir` dropped the `includeMetadata` input (snapshot is always included) and renamed `repositoryContext` → `repository` with a reshaped status block (full path arrays instead of per-type counts). `git_wrapup_instructions` renamed `gitStatus` → `repository.status` and replaced the single `gitStatusError` string with a `enrichmentWarnings` array. The service-level `GitCommitInfo.author/authorEmail/timestamp/parents` fields became optional (omitted in oneline mode, where only `%H|%h|%s` is fetched). ### Added - **`gatherRepoSnapshot` shared utility** (`src/mcp-server/tools/utils/repo-snapshot.ts`): Best-effort gatherer that runs `status`/`log`/`tag` (and optionally `remote`) in parallel via `Promise.allSettled`, collapses "not a git repository" errors from every branch into a single actionable hint, and surfaces per-operation failures as `warnings` entries rather than bubbling up. Exports `RepoSnapshot*Schema` so tool output schemas stay in lockstep with the produced shape. - **`git_status.upstream` / `ahead` / `behind` output fields**: Parsed from `git status --porcelain=v2 --branch` headers (`# branch.upstream`, `# branch.ab`). Present only when the current branch is tracking an upstream — callers can decide whether to push, pull, or rebase without a second round-trip. - **`git_branch.operation: 'show-current'` — dedicated fast path**: One `git symbolic-ref --quiet --short HEAD` call instead of loading every ref under `refs/heads`. Returns `null` for detached HEAD via the command's exit-code-1 signal. - **`git_branch.limit` input (list mode)**: Caps results at the git command via `--count=N` on `for-each-ref`. Applied at the source, not post-hoc in JS. - **`git_tag.limit` input (list mode)**: Same mechanism — `--count=N` on `for-each-ref refs/tags`. Paired with a stricter sort: `--sort=-version:refname --sort=-creatordate` (last key is primary, so creator date leads and version-aware refname is the tiebreaker when timestamps tie in the same second). - **`git_tag` annotation body split**: `GitTagInfo.annotationBody` (optional string) carries the body separately from `message` (now explicitly the subject/first line). Uses `GIT_RECORD_DELIMITER` as the record terminator so multi-line bodies round-trip without breaking the `\n`-based line split. - **`git_stash.limit` input (list mode)**: `git stash list` wraps `git log` on the stash ref, so `-nN` caps entries at the source. - **`git_changelog_analyze.maxTags` input (default 100)**: Caps the tag fetch at the git command. Large tag catalogs no longer bloat the response. - **`git_log.note` output field**: Set only when filters returned zero commits. Echoes the applied criteria (`author=`, `grep=`, `since=`, `until=`, `filePath=`, `branch=`) and suggests broadening so callers can self-correct without inspecting the request. ### Changed - **`git_set_working_dir` — always returns a repository snapshot**: Dropped the `includeMetadata` toggle. Every call now returns `repository` (status, recentCommits, recentTags, remotes) via `gatherRepoSnapshot` with `commitLimit: 2, tagLimit: 2, includeRemotes: true`. The snapshot is omitted only when the path isn't a git repository — in which case `enrichmentWarnings` explains why and points to `git_init` or `initializeIfNotPresent`. - **`git_wrapup_instructions` — returns the same repository shape**: Renamed `gitStatus` → `repository.status` with the richer schema (full staged/unstaged path arrays + upstream tracking). The single `gitStatusError` string became an `enrichmentWarnings` array, so per-operation failures are listed individually. No session working directory set is now a warning (`Call git_set_working_dir first...`) rather than a protocol-breaking error. - **`git_log.oneline` — fetches less data at the source**: Oneline mode now requests only `%H|%h|%s` from `git log --format` instead of the full eight-field format and discarding most fields in JS. Non-oneline mode is unchanged. - **`git_show` — parallelized `cat-file -t` and `show`**: Object type detection and content fetch are independent queries against the same object; they now run concurrently via `Promise.all` instead of sequentially. - **`git_tag` list sort order**: Dual-sort (`-version:refname`, `-creatordate`) fixes the edge case where tags created in the same second (common in CI) fell back to lexical ordering so `v0.10.0` ranked below `v0.7.0`. Primary key is still creator date; version-aware refname is only the tiebreaker. - **`GitCommitInfo` — optional fields for oneline mode**: `author`, `authorEmail`, `timestamp`, and `parents` became optional at the service level. Present in the full format; omitted when the caller requested `oneline` (the git command didn't fetch them). - **`GitBranchResult` — new `'show-current'` variant**: Discriminated union gained `{ mode: 'show-current'; current: string | null }`. Existing `list`/`create`/`delete`/`rename` variants unchanged. ### Removed - **`git_set_working_dir.includeMetadata` input parameter**: Snapshot gathering is cheap (parallel, graceful degradation) and callers almost always wanted the context — the toggle added friction without real payoff. Callers passing `includeMetadata` will have the key stripped by Zod. - **`git_set_working_dir.repositoryContext.status.{stagedCount, unstagedCount, untrackedCount, conflictsCount}`**: Replaced by full path arrays on the new `repository.status` shape (same data as `git_status`). Counts were trivially derivable from the arrays and callers consistently wanted the paths anyway. - **`git_set_working_dir.repositoryContext.branches.{totalLocal, totalRemote}`**: Branch counts required two extra `git branch --list` calls per snapshot. The snapshot now carries upstream tracking on `status` instead — which is what callers actually needed for "am I ahead/behind main". ### Fixed - **`README.md` — stale `git_wrapup` prompt params**: The Prompts table still listed `skipDocumentation` and `updateAgentFiles`, removed in v2.12.1. Updated to the current `changelogPath`, `createTag`. ### Internal - **Test coverage**: Added dedicated test suites for the new `gatherRepoSnapshot` utility (`tests/mcp-server/tools/utils/repo-snapshot.test.ts`) and per-operation CLI tests for `status`, `branch`, `log`, `stash`, and `tag` covering the new parse paths, `limit` pass-through, and annotation-body round-tripping. Tool-layer tests updated to the reshaped output (`repository` vs `repositoryContext`, `enrichmentWarnings` vs `gitStatusError`, `show-current` mode). ## v2.13.0 - 2026-04-23 Uniform GPG/SSH signing policy: `GIT_SIGN_COMMITS` now defaults to `true` and is the single switch for all signing operations. When enabled, the server attempts to sign and silently falls back to unsigned on failure, surfacing the actual outcome via new `signed` and `signingWarning` fields on tool responses. Per-call `sign` and `forceUnsignedOnFailure` parameters are gone — the tri-state added cognitive load without real utility, and LLM callers were overriding server config with explicit `sign: false` despite v2.11.1's schema clarification. **Breaking**: `git_commit` and `git_tag` no longer accept `sign` or `forceUnsignedOnFailure` inputs. Callers setting either will have those keys stripped by Zod; server-side policy applies uniformly. ### Changed - **`GIT_SIGN_COMMITS` default flipped to `true`**: Matches the common case where users want verified commits by default. Set `GIT_SIGN_COMMITS=false` to opt out in environments without a signing key. The setting governs commits, tags, merges, rebases, and cherry-picks uniformly. - **Signing policy — attempt then silently fall back**: When `GIT_SIGN_COMMITS=true`, `git_commit` and `git_tag` attempt to sign and retry unsigned on failure without raising an error. A `logger.warning` is emitted for server-side observability, and the tool response carries a factual `signingWarning` message so orchestrating agents can inform the user if appropriate. `git_merge`, `git_rebase`, `git_cherry_pick`, and `git_pull` read the same setting (no fallback there — signing-failure behavior during those operations is git's responsibility). - **`git_tag.annotated` description**: Now notes the flag is only effective when no message is provided and signing is disabled — otherwise the tag is always annotated. Previous wording referenced the removed `sign` input. ### Added - **`git_commit.signed` output field (required boolean)**: Reflects whether the commit was actually signed — `true` only when signing was attempted and succeeded, `false` when signing was not requested or fell back to unsigned on failure. Surfaced at every verbosity level including `minimal`, since signing drift is load-bearing for downstream verification workflows. - **`git_tag.signed` output field (optional boolean, create mode only)**: Same semantics as the commit field; absent for `list` and `delete` modes. - **`git_commit.signingWarning` / `git_tag.signingWarning` (optional string)**: Populated only when `GIT_SIGN_COMMITS=true` was in effect but signing failed and the operation fell back to unsigned. Factual, not prescriptive — names the env var, the failure, and the underlying error string (e.g., `gpg-agent not running`). ### Removed - **`git_commit.sign` and `git_tag.sign` input parameters**: The tri-state `boolean | undefined` override is gone. Server config is now the only lever. - **`git_commit.forceUnsignedOnFailure` and `git_tag.forceUnsignedOnFailure` input parameters**: Fallback-on-failure is now uniform behavior whenever signing is requested. - **`SignSchema` shared Zod schema**: Unused after the tool input removals; dropped from `src/mcp-server/tools/schemas/common.ts`. - **Dead `sign?` fields in service-layer option types**: `GitMergeOptions`, `GitRebaseOptions`, and `GitCherryPickOptions` carried a `sign?: boolean` that was never wired to any tool input — only `shouldSignCommits()` was actually consulted. Removed to keep the types honest. ### Fixed - **`git_pull` now honors `GIT_SIGN_COMMITS`** ([#44](https://github.com/cyanheads/git-mcp-server/issues/44)): `pull.ts` wasn't consulting `shouldSignCommits()` and didn't forward `-S` to the underlying merge/rebase, so pulls producing merge commits (divergent histories) or rebased commits (`rebase: true`) stayed unsigned even with `GIT_SIGN_COMMITS=true` — the one gap in uniform signing. Fixed by mirroring the `merge.ts` / `rebase.ts` / `cherry-pick.ts` pattern: push `-S` when the config is enabled. Fast-forward pulls are unaffected (no commit is created). No tool input or option-type change — server config is the single switch. - **`z.coerce.boolean()` footgun for `GIT_SIGN_COMMITS`**: `z.coerce.boolean()` treats the literal string `"false"` as truthy (non-empty string coercion), so `GIT_SIGN_COMMITS=false` would silently fail to opt out under the old schema. Replaced with a `parseBoolEnv(defaultValue)` preprocess helper in `src/config/index.ts` that handles `true/false/1/0/yes/no/on/off/` case-insensitively and returns the default when the value is malformed or missing. ### Internal - **`shouldSignCommits()` JSDoc rewrite**: Reflects the single-switch / silent-fallback model and surfaces the observability fields. - **`.env.example` and README updates**: Flipped the documented default to `true` and added the `signed`/`signingWarning` fallback note to the env table row and the Commit signing capability description. - **Service-layer signing tests rewritten**: `commit.test.ts` and `tag.test.ts` now mock `shouldSignCommits` as a `vi.fn()` and flip it per-case via a direct cast. Describe blocks renamed from `signing option` / `forceUnsignedOnFailure option` to `signing policy`, with test titles describing the observable outcome rather than the removed input. - **Tool-layer signing tests updated**: `git-commit.tool.test.ts` fixtures now include `signed` on `GitCommitResult` mocks; `git-tag.tool.test.ts` replaces the old `sign`/`forceUnsignedOnFailure` suite with pass-through assertions for `signed` and `signingWarning`. - **Pull signing tests added**: `pull.test.ts` now covers the `-S` pass-through for the merge path (default), explicit opt-out (default `shouldSignCommits = false`), and the rebase path (`rebase: true` with signing enabled). All 1,307 tests pass. ## v2.12.1 - 2026-04-23 Follow-up to v2.12.0: the `git_wrapup` prompt was still emitting the pre-rewrite phased procedural script and telling callers to pass `updateAgentMetaFiles: "yes"` — an input the tool no longer accepts. Realigned the prompt with the acceptance-criteria protocol it's meant to orchestrate. ### Changed - **`git_wrapup` prompt — acceptance-criteria orchestration**: Rewrote the prompt body as a thin session-flow wrapper around `git_wrapup_instructions` rather than an inline phased script. It now instructs the agent to load the protocol, set the working directory, analyze the diff, satisfy each acceptance checkbox per project convention, commit atomically, and (optionally) tag. The text no longer prescribes changelog categories or commit structure — those defer to each project's existing conventions, consistent with the tool's goals-strict/mechanism-generic philosophy. - **`git_wrapup.createTag` default flipped to `'true'`**: To match the tool's "every wrap-up is a release" stance. Set to `'false'` when tagging is deferred to a separate release step — the prompt then passes `createTag: false` through to the tool call. ### Removed - **`git_wrapup.skipDocumentation` input parameter**: Documentation currency is now a standing acceptance criterion in the protocol, not a gated section. Callers previously passing this key will have it stripped by Zod with no behavior change in the emitted prompt. - **`git_wrapup.updateAgentFiles` input parameter**: Agent-instruction file updates are standing guidance in the protocol now. The prompt also no longer tells the agent to pass the removed `updateAgentMetaFiles` input to the tool. ### Internal - **Test coverage**: Rewrote `git-wrapup.prompt.test.ts` to assert the new session-flow structure (Load Protocol, Satisfy the Acceptance Criteria, etc.), the flipped `createTag` default, the removed inputs, and the pass-through of `createTag: false` to the tool call. All 17 prompt tests pass. - **`@hono/node-server` 2.0 verification**: Confirmed the v2.12.0 upgrade is clean against our usage. The two v2 breaking changes (dropped Node 18, removed Vercel adapter) don't apply — our `engines.node` is `>=20.0.0` and we don't import the Vercel adapter. Public `serve`/`ServerType`/`HttpBindings` API is unchanged; headline is a ~2.3x body-parsing throughput improvement from the new fast path. ## v2.12.0 - 2026-04-23 Reframed the `git_wrapup_instructions` protocol as an acceptance-criteria checklist (goals-strict, mechanism-generic) so it travels cleanly across projects with different release conventions. Internal type-safety pass removed unnecessary casts across handlers and utilities, and a `skills/` directory now ships agent skill sources alongside the server. ### Changed - **`git_wrapup_instructions` — acceptance-criteria protocol**: The default wrap-up output is now a fixed acceptance-criteria checklist with generic guidance beneath it, rather than a phased procedural script. The checklist is strict on outcomes (version bump, changelog, docs, verification, atomic Conventional Commits, annotated tag) and generic on mechanism, deferring to each project's own conventions for where versions live, how changelogs are formatted, and what the verification suite looks like. Custom instructions loaded from `GIT_WRAPUP_INSTRUCTIONS_PATH` still override the default entirely. - **`git_wrapup_instructions.createTag` — inclusion toggle**: Now controls whether the tag criterion appears in the emitted protocol. Omit or set `true` to include the tag step; set `false` to omit it entirely (e.g., when tagging is deferred to a separate release step). Previously appended a procedural step post-hoc. ### Removed - **`git_wrapup_instructions.updateAgentMetaFiles` input parameter**: The old "append agent-meta-files instruction" toggle is gone. Agent-instruction file updates (`AGENTS.md`, `CLAUDE.md`, etc.) are now a standing element of the protocol's "Commonly relevant files" guidance — surfaced for every wrap-up instead of gated behind a flag. Callers previously passing `updateAgentMetaFiles` will simply have the key stripped by Zod; no type error, but no append behavior either. ### Added - **`skills/` directory**: Project-level Agent Skills (`field-test`, `maintenance`, `polish-docs-meta`, `release-and-publish`, `report-issue`) now live at the repo root as the source of truth for agent working copies (`.claude/skills/`, `.codex/skills/`, etc.). See `skills/README.md` for the sync pattern. ### Internal - **Type-safety cleanup across handlers and utilities**: Removed unnecessary casts (`as unknown`, `as TParams`, `as Record`, `as MetricOptions`, `as Promise<...>`) in `prompt-registration.ts`, `resourceHandlerFactory.ts`, `toolHandlerFactory.ts`, `errorHandler.ts`, `performance.ts`, `requestContext.ts`, and `metrics/registry.ts`. Behaviour unchanged; the compiler now infers each type directly. - **`@hono/node-server` 1.19 → 2.0**: Major version upgrade of the HTTP runtime adapter. Other bumps: `@cloudflare/workers-types`, `@supabase/supabase-js`, `@types/bun`, `bun-types`, `@vitest/coverage-v8`, `vitest`, `typescript-eslint`, `vite`, `msw`. - **Test coverage**: `git_wrapup_instructions` tests now assert the new acceptance-criteria structure (Outcome/Philosophy/Orient/Acceptance criteria/Constraints sections, every checkbox, tag inclusion toggle). - **`docs/tree.md`**: Regenerated to include the new `skills/` directory. ## v2.11.1 - 2026-04-20 Schema-level clarification so LLM callers stop overriding the server's default signing configuration unnecessarily. ### Changed - **`SignSchema` description**: The shared `sign` parameter on `git_commit` and `git_tag` now documents its tri-state semantics — omit to use the server's `GIT_SIGN_COMMITS` default, set `true` to force signing, set `false` to skip. Previously the description read only `"Sign the commit/tag with GPG."`, which led LLMs to send explicit `sign: false` and silently override a server configured with `GIT_SIGN_COMMITS=true`. No runtime behavior change — the service-layer `options.sign ?? shouldSignCommits()` fallback was already correct. ## v2.11.0 - 2026-04-19 Surfaced through `/field-test` against the running server: integration operations were throwing on conflicts (a documented success state), and several tools were leaking raw porcelain into LLM-facing output or omitting fields the LLM needed to act without re-querying. ### Added - **`allowNonZeroExit` executor option**: `executeGitCommand` and the underlying `spawnGitCommand` (Bun + Node paths) now accept `{ allowNonZeroExit: true }` and return the `exitCode` so operations can handle git's expected non-zero exits structurally instead of as errors. `CliGitProvider` threads this through every operation closure. - **`GitPullResult.conflictedFiles`**: `git_pull` now returns the list of conflicted file paths alongside the existing `conflicts` flag — included in `minimal` verbosity when `conflicts: true` so the LLM can act without a follow-up `git_status`. - **`GitResetResult.previousCommit`**: `git_reset` now reports the pre-reset HEAD when HEAD moved, and `filesReset` now reflects what actually changed (paths unstaged, files differing across the HEAD move, or working-tree changes discarded by `--hard`). ### Changed - **`git_merge`, `git_rebase`, `git_cherry_pick`, `git_pull` — conflicts are structured success, not errors**: Previously, a non-zero exit from a `CONFLICT` was thrown as an `McpError`, forcing callers to parse error messages and re-run `git_status` to recover state. These operations now return `{ success: true, conflicts: true, conflictedFiles: [...] }` with an actionable message, and only throw when the non-zero exit is a real failure (no `CONFLICT` marker present). Continuation modes (`--continue`) follow the same pattern. - **`git_init` standard verbosity**: `isBare` is now included at `standard` verbosity (was `full`-only). Bare repos reject `git_add`/`git_commit` — the LLM needs this signal without escalating verbosity. - **`git_show` standard verbosity**: `metadata` is now included at `standard` verbosity (was `full`-only). Tag/blob/tree objects carry tagger, mode, size, and entry data here that's load-bearing for inspection workflows. ### Fixed - **`git_status` — porcelain v2 unmerged path index**: The unmerged-entry parser was reading `parts[8]` as the file path, but the porcelain v2 `u` format places the path at index 10 (after `XY sub m1 m2 m3 mW h1 h2 h3 path`). `conflictedFiles` was leaking blob hashes instead of file paths. Fixed to `parts.slice(10).join(' ')`. - **`git_checkout` — porcelain prefix in `filesModified`**: Output was returning literal `"M\tREADME.md"` strings instead of bare paths. The parser now matches `/^([A-Z])\t(.+)$/` and emits the path only. Expanded the informational-line skip list to cover `Switched`, `Already`, `Your branch`, `(use `, `HEAD is now`, `Note:`, `Updated`. - **`git_pull` — `filesChanged` leaking diffstat formatting**: Previously emitted raw stat lines. Now extracts bare paths from diffstat lines (`/^\s(.+?)\s*\|\s*(?:\d+\s*[+-]*|Bin\s)/`), including binary-file entries. - **`git_reset` — incomplete `filesReset`**: The previous implementation returned `input.paths ?? []`, so commit-move resets reported nothing. Now captures HEAD before/after, computes `git diff --name-only OLD..NEW` when HEAD moved, lists working-tree dirty files for `--hard`, and combines all three sources. ### Internal - **Test coverage**: Updated the `ExecGitFn` mock signature across all operation tests to match the new executor type (`(args, cwd, ctx, options?) => Promise<{stdout, stderr, exitCode?}>`). Added cases for conflict-as-success on merge/rebase/cherry-pick/pull, porcelain v2 unmerged parsing, checkout filesModified parsing, and the rewritten reset semantics. All 1,303 tests pass. ## v2.10.6 - 2026-04-19 ### Fixed - **`GIT_BASE_DIR` path resolution ([#43](https://github.com/cyanheads/git-mcp-server/issues/43))**: When `GIT_BASE_DIR` was set, absolute paths passed to tools were sanitized into relative paths and used as the spawn `cwd`, making behavior dependent on the MCP process's own `cwd`. `resolveWorkingDirectory` now re-anchors sanitized relative paths back to `GIT_BASE_DIR` so git always receives an absolute working directory. - **Misleading ENOENT error**: A non-existent or non-directory `cwd` previously surfaced as `"Git command not found. Please ensure Git is installed and in your PATH."` — indistinguishable from a real missing-git error. `executeGitCommand` now pre-flights the cwd with `existsSync`/`statSync` and throws a clear `"Working directory does not exist"` / `"is not a directory"` error instead. - **`git_tag` tool descriptions**: `force` now correctly notes it only applies to create mode (git has no force-delete for tags); `message` makes the annotated-tag implication explicit; `annotated` no longer claims auto-coercion that never happened in the tool layer. ### Changed - **Dependency updates**: Bumped 28 dev dependencies to latest, including `@modelcontextprotocol/sdk` 1.27.1 → 1.29.0, TypeScript 6.0.2 → 6.0.3, Hono 4.12.9 → 4.12.14, Vite 8.0.2 → 8.0.8, msw 2.12.14 → 2.13.4, eslint 10.1.0 → 10.2.1, and the OpenTelemetry suite 2.6.0/0.213.0 → 2.7.0/0.215.0. - **Removed all `resolutions` pins** and converted pinned direct dependencies to caret ranges so `bun update` can keep them current. - **Tag signing config documented**: `shouldSignCommits()` now explicitly notes it governs both commits and tags; per-call overrides remain available via each tool's `sign` parameter. ### Internal - **Deduplicated `loadConfig`**: Single source of truth in `config-helper.ts`; `command-builder.ts` imports instead of redefining. - **Cleanup in `git-tag.tool.ts`**: Removed dead `if (input.x !== undefined)` guards on fields with Zod defaults (always defined post-parse). - **Coverage**: Added unit tests for `executeGitCommand`'s new cwd pre-flight. ## v2.10.5 - 2026-03-25 ### Fixed - **`git_add` tool**: Derived staged file list from post-add status when provider returns empty array (happens with `all`/`update` flags) - **`git_branch` tool**: Coerced string `"true"`/`"false"` to booleans for `merged`/`noMerged` params (LLM clients sometimes send strings); stopped emitting `--merged=HEAD` when `merged` is explicitly `false` - **`git_clean` tool**: Allowed `force=false` when `dryRun=true` so users can preview without the force requirement - **`git_show` tool**: Removed invalid `json` format option (not a real git format); only `raw` is supported - **`git_status` tool**: Clarified `isClean` description to explain behavior with `includeUntracked=false` - **`git checkout` operation**: Filtered additional git informational messages (`Your branch`, `HEAD is now`, `(use `) from `filesModified` output - **`git rebase` operation**: Fixed commit count parsing for modern git merge backend (`Rebasing (N/M)` progress in stderr) with fallback to legacy `Applying:` lines - **`git diff` operation**: Fixed untracked file stat counting — parsed per-file stats individually instead of batching (which caused `parseGitDiffStat` to overwrite with the last summary line) - **`git init` operation**: Created target directory before spawning `git init`; ran git in the target path instead of the context working directory - **`git pull` operation**: Filtered git informational messages (`From`, `Updating`, `Fast-forward`, `Already up to date`, summary lines) from `filesChanged` output - **`git stash` operation**: Parsed `stash@{N}` format correctly to extract stash index (was attempting `parseInt` on the full ref string) - **`git tag` operation**: Added `-c tag.gpgSign=false` config override when not signing to prevent git config from forcing signing/editor in non-interactive context; fixed tagger email format (removed redundant angle brackets since `%(taggeremail)` already includes them) ### Added - Test coverage for all fixed behaviors across tool and service layers ## v2.10.4 - 2026-03-24 ### Changed - **TypeScript 6.0**: Upgraded from TypeScript 5.9.3 to 6.0.2; updated `tsconfig.json` path mappings to use `./` prefix (replaces `baseUrl`) - **Dependencies**: Bumped Hono 4.12.5→4.12.9, Vite 7.3.1→8.0.2, Rollup 4.59.0→4.60.0, ESLint 10.0.3→10.1.0, Vitest 4.0.18→4.1.1, and other dev dependencies to latest ### Added - **`flatted` dependency**: Added `flatted` 3.4.2 ## v2.10.3 - 2026-03-09 ### Fixed - **Tool error responses**: Removed invalid `structuredContent` from error results in `createMcpToolHandler` — structured content is only valid on successful responses ([#40](https://github.com/cyanheads/git-mcp-server/issues/40)) ## v2.10.2 - 2026-03-08 ### Changed - **`git_tag` tool**: Improved `message` parameter description to encourage meaningful release notes on annotated tags ## v2.10.1 - 2026-03-08 ### Added - **`git_diff` auto-exclude**: Lock files and generated files (16 patterns across ecosystems) are now excluded from diff output by default, reducing context bloat for LLMs. New `autoExclude` input parameter (default: `true`) and `excludedFiles` output field showing which files were filtered ### Fixed - **`git_diff` untracked file stats**: Untracked file insertions and deletions are now included in diff stat totals - **Config**: Removed runtime `hasFileSystemAccess` check that defaulted `LOGS_DIR` to `logs/`; file logging is now disabled unless `LOGS_DIR` is explicitly set ([#38](https://github.com/cyanheads/git-mcp-server/issues/38)) ### Changed - **Dependencies**: Bumped `@cloudflare/workers-types` to `4.20260307.1`, `eslint` to `10.0.3` ## v2.10.0 - 2026-03-06 ### Removed - **LLM service**: Removed `src/services/llm/` (OpenRouter provider, interfaces, types) — unused by git MCP tools - **Speech service**: Removed `src/services/speech/` (ElevenLabs TTS, OpenAI Whisper STT, SpeechService orchestrator) — unused by git MCP tools - **Parsing utilities**: Removed `src/utils/parsing/` (CSV, date, JSON, PDF, XML, YAML parsers) — unused by git MCP tools - **Network utilities**: Removed `src/utils/network/fetchWithTimeout` — unused by git MCP tools - **Scheduling utilities**: Removed `src/utils/scheduling/` (cron scheduler) — unused by git MCP tools - **HTML sanitization**: Removed `sanitizeHtml`, `sanitizeString`, and related types from `Sanitization` class — unused; git operations only need path and input sanitization - **DI tokens**: Removed `LlmProvider` and `SpeechService` container tokens and registrations - **Config fields**: Removed `openrouter*`, `llmDefault*`, and `speech.*` configuration schema and parsing - **17 dependencies**: Removed `ajv`, `ajv-formats`, `axios`, `chrono-node`, `clipboardy`, `fast-xml-parser`, `js-yaml`, `node-cron`, `openai`, `papaparse`, `partial-json`, `pdf-lib`, `sanitize-html`, and associated `@types/*` packages ### Changed - **`.gitignore`**: Added `.vscode/` to ignored directories ## v2.9.2 - 2026-03-06 ### Fixed - **`git_add` tool**: Made `files` optional when `all` or `update` is true; added Zod refinement validation to enforce at least one staging method - **`git_remote` tool**: Corrected auth scope from `tool:git:write` to `tool:git:read` since remote operations include read-only actions (list, show, get-url) - **`git_reset` tool**: Updated confirmation description to cover `merge` and `keep` reset modes alongside `hard` - **`git_branch` tool**: Removed redundant type assertion on operation mode - **`git merge` diffstat parsing**: Handle binary file entries (`Bin 0 -> 1234 bytes`) in addition to numeric diffstat lines - **`git rebase` argument ordering**: Positional arguments (upstream, branch) now placed after flags (`--interactive`, `--gpg-sign`, etc.) - **`git clone` result accuracy**: Returns the resolved local path instead of raw input, detects actual checked-out branch name, and parallelizes post-clone metadata queries - **`git blame` open-end range**: Supports `-L,` when only `startLine` is provided (shows from start to end of file) - **`git fetch` ref regex**: Fixed pattern to handle force-update prefixes (`+`) and triple-dot notation (`...`) - **`git push` delete validation**: Requires a branch or remote branch name for `--delete` operations instead of silently producing invalid commands - **`git stash` list timestamps**: Uses `--format=%gd\t%ct\t%gs` for structured output with real unix timestamps instead of hardcoded `0` - **`git show` file viewing**: Added `filePath` support via `commit:path` syntax to show specific file contents at a given revision - **Branch output parser**: Fixed misleading comment on line trimming logic ## v2.9.1 - 2026-03-06 ### Fixed - **Argument ordering**: Flags now precede positional arguments (commits, branches, paths, objects) in `cherry-pick`, `merge`, `show`, and `worktree remove`, matching git CLI conventions and preventing misinterpretation - **`git_merge` abort**: Added `--abort` support to cancel in-progress merges; abort path no longer passes the branch name to git - **`git_rebase` continue**: Removed unnecessary `--no-edit` fallback that added complexity for no benefit; `rebasedCommits` returns `0` on continue since the actual count is unknown - **`git_blame` line numbers**: Uses git's reported final line number from porcelain output instead of a manual counter, fixing incorrect line numbers when `startLine` offset was used - **`git_stash` list parsing**: Properly extracts branch name and description from stash entries (e.g., `WIP on main: abc123 msg` now returns `branch: "main"`, `description: "abc123 msg"`); uses parsed stash index instead of array position - **`git_push` ref parsing**: Matches both new branch and normal push output lines, capturing the remote ref name correctly - **`git_branch` show-current**: Fixed unreachable code path — result is now returned for all `show-current` cases, not just when `result.mode === 'list'` - **`git_reset` protected branch message**: Reports the actual reset mode (`--soft`, `--mixed`, etc.) instead of always saying `--hard` ### Added - **`git_clone` commit hash**: Returns the HEAD commit hash of the cloned repository in the response - **`git_merge` abort option**: New `abort` parameter to cancel an in-progress merge ### Changed - **`git_rebase` continue simplification**: Single `--continue` invocation instead of try/catch with `--no-edit` fallback ## v2.9.0 - 2026-03-06 ### Fixed - **`git_show` type detection**: Replaced heuristic output-based type detection with reliable `cat-file -t` pre-check, fixing misclassification when commit output contained "tree" or "tag" keywords in headers - **`git_reflog` action parsing**: Extracted action verb from message subject (e.g., "commit", "checkout") instead of parsing index from refName curly braces, which returned meaningless numeric values - **`git_branch` all option**: `all: true` now correctly queries both `refs/heads` and `refs/remotes` instead of incorrectly mapping to `remote: true` - **`git_set_working_dir` branch counts**: Separate local/remote branch queries produce accurate counts instead of filtering a single query by name prefix - **`git_merge` file parsing**: Parse merged files from diffstat format (`file.txt | 5 +++++`) instead of raw output lines that included CONFLICT markers - **`git_rebase` commit counting**: Count rebased commits from `Applying:` lines instead of unreliable `N commits applied` regex that never matched real git output - **`git_fetch` ref parsing**: Match all fetched ref types (new branches, tags, updated refs) and capture full remote ref names (e.g., `origin/main` instead of `main`) - **`git_worktree add` argument ordering**: Flags (`-b`, `--detach`, `--force`) now precede ` [commitish]` per git CLI spec - **`git_status` rename/copy parsing**: Properly handle porcelain v2 type-2 (renamed/copied) entries with separate staged/unstaged status tracking and correct copy detection - **`git_add` staged files reporting**: Return empty array when `--all` or `--update` is used since actual staged files are unknown ### Added - **`git_push` delete and refspec support**: Added `--delete` flag for remote branch deletion and `remoteBranch` option for `local:remote` refspec mapping (e.g., push `feature` to `deploy`) - **`git_commit` filesToStage**: Atomic stage+commit in a single operation — runs `git add` for specified files before committing - **`git_cherry_pick` options**: Added `mainline`, `strategy`, and `signoff` parameters - **`git_worktree prune` flags**: Added `--dry-run` and `--verbose` support - **`git_reset` modes**: Added `merge` and `keep` reset modes with protected branch enforcement - **Command builder**: Expanded safe git options whitelist (reset, cherry-pick/merge, worktree flags) ### Changed - **`git_log` defaults and output**: Default `maxCount` to 10; `oneline` mode strips response to `hash`, `shortHash`, and `subject` only, significantly reducing payload size; made `author`, `authorEmail`, `timestamp`, `parents` optional in output schema - **`git_reflog` default limit**: Default `maxCount` to 25 - **`git_stash` default mode**: Changed from `list` to `push` (save current changes) — more intuitive default - **`git_show` verbosity levels**: Standard level now includes content (primary output of `git show`); full includes content + metadata - **`git_remote` get-url**: Returns `url` string directly instead of wrapping in a synthetic remotes array - **`git_reset` protected branch checks**: Extended to `merge` and `keep` modes in addition to `hard` - **`git_tag` listing**: Uses `for-each-ref` for richer output including commit hash, message, tagger, and timestamp - **`git_tag` annotated handling**: Automatically set when message is provided; added tagName validation for create/delete modes; annotated without message uses tag name as default - **`git_blame` description**: Enhanced to mention `startLine`/`endLine` for large file output control - **Dependency updates**: Updated OpenTelemetry (0.212→0.213, 2.5→2.6), Hono (4.12.3→4.12.5), jose (6.1→6.2), openai (6.25→6.27), fast-xml-parser (5.4.1→5.4.2), @cloudflare/workers-types, @types/bun, @types/node, globals ## v2.8.5 - 2026-02-28 ### Fixed - **`git_diff` multi-path filtering**: Changed `GitDiffOptions.path` (single string) to `paths` (string array), enabling proper multi-path filtering. The tool layer previously joined paths with spaces, which broke when paths contained spaces and didn't leverage git's native multi-path support - **`git_diff` argument ordering**: Separated flags from path arguments to enforce correct git CLI ordering (`git diff [flags] [commits] -- [paths]`), fixing cases where `--stat` or path args appeared in the wrong position - **`git_diff` stat mode missing untracked files**: Stat-only mode (`stat: true`) now includes untracked file statistics when `includeUntracked` is enabled, matching the behavior of full diff mode - **`parseGitDiffStat` zero-count handling**: Fixed parser failing to extract stats when git omits the insertions or deletions term (e.g., `1 file changed, 5 insertions(+)` with no deletions). Each term is now matched independently - **`git_diff` stat mode leaking full patch**: Stat-only mode (`stat: true`) included the full unified diff output when `contextLines` was set, because `--unified=N` was not stripped from the stat command flags. Git interprets `--unified=N --stat` as "output both stat summary and patch" ### Changed - **Diff service refactoring**: Extracted `getUntrackedFiles()` and `execUntrackedDiff()` helpers from `executeDiff()`, eliminating duplicated untracked file logic between full diff and stat modes - **Dependency updates**: Updated hono, qs, @modelcontextprotocol/sdk, @opentelemetry/\*, @supabase/supabase-js, eslint, typescript-eslint, and other dev dependencies to latest versions ## v2.8.4 - 2026-02-14 ### Fixed - **`git_clone` ENOENT on non-existent target path**: Clone operations failed with a misleading "Git command not found" error because the child process was spawned with `cwd` set to the clone destination — which doesn't exist yet. The service layer now resolves `localPath` to an absolute path and uses its parent directory as the working directory for the git process. The tool layer no longer passes the clone target as `workingDirectory`. (Reported via [#33](https://github.com/cyanheads/git-mcp-server/pull/33) by [@ABHIRAMSHIBU](https://github.com/ABHIRAMSHIBU) and [@cmdev007](https://github.com/cmdev007)) ## v2.8.3 - 2026-02-12 ### Fixed - **Per-session McpServer isolation**: HTTP transport now creates a dedicated McpServer + StreamableHTTPTransport pair per session, fixing a correctness issue where the SDK's Protocol instance (which maintains a 1:1 relationship with its transport) was shared across concurrent connections - **Session expiry cleanup**: SessionManager now invokes an `onSessionExpired` callback when sessions expire due to inactivity, ensuring per-session transports are properly closed and cleaned up - **Protocol version validation**: Removed manual version checking from the HTTP handler — delegated to the SDK's `StreamableHTTPTransport` which already validates against `SUPPORTED_PROTOCOL_VERSIONS` ### Changed - **HTTP transport API**: `createHttpApp` and `startHttpTransport` now accept a `McpServerFactory` (async factory function) instead of a pre-created `McpServer` instance; STDIO transport is unchanged (single server) - **GET /mcp routing**: Moved server info response from a standalone GET handler into the session-aware GET handler — requests without `Mcp-Session-Id` return server info, requests with a session ID delegate to the transport for SSE streaming - **DELETE /mcp handling**: Delegates to `StreamableHTTPTransport.handleRequest()` for internal stream cleanup before removing session state - **Worker adapter**: Updated `worker.ts` to pass the server factory to `createHttpApp`, aligning with the per-session architecture ## v2.8.2 - 2026-02-12 ### Added - **Protected branch guards**: `git_push` and `git_reset` now enforce confirmation before destructive operations (force push, branch deletion, hard reset) on protected branches (main, master, production, etc.) via a `confirmed` input flag - **CORS wildcard warning**: HTTP transport logs a warning when `MCP_ALLOWED_ORIGINS` is unconfigured in production, making permissive CORS visible rather than silent ### Changed - **Config validation hardening**: `authorName` and `committerName` now reject newlines and null bytes via regex validation, preventing header injection in git identity fields - **Removed `environment` from public endpoint**: The `GET /mcp` identity response no longer exposes the deployment environment, reducing information leakage - **Removed `escapeShellArg`**: Deleted unused shell escaping utility from command builder — git commands use `execFile` array args, making shell escaping unnecessary and misleading ## v2.8.1 - 2026-02-12 ### Added - **`git_tag` sign option**: Exposed explicit `sign` parameter on the `git_tag` tool, allowing callers to request GPG/SSH-signed tags independent of the global `GIT_SIGN_COMMITS` config - **`forceUnsignedOnFailure` option**: Added to both `git_commit` and `git_tag` — when signing fails (e.g., missing GPG key, agent unavailable), automatically retries the operation unsigned instead of failing - **Signing resilience tests**: Comprehensive test coverage for `forceUnsignedOnFailure` retry behavior in commit and tag operations, plus `sign` option passthrough in the tag tool ### Changed - **Tag create refactor**: Extracted `buildCreateArgs` helper in tag service to cleanly support signed/unsigned retry without duplicating argument construction logic ## v2.8.0 - 2026-02-12 ### Added - **`git_changelog_analyze` tool**: New read-only tool that gathers git history context (commits, tags) and structured review instructions for LLM-driven changelog analysis. Supports six review types: `security`, `features`, `storyline`, `gaps`, `breaking_changes`, and `quality`. Configurable commit window (`maxCommits`), tag-based range filtering (`sinceTag`), and branch selection - **`git_changelog_analyze` unit tests**: Comprehensive test suite covering input schema validation, tool logic (parallel fetching, sinceTag/branch precedence, empty states), review instruction generation, response formatting, and tool metadata ### Changed - **Tool count**: Updated README and tool overview from 27 to 28 tools, added new "Analysis" category to the tools table ## v2.7.1 - 2026-02-12 ### Fixed - **Literal escape sequences in messages**: Added `normalizeMessage()` utility that converts literal `\n`, `\r`, `\t`, and `\r\n` sequences to actual characters in commit, tag, and stash messages — LLM clients frequently send these as two-character literal sequences instead of real control characters - **CommitMessageSchema transform**: Applied `normalizeMessage` as a Zod `.transform()` on `CommitMessageSchema` so commit messages are normalized at parse time - **Stash and tag message normalization**: Applied `normalizeMessage` to stash (`git_stash`) and tag (`git_tag`) message inputs - **Commit tool description**: Updated `git_commit` tool description to document escape sequence normalization behavior ### Added - **`normalizeMessage` tests**: Added unit tests for `normalizeMessage` covering all escape sequences, mixed input, empty strings, and realistic multi-line commit messages - **`CommitMessageSchema` tests**: Added schema-level tests verifying transform behavior, passthrough of real newlines, and validation constraints ## v2.7.0 - 2026-02-12 ### Added - **CI workflow**: Added GitHub Actions CI pipeline with lint, typecheck, and test steps on push/PR to main - **Comprehensive unit test suite**: Added 41 new test files covering all tool definitions, service layer operations, prompts, resources, auth middleware, and shared utilities - **Bun test runner compatibility**: Added Vitest compatibility shims in test setup for `vi.mock`, fake timers, and pre-mocked modules ### Changed - **Removed roots, elicitation, and sampling capabilities** from MCP server registration; simplified server to logging, resources, tools, and prompts - **Removed `ElicitableContext`** and elicitation bridging logic from tool handler factory, simplifying `appContext` creation - **Deleted `roots-registration.ts`** module and its import/usage in server setup - **Modernized publish workflow**: Added Bun setup, upgraded Node.js 18→22, migrated install/build/test steps from npm to Bun, added lint and typecheck gates - **Rewrote CLAUDE.md** (v2.4.1 → v2.5.0): consolidated agent protocol docs, updated tool workflow to use `createToolHandler` pattern, reformatted tables - **Deleted `.clinerules/clinerules.md`**: obsolete hard-linked copy replaced by AGENTS.md symlink - **Updated `docs/tree.md`** to reflect removal of roots directory - **Updated server.json**: bumped schema to 2025-12-11, removed deprecated `mcpName` field ### Fixed - **Wrapup tool module init**: Added defensive null check (`config?.git?.wrapupInstructionsPath`) to prevent crash when config is undefined during test or early initialization - **Logger integration tests**: Replaced brittle `setTimeout` waits with deterministic `waitForLogEntry`/`waitForFile` polling helpers ### Improved - **Test type safety**: Added explicit `ExecGitFn` type for mock functions and non-null assertions on mock call access in checkout, diff, and log tests - **Test runner config**: Added sequential execution (`maxWorkers: 1`) and fake timer configuration to vitest.config.ts - **Clean script**: Added `coverage` to default clean directories ### Dependencies - Bumped `@modelcontextprotocol/sdk` from ^1.24.3 to ^1.26.0 - Bumped `eslint` from ^9.39.2 to ^10.0.0 and `@eslint/js` from ^9.39.2 to ^10.0.1 - Bumped `zod` from ^4.1.13 to ^4.3.6 - Bumped `hono` from ^4.10.8 to ^4.11.9 and `@hono/node-server` from ^1.19.7 to ^1.19.9 - Bumped `vitest` from ^4.0.15 to ^4.0.18 and `@vitest/coverage-v8` from 4.0.15 to 4.0.18 - Bumped `pino` from ^10.1.0 to ^10.3.1 - Bumped `typescript-eslint` from 8.49.0 to 8.55.0 - Bumped `vite` from 7.2.7 to 7.3.1 and `vite-tsconfig-paths` from ^5.1.4 to ^6.1.1 - Bumped `globals` from ^16.5.0 to ^17.3.0 - Updated numerous other dev dependencies to latest versions ## v2.6.5 - 2025-12-13 ### Added - **git_log stat/patch support**: Added `stat` and `patch` options to git_log tool for viewing file change statistics and full diff patches per commit - **git_log skip support**: Added `skip` option for pagination of commit history - **git_diff includeUntracked support**: Implemented full support for including untracked files in diff output using `git ls-files --others` and `git diff --no-index` - **git_checkout track support**: Added `track` option for setting up branch tracking when creating branches ### Changed - **Tool Option Mapping**: Refactored git_log and git_diff tools to use cleaner spread operator pattern for mapping tool interface to provider options - **Diff Command Ordering**: Corrected flag ordering in diff operations to place flags before commits/paths per git convention ### Fixed - **git_diff nameOnly mode**: Fixed nameOnly output to properly count and return file list including untracked files - **git_diff stat mode**: Fixed stat-only mode to return complete diffstat output ### Dependencies - Updated `@cloudflare/workers-types` from 4.20251212.0 to 4.20251213.0 - Updated `@eslint/js` from 9.39.1 to 9.39.2 - Updated `clipboardy` from 5.0.1 to 5.0.2 - Updated `eslint` from 9.39.1 to 9.39.2 - Updated `repomix` from 1.10.0 to 1.10.1 ## v2.6.4 - 2025-12-12 ### Fixed - **Build Artifact Version Mismatch**: Rebuilt dist to embed correct version. v2.6.3 was published with stale build artifacts containing v2.6.2 version string. ## v2.6.3 - 2025-12-12 ### Fixed - **Windows Git Executable Resolution**: Fixed `ENOENT` error when spawning git commands on Windows. Node.js `child_process.spawn()` doesn't search PATH like cmd.exe does. Replaced with `cross-spawn` package for proper Windows PATH resolution. Fixes [#37](https://github.com/cyanheads/git-mcp-server/issues/37). ### Changed - **Runtime Adapter**: Updated Node.js spawn implementation to use `cross-spawn` for cross-platform compatibility while maintaining array-based argument passing for security ### Added - **Runtime Adapter Tests**: Added unit tests for `detectRuntime()` and `spawnGitCommand()` covering runtime detection, git command execution, timeout handling, and abort signal cancellation - **Command Builder Tests**: Added unit tests for `buildGitEnv()`, `buildGitCommand()`, `validateGitArgs()`, and `escapeShellArg()` covering PATH preservation, git-specific environment variables, null byte rejection, and shell metacharacter safety ## v2.6.2 - 2025-12-12 ### Fixed - **JSON Schema Compatibility**: Changed numeric schema validators from `.positive()` to `.min(1)` for Draft 4 compatibility. Go clients using Draft 4 JSON Schema parsers failed when `exclusiveMinimum` was a number (Draft 7 format) instead of a boolean (Draft 4 format). Using `.min(1)` outputs `minimum: 1` which works across all JSON Schema drafts. Fixes [#34](https://github.com/cyanheads/git-mcp-server/issues/34). - Updated `LimitSchema` and `DepthSchema` in common schemas - Updated `mainline` parameter in `git_cherry_pick` tool ### Added - **Schema Compatibility Tests**: Added comprehensive test suite (`tests/mcp-server/tools/schemas/common.test.ts`) validating JSON Schema output for Draft 4 compatibility across all numeric constraints ## v2.6.1 - 2025-12-12 ### Fixed - **Cross-Platform Path Validation**: Replaced Unix-specific `/` prefix check with `path.isAbsolute()` for proper Windows and POSIX path handling in `GIT_BASE_DIR` validation. Fixes [#36](https://github.com/cyanheads/git-mcp-server/issues/36). - **Path Sanitization**: Fixed absolute path handling when a rootDir is specified - paths within rootDir are now correctly validated instead of being rejected. Related to [#36](https://github.com/cyanheads/git-mcp-server/issues/36). ### Security - **Enhanced Path Traversal Detection**: Improved path normalization in sanitization logic to consistently compare normalized paths, preventing bypass attempts via redundant slashes or dot segments ### Added - **Path Sanitization Tests**: Added comprehensive test suite covering absolute paths within/outside rootDir, nested paths, redundant slashes, dot segments, and path traversal scenarios ## v2.6.0 - 2025-12-12 ### Changed - **MCP SDK 1.24.x Upgrade**: Upgraded to MCP SDK 1.24.3 with breaking API changes: - Updated tool handler signatures to use new SDK types (`ServerRequest`, `ServerNotification`) - Changed resource registration to use `title` property instead of `name` - Updated tool registration to pass schemas directly instead of `.shape` - Removed deprecated `description` property from server configuration - **Zod 4.x Migration**: Upgraded from Zod 3.x to 4.x: - Updated `z.record(z.any())` to `z.record(z.string(), z.any())` in git-add, git-commit, and git-show tools - All tool schemas now compatible with Zod 4.x strict typing - **MCP Spec Compliance**: Updated spec version reference from 2025-06-18 to 2025-11-25 - **Runtime Recommendation**: Changed primary recommendation from Bun to Node.js for end users: - Documentation now recommends `npx` as the primary installation method - `bunx` remains available as an alternative - Development commands updated from `bun` to `npm run` - **Documentation**: Simplified prerequisites and streamlined installation instructions ### Fixed - **Import Order**: Added critical comment noting `reflect-metadata` must be imported before any module using tsyringe ### Dependencies - Updated MCP SDK from 1.20.2 to 1.24.3 - Updated Zod from 3.23.8 to 4.1.13 - Updated Hono from 4.10.3 to 4.10.8 - Updated @hono/mcp from 0.1.4 to 0.2.2 - Updated @hono/node-server from 1.19.5 to 1.19.7 - Updated OpenTelemetry packages from 0.207.x to 0.208.x - Updated TypeScript-ESLint from 8.46.2 to 8.49.0 - Updated Vitest from 4.0.4 to 4.0.15 - Updated numerous other dependencies to latest versions ## v2.5.8 - 2025-10-27 ### Changed - **Dependency Updates**: Updated several core dependencies to their latest versions for improved security and performance: - Updated `axios` from 1.12.2 to 1.13.0 - Updated `hono` from 4.9.12 to 4.10.3 - Updated `validator` from 13.15.15 to 13.15.20 - Updated `@types/validator` from 13.15.3 to 13.15.4 - Updated `vitest` and related testing packages from 4.0.3 to 4.0.4 ## v2.5.7 - 2025-10-24 ### Changed - **API Refinement**: Renamed `includeContext` parameter to `includeMetadata` in `git_set_working_dir` tool for better clarity. Changed default from `true` to `false` to minimize response size and improve performance. The metadata (status, branches, remotes, recent commits) is now opt-in rather than opt-out. ### Improved - **Tool Descriptions**: Enhanced `git_commit` tool description with explicit examples showing proper JSON string formatting for single-line and multi-line commit messages. - **Code Formatting**: Improved readability of conditional statements in logger error handlers with better line breaks. ## v2.5.6 - 2025-10-24 ### Fixed - **Critical: Worker Thread Crashes**: Externalized `pino` and `pino-pretty` from the bundle to fix ThreadStream worker exit errors. Pino's worker threads require actual files on disk, which fail when bundled. This resolves the immediate crash on startup reported in [#27](https://github.com/cyanheads/git-mcp-server/issues/27). - Added `--external pino --external pino-pretty` to build command - Reduced bundle size from 7.30 MB to 7.18 MB (1992 vs 2021 modules) - Logger now loads from node_modules at runtime instead of being embedded ## v2.5.5 - 2025-10-24 > **Note**: Version 2.5.4 was published but I messed up the changelog somehow. Skipped to avoid conflicts. This release supersedes 2.5.4. ## v2.5.4 - 2025-10-24 ### Fixed - **Console Output in Non-TTY Environments**: Enhanced logging to prevent ANSI codes and debug output from polluting non-TTY environments, especially STDIO mode. Added TTY checks (`process.stderr?.isTTY`) throughout logging infrastructure to ensure clean JSON-RPC output. - JSON response formatter now checks TTY before debug logging - Tool handler factory validates SDK context only when TTY available - Logger startup messages conditional on TTY to avoid stderr pollution - Startup banner uses stderr in STDIO mode (stdout reserved for MCP JSON-RPC) ### Changed - **Dependencies**: Moved `pino` and `pino-pretty` from devDependencies to regular dependencies for better production deployment - **Dependency Updates**: - Updated OpenTelemetry packages from 0.206.x to 0.207.x - Updated MCP SDK from 1.20.0 to 1.20.2 - Updated ESLint and TypeScript-ESLint packages (9.37.0 → 9.38.0, 8.46.0 → 8.46.2) - Updated Vitest from 3.2.4 to 4.0.3 - Updated Hono from 4.9.12 to 4.10.3 - Updated Vite from 7.1.9 to 7.1.12 - Various other package updates (MSW, OpenAI, Repomix, etc.) ### Technical Details - The STDIO transport requires pristine stdout for MCP JSON-RPC protocol compliance - All startup banners, debug output, and logs now respect TTY detection - In STDIO mode, banners and errors use stderr; HTTP mode continues to use stdout - Enhanced test coverage to verify transport-specific logging behavior ## v2.5.3 - 2025-10-15 ### Fixed - **Critical: STDIO Logging to stderr**: Fixed logger to route all log output to stderr (fd 2) instead of stdout (fd 1) when using STDIO transport. The MCP specification mandates that stdout must contain ONLY JSON-RPC messages. Previously, logs were incorrectly sent to stdout, which could interfere with MCP client parsing. - Changed `pino/file` destination from `1` (stdout) to `2` (stderr) for STDIO and production modes - Enhanced test coverage to verify stderr routing and validate ANSI code removal - Added comprehensive documentation explaining the MCP specification requirement ### Technical Details - The MCP specification requires strict stdout hygiene - only JSON-RPC protocol messages allowed - Logs were already in plain JSON format (no ANSI codes) as of v2.5.2, but routing to stdout still violated spec - Solution: Updated logger transport configuration to use stderr (fd 2) for all non-development STDIO scenarios - This ensures MCP clients can reliably parse stdout as pure JSON-RPC without encountering log messages ### Changed - **Documentation**: Updated test comments to clarify that file-based testing verifies format while stderr routing is enforced by implementation ## v2.5.2 - 2025-10-15 ### Fixed - **STDIO Transport Logging Compliance**: Fixed logger to prevent ANSI color codes from appearing in stdout when using STDIO transport. The MCP specification requires clean JSON-RPC output with no formatting escape sequences. Logger now accepts transport type during initialization and forces plain JSON output for STDIO mode while preserving colored output for HTTP mode in development. - Added `transportType` parameter to `logger.initialize()` - STDIO mode now bypasses `pino-pretty` and outputs raw JSON - HTTP mode continues to use colored output in development for better developer experience - Added comprehensive test coverage validating ANSI code removal in STDIO logs ### Technical Details - The root cause was that the logger used `pino-pretty` for all development environments, which adds ANSI escape codes for colorized output - MCP clients parse stdout as JSON-RPC and fail when encountering non-JSON content - Solution: Pass `config.mcpTransportType` to logger during initialization to conditionally enable pretty output ## v2.5.1 - 2025-10-15 ### Fixed - **Critical: Dependency Resolution Issues with `bunx`/`npx`**: Resolved Cursor MCP client connection failures caused by Bun's `EEXIST` linking errors during dependency installation. The root cause was that all dependencies were listed as runtime dependencies despite being bundled into the single-file output by `bun build`. - **Solution**: Moved all dependencies to `devDependencies` since they are already bundled into `dist/index.js` (7.2MB single-file bundle) - **Impact**: Package now installs in ~20ms with **zero runtime dependencies**, eliminating all dependency linking conflicts - **Benefit**: MCP clients using `bunx` or `npx` can now reliably execute the server without installation failures ### Technical Details - The build process (`bun build --target node`) creates a self-contained bundle with all code inlined - Published package now contains only: `dist/index.js`, `package.json`, `README.md`, `LICENSE` - Package size reduced from requiring 30+ dependency installations to single-file execution - No changes to functionality - all features work identically ## v2.5.0 - 2025-10-13 ### Added - **MCP Spec 2025-06-18 Compliance Enhancements**: - **Protocol Version Validation**: Server now properly validates `MCP-Protocol-Version` header and returns HTTP 400 Bad Request for unsupported protocol versions (per MCP spec requirement). Previously only logged a warning. - **Session Management**: Implemented comprehensive HTTP session lifecycle management per MCP specification: - New `SessionManager` service tracks session creation, activity, and expiry - Sessions automatically expire after configurable timeout (`MCP_STATEFUL_SESSION_STALE_TIMEOUT_MS`) - Background cleanup removes stale sessions periodically - Server returns HTTP 404 when session expires, signaling clients to reinitialize - DELETE endpoint for explicit client-initiated session termination - **Cancellation Support**: Wired up `AbortSignal` throughout the git operation stack for proper request cancellation: - Git CLI executor now accepts and respects `AbortSignal` from MCP SDK - Both Bun and Node.js runtime adapters kill child processes on abort - Long-running operations (clone, fetch, push, pull) can be cancelled mid-execution - Resources cleaned up properly on cancellation ### Changed - **HTTP Transport**: Enhanced `httpTransport.ts` with session validation and lifecycle management - **Git Runtime Adapter**: Updated `runtime-adapter.ts` to support cancellation in both Bun and Node.js spawning paths - **Session Lifecycle**: HTTP transport now stops session cleanup interval during graceful shutdown ### Technical Debt Reduced - Eliminated potential memory leak from never-expiring sessions - Improved cancellation story for long-running git operations - Better alignment with MCP specification recommendations ## v2.4.9 - 2025-10-13 ### Added - **Configurable Git Identity**: Introduced support for setting Git author and committer information via environment variables (e.g., `GIT_AUTHOR_NAME`, `GIT_AUTHOR_EMAIL`). The server now automatically uses these values, with a fallback to the user's global Git configuration if they are not set. This allows for consistent identity management across all Git operations. - **Expanded Commit Signing**: Extended GPG/SSH signing capabilities to all commit-creating operations. Signing can now be enabled for `git merge`, `git rebase`, `git cherry-pick`, and `git tag` in addition to `git commit`. ### Changed - **Internal Refactor**: Centralized the logic for handling Git identity and commit signing within the command builder (`command-builder.ts`) and a new configuration helper (`config-helper.ts`). This ensures that all Git operations consistently use the configured identity and signing settings. - **Documentation**: Updated `README.md` and `.env.example` to provide clear documentation and examples for the new Git identity and expanded signing features. - **Version**: Bumped the package version to `2.4.9`. ## v2.4.8 - 2025-10-13 ### Fixed - **Package Scripts**: Reorganized `package.json` scripts section to match template structure, fixing stdio transport connection issues. Removed comment separators that could interfere with script execution and reordered scripts in the proper sequence (build → deploy → start → dev). Added missing `rebuild` script. - **Transport Detection**: Resolved issue where MCP clients (like Cursor) would show red connection indicator despite successful tool/resource registration when using stdio transport. ### Changed - **Script Organization**: Scripts now follow consistent ordering pattern matching the mcp-ts-template for better maintainability and cross-project consistency. ## v2.4.7 - 2025-10-13 ### Added - **Cross-Runtime Compatibility**: The server now officially supports both **Bun** and **Node.js** runtimes. A new runtime detection mechanism (`src/utils/internal/runtime.ts`) and a runtime adapter for Git command execution (`src/services/git/providers/cli/utils/runtime-adapter.ts`) have been added. This ensures optimal performance by using `Bun.spawn` in the Bun runtime and `child_process.spawn` in the Node.js runtime. - **Runtime Logging**: The server now logs the detected runtime environment on startup for easier debugging and support. ### Changed - **Documentation**: Updated `README.md` to reflect the new cross-runtime compatibility, providing clear instructions and configuration examples for both `bunx` and `npx`. - **Dependencies**: Updated several dependencies to their latest versions, including `hono`, `repomix`, and `vite`. ## v2.4.6 - 2025-10-11 ### Changed - **Documentation**: Polished the `README.md` to improve clarity and consistency across the "Tools," "Resources," and "Prompts" sections. - **Configuration**: Refined the `package.json` file by organizing scripts into logical groups, alphabetizing keywords, and simplifying the project description for better readability. ## v2.4.5 - 2025-10-11 ### Added - **Tilde Expansion Support**: Configuration now supports tilde (`~`) expansion in path environment variables for improved developer experience. Applies to `LOGS_DIR`, `STORAGE_FILESYSTEM_PATH`, `GIT_WRAPUP_INSTRUCTIONS_PATH`, and `GIT_BASE_DIR`. Supports both `~/path` (expands to `homedir/path`) and `~` alone (expands to `homedir`). - **Enhanced Git Branch Filtering**: The `git_branch` tool now accepts commit references for `merged` and `noMerged` parameters. Users can specify a commit hash or branch name to filter branches (e.g., `merged: "main"` shows branches merged into main, not just HEAD). - **Shared Formatter Utility**: Extracted duplicate `flattenChanges` helper function into shared utility module (`git-formatters.ts`) for better code reuse across git tools. ### Fixed - **Documentation Typo**: Corrected agent meta files reference in `git_wrapup_instructions` tool from `.clinerules` to `.cline_rules`. ### Changed - **Version Bump**: Updated version from 2.4.4 to 2.4.5 in package.json and README.md. - **Code Refactoring**: Consolidated duplicate change flattening logic from `git_add` and `git_commit` tools into the shared `flattenChanges` utility, improving maintainability. - **Documentation**: Updated tree.md to reflect addition of `git-formatters.ts` utility. - **README Examples**: Enhanced README with more comprehensive configuration examples including git username, email, base directory, and logs directory settings. ## v2.4.4 - 2025-10-11 ### Added - **Enhanced Repository Context**: The `git_set_working_dir` tool now provides rich repository context by default when setting the working directory. Includes immediate status, branch information, configured remotes, and recent commits. Context gathering can be disabled via the new `includeContext` parameter. - **Base Directory Security**: New optional `GIT_BASE_DIR` environment variable to restrict all git operations to a specific directory tree. Provides security sandboxing for multi-tenant or shared hosting environments. When configured, prevents git operations from accessing paths outside the specified base directory. ### Changed - **Configuration**: Updated default HTTP port from 3010 to 3015 across all configuration files (`.env.example`, `src/config/index.ts`, `smithery.yaml`, tests). - **Documentation**: Enhanced response format documentation in README with comprehensive examples showing both JSON (LLM-optimized) and Markdown (human-readable) output formats. Added detailed explanation of verbosity levels and when to use each format. - **Documentation**: Clarified tool count (now 27 with addition of `git_clear_working_dir`) and updated Advanced Workflows category to reflect both `git_set_working_dir` and `git_clear_working_dir` tools. - **Documentation**: Added comprehensive Roadmap section detailing provider-based architecture and planned git provider integrations (CLI via Bun.spawn, isomorphic-git, GitHub API). Includes technical details about current CLI provider implementation (streaming I/O, timeout handling, buffer limits). - **Documentation**: Enhanced Features section to highlight provider-based architecture and optimized git execution via Bun.spawn with streaming I/O and timeout handling. - **Branding**: Updated project references from `mcp-ts-template` to `git-mcp-server` in configuration files (`typedoc.json`, `smithery.yaml`, `wrangler.toml`). ### Fixed - **Import Order**: Corrected import organization in `git-set-working-dir.tool.ts` to follow project conventions (framework imports first, internal imports second). - **Config Import**: Fixed config import in `git-validators.ts` to use named export pattern with proper TypeScript typing for optional GIT_BASE_DIR value. Added defensive null-safety checks to handle undefined config in test environments. ## v2.4.3 - 2025-10-11 ### Fixed - **Git Branch Tool**: Fixed `git for-each-ref` command construction by correctly placing the command in the `command` parameter instead of args array - **Git Rebase Tool**: Enhanced `--continue` mode with fallback handling for `--no-edit` option, improving compatibility across different Git versions - **Git Command Builder**: Fixed environment variable construction to preserve PATH from process.env, ensuring git executable can be found in custom install locations ### Changed - **Documentation**: Updated tree.md to reflect addition of CLAUDE.md file ## v2.4.2 - 2025-10-10 ### Added - **JSON Response Formatter**: Introduced a new `json-response-formatter` utility (`src/mcp-server/tools/utils/json-response-formatter.ts`) to create LLM-optimized, structured JSON responses for tools. This improves parsing efficiency and reduces token usage compared to Markdown. The formatter supports configurable verbosity levels (`minimal`, `standard`, `full`). ### Changed - **Tool Architecture**: Refactored all Git tools to align with the new v2.4.0 architecture. All `responseFormatter` implementations now use the new `createJsonFormatter`, and Git command execution is consistently delegated to the `GitProvider` service layer. - **Test Suite**: Updated the entire test suite to reflect the architectural changes. Test helpers, assertions, and unit tests have been modified to validate structured JSON output instead of Markdown. - **Configuration**: The `.env.example` file has been updated to include the new `MCP_RESPONSE_VERBOSITY` configuration option. - **Logging**: The logger (`src/utils/internal/logger.ts`) has been enhanced to include a `notice` level and an improved startup banner. ### Dependencies - Updated `package.json` and `bun.lock` with the latest versions of project dependencies. ## v2.4.1 - 2025-10-11 ### Added - **Markdown Builder Utility**: Added a fluent interface markdown builder (`src/mcp-server/tools/utils/markdown-builder.ts`) for constructing LLM-optimized response formatters. Provides chainable methods for headings, sections, lists, key-value pairs, and conditional content. Improves consistency and maintainability across all tool response formatters. - **SDK Context Validation**: Added defensive type guard (`validateSdkContext`) in tool handler factory to validate MCP SDK context structure, catching unexpected issues early and improving robustness. ### Changed - **Tool Response Formatters**: Refactored `git_add` and `git_commit` response formatters to use the new markdown builder utility, resulting in cleaner, more maintainable code with consistent formatting. - **Enhanced Tool Output**: - `git_add` tool now includes comprehensive repository status after staging, showing all staged changes, remaining unstaged changes, untracked files, and whether the repository is ready to commit. - `git_commit` tool response formatter refactored for improved readability and structure using markdown builder. - **Tool Handler Improvements**: - Enhanced dependency injection with closure-based memoization for thread-safe singleton pattern. - Added debug mode logging for tool inputs (enabled via `MCP_DEBUG_TOOL_INPUTS=true`). - Improved error context logging with more detailed information about failures. - Better path resolution with runtime type safety checks and comprehensive logging. - Added graceful fallback when path property is unexpectedly missing from tool input. ### Fixed - **Tool Handler Type Safety**: Improved runtime type checking for tool inputs with path properties, preventing potential type mismatches during working directory resolution. ### Documentation - **README**: Enhanced formatting and improved documentation structure for prompts and tool responses sections. - **CHANGELOG**: Consolidated alpha release notes into cohesive v2.4.0 release notes. ### Dependencies - Updated `@cloudflare/workers-types` to `^4.20251011.0` - Updated `@types/bun` to `^1.3.0` - Updated `bun-types` to `^1.3.0` - Removed unused transitive dependencies from lock file ## v2.4.0 - 2025-10-10 - Aligned with [mcp-ts-template](https://github.com/cyanheads/mcp-ts-template) v2.3.5 - Moved to [Bun](https://bun.sh) for dependency management, scripting, and runtime execution. - Major architectural refactor to a dual-output tool architecture with structured content and User-optimized responses. ### New Features - **Git Wrapup Prompt** (`git_wrapup`): A new structured workflow prompt for completing git sessions. Guides users through a systematic protocol including reviewing changes with `git_diff`, updating changelog and documentation, creating logical commits, and optionally creating release tags. Features configurable options for skipping documentation review, creating tags, and updating agent meta files. Integrates with the `git_wrapup_instructions` tool for context-aware workflow generation. - **Git Blame Tool** (`git_blame`): Show line-by-line authorship information for files, displaying who last modified each line and when. Supports optional line range filtering (`startLine`, `endLine`), whitespace change ignoring, and provides formatted output with commit hash, date, author, and content for each line. - **Git Reflog Tool** (`git_reflog`): View reference logs (reflog) to track when branch tips and other references were updated. Essential for recovering lost commits and understanding repository history. Supports filtering by specific references (default: HEAD) and configurable entry limits. Output includes chronological history of all git operations. ### Added - **Dual-Output Tool Architecture**: All tools now implement a sophisticated dual-output system that provides different perspectives of the same operation: - **Structured Content** (`outputSchema`): Type-safe Zod schemas define the complete, machine-readable data structure returned by tool logic. This is the "source of truth" containing all operational details. - **Response Formatter** (`responseFormatter`): Transforms structured output into LLM-optimized `ContentBlock[]` arrays. These formatted responses balance human-readable summaries with complete data, ensuring LLMs have full context to answer follow-up questions. Supports markdown formatting, hierarchical organization, and intelligent truncation. - **Key Benefit**: Clients can access raw structured data for processing while LLMs receive optimized, contextual narratives—all from a single tool invocation. - **Architectural Foundation**: - **Dependency Injection**: Integrated `tsyringe` for robust dependency injection, decoupling services and tools. A central DI `container` now manages object lifetimes. - **Service/Provider Pattern**: Introduced a standardized service and provider pattern (`src/services/`, `src/storage/`) for abstracting external integrations and data persistence. - **Declarative Definitions**: Resources and tools are now self-contained, declarative `ToolDefinition` and `ResourceDefinition` objects in `src/mcp-server/tools/definitions/` and `src/mcp-server/resources/definitions/`, respectively. This simplifies registration and improves modularity. - **Core Utilities**: - **Observability**: Added `performance` and `telemetry` utilities for tracing and metrics, including `measureToolExecution` for automatic performance tracking. - **Runtime Helpers**: New utilities for runtime detection (`isBun`, `isCloudflareWorker`) and startup banners. - **Health Checks**: A new internal health check utility for verifying service status. - **Authorization**: Implemented `withToolAuth` and `withResourceAuth` wrapper functions to apply scope-based authorization declaratively to tools and resources. - **Build & Development**: - **Bun**: Fully migrated to `bun` for dependency management, scripting, and runtime execution, replacing `npm` and `tsx`. - **Devcheck Script**: Added a new `devcheck` script (`scripts/devcheck.ts`) for comprehensive quality checks (lint, format, typecheck, audit). ### Changed - **Major Architectural Refactor**: The entire server has been overhauled to align with the `mcp-ts-template v2.3.5` architecture. This is a breaking change for the internal structure but maintains external API compatibility. - **File Structure**: Massively reorganized the `src` directory to enforce a strict separation of concerns, with new top-level directories for `container`, `services`, `storage`, and `mcp-server`. - **Tool Registration**: The previous registration system (`registration.ts` files) has been replaced by a barrel export (`index.ts`) in the `definitions` directories, which is automatically consumed by the DI container. - **Configuration**: Enhanced `src/config/index.ts` with more detailed Zod validation and runtime-specific configurations. - **Transports**: Refactored transport management (`src/mcp-server/transports/`) with a unified `TransportManager` and a clear `ITransport` interface. - **Error Handling**: Centralized error handling logic into `src/utils/internal/error-handler/`, improving consistency. ### Removed - **Legacy Tool Structure**: Deleted the entire old tool directory structure (`src/mcp-server/tools/[toolName]/{index.ts, logic.ts, registration.ts}`). All tools were rewritten as declarative definitions. - **Legacy Resource Structure**: Deleted the old resource directory structure for `gitWorkingDir`. - **Legacy Transport Core**: Removed outdated transport management files from `src/mcp-server/transports/core/`. - **Build & Config Files**: Removed `package-lock.json`, `.ncurc.json`, `Dockerfile`, and `tsconfig.typedoc.json`, which are no longer needed with the `bun`-based workflow. ## v2.3.5 - 2025-09-29 ### Changed - **Tooling**: - The `git_commit` tool now correctly handles cases where there are no changes to commit, returning a `nothingToCommit: true` status instead of throwing an error. - The `git_status` tool's schema is now more flexible (`.passthrough()`) to prevent validation errors on encountering unexpected Git status identifiers. - **Dependencies**: Updated various dependencies, including `@hono/node-server`, `@types/node`, `typescript-eslint`, and `typescript`. - **CI/CD**: Minor formatting adjustments in the `publish.yml` GitHub Actions workflow. ### Removed - **Legacy Files**: Deleted `mcp.json`, `docs/publishing-mcp-server-registry.md`, and `scripts/validate-mcp-publish-schema.ts`, which were part of an outdated publishing workflow. ## v2.3.4 - 2025-09-26 ### Removed - **Publishing**: Removed the manual publishing script (`scripts/validate-mcp-publish-schema.ts`) and associated documentation (`docs/publishing-mcp-server-registry.md`). The `mcp.json` file, related to the old workflow, has also been deleted. This streamlines the publishing process. ### Added - **Custom Instructions**: The `git_wrapup_instructions` tool can now load custom instructions from an external Markdown file. The file path can be specified using the `GIT_WRAPUP_INSTRUCTIONS_PATH` environment variable. ### Changed - **Instructions**: Enhanced the default `git_wrapup_instructions` to be more authoritative and include an example task list. - **Dependencies**: Updated various dependencies to their latest versions, including `@modelcontextprotocol/sdk`, `openai`, `tsx`, and `typescript-eslint`. ## v2.3.3 - 2025-09-15 ### Added - **Documentation**: New guide on "How to Publish Your MCP Server" (`docs/publishing-mcp-server-registry.md`) including an all-in-one `publish-mcp` script. - **Scripts**: Added `scripts/validate-mcp-publish-schema.ts` to automate version syncing, schema validation, and publishing workflow for MCP servers. ### Changed - **Build & Configuration**: - Updated `.gitignore` with new categories and ignore patterns for `.vscode/`, `.history/`, `build/`, `dist/`, `out/`, `logs/`, `data/`, generated documentation, environment files, and MCP registry related files. - Added `mcpName` field to `package.json` for MCP registry identification. - `server.json` updated with new `mcpName` and version. - **Dependencies**: - Updated `@modelcontextprotocol/sdk` to `^1.18.0`. - Updated `axios` to `^1.12.2`. - Updated `jose` to `^6.1.0`. - Updated `openai` to `^5.20.2`. - Updated `tiktoken` to `^1.0.22`. - Updated `@eslint/js` to `^9.35.0`. - Updated `@types/node` to `^24.4.0`. - Updated `@types/validator` to `13.15.3`. - Added `ajv` and `ajv-formats` as devDependencies. - Updated `eslint` to `^9.35.0`. - Updated `globals` to `^16.4.0`. - Updated `msw` to `^2.11.2`. - Updated `tsx` to `^4.20.5`. - Updated `typedoc` to `^0.28.13`. - Updated `typescript-eslint` to `^8.43.0`. - **Code Improvement**: - Modified `src/utils/metrics/tokenCounter.ts` to explicitly check `tool_call.type === "function"` before accessing function-specific properties; improves robustness for different tool call types. ## v2.3.2 - 2025-07-31 ### Feature - **Enhanced Tool Feedback**: Implemented an enhancement across multiple core Git tools to provide immediate, contextual feedback on the repository's state. The following tools now include the complete, structured output of `git status` in their JSON response upon successful execution: - `git_add` - `git_checkout` - `git_cherry_pick` - `git_clean` - `git_commit` - `git_merge` - `git_pull` - `git_rebase` - `git_reset` - `git_stash` This change allows agents and clients to instantly verify the outcome of an operation without needing to make a subsequent call to `git_status`. ### Chore - **Build & Configuration**: - **ESLint**: Updated `eslint.config.js` to add `coverage/`, `dist/`, `logs/`, and `data/` to the ignored paths, preventing linting of generated or irrelevant files. - **MCP Configuration**: Modified `mcp.json` to use `npx @cyanheads/git-mcp-server` as the execution command, simplifying server startup and removing the need for a local build. - **Dependencies**: - Bumped the package version to `2.3.2` in `package.json` and `package-lock.json`. - **Testing**: - Performed minor refactoring in `tests/utils/internal/errorHandler.test.ts` and `tests/utils/internal/logger.test.ts` to align with recent code modifications and improve test clarity. ## v2.3.1 - 2025-07-31 ### Added - **Testing**: - Added a comprehensive test suite covering authentication (`auth.test.ts`, `authUtils.test.ts`, `oauthStrategy.test.ts`), core utilities (`errorHandler.test.ts`, `logger.test.ts`, `requestContext.test.ts`), and transports (`stdioTransport.test.ts`). - Integrated `msw` for mocking API requests during tests. - Added `@vitest/coverage-v8` for generating code coverage reports. - **CI/CD**: - Added `logs/` to `.gitignore` to prevent log files from being committed. ### Changed - **Error Handling**: - Improved `ErrorHandler` to provide more specific and consistent error messages. - Enhanced `jwtStrategy.ts` and `oauthStrategy.ts` to re-throw structured `McpError`s, ensuring consistent error propagation. - **Logging**: - Refactored the `Logger` class in `logger.ts` to be exportable and added a `resetForTesting` method to support isolated test runs. - Corrected the parameter order in a `logger.fatal` call within `httpTransport.ts` for better error reporting. - **Dependencies**: - Updated `@modelcontextprotocol/sdk` to `^1.17.1`. - Updated various development dependencies to their latest versions. ### Fixed - **Path Sanitization**: Improved path validation in `sanitization.ts` to explicitly disallow null bytes, enhancing security. - **Git Log Parsing**: Corrected the field destructuring in `gitLog/logic.ts` to prevent potential errors when parsing commit bodies. ## v2.3.0 - 2025-07-31 ### Added - **Development Tooling**: - **`tsx`**: Replaced `ts-node` with `tsx` for significantly faster TypeScript execution in development, improving the developer workflow. - **ESLint**: Integrated ESLint with TypeScript support (`typescript-eslint`) to enforce code quality, catch potential errors, and maintain a consistent coding style across the project. A new `eslint.config.js` file has been added. - **TypeDoc**: Added TypeDoc for generating comprehensive API documentation from JSDoc comments. New configuration files (`typedoc.json`, `tsconfig.typedoc.json`, `tsdoc.json`) have been included. - **Scripts**: - Added new npm scripts: `lint`, `lint:fix`, `typecheck`, `dev`, `dev:stdio`, `dev:http`, `audit`, and `audit:fix` to support the new tooling and improve development workflows. - Added `scripts/fetch-openapi-spec.ts` to download and save API specifications. - Added `scripts/README.md` to document the utility scripts. ### Changed - **Core Refactoring**: - **Architectural Alignment**: The entire codebase has been refactored to strictly adhere to the "Logic Throws, Handler Catches" principle, improving separation of concerns and error handling consistency. - **JSDoc**: Added comprehensive JSDoc comments to all core files, tools, utilities, and scripts, enabling clear API documentation and better maintainability. - **Type Safety**: Replaced ambiguous `any` types with specific, inferred types from Zod schemas, enhancing type safety throughout the application. - **Logging & Error Handling**: - **`RequestContext`**: Consistently passed `RequestContext` through the entire call stack for improved traceability and contextual logging. - **`ErrorHandler`**: Centralized error handling to use the `ErrorHandler` utility and structured `McpError` objects for consistent, machine-readable error responses. - **Dependencies**: - Updated all major dependencies, including `@modelcontextprotocol/sdk`, `hono`, `zod`, and `winston`. - Added new development dependencies like `eslint`, `typescript-eslint`, `tsx`, and `typedoc`. ## v2.2.4 - 2025-07-29 ### Added - **Git Working Directory Resource**: Introduced a new resource, `git://working-directory`, which allows clients to retrieve the currently configured working directory for a session. This enhances contextual awareness for tools and agents interacting with the server. ### Changed - **Documentation**: Updated `README.md` to include the new "Resources" section, documenting the `git://working-directory` resource. Also updated the version badge to `2.2.4`. ## v2.2.3 - 2025-07-29 ### Added - **Testing Framework**: Initial setup of Vitest testing framework for unit and integration testing. Added initial test setup, configurations (`vitest.config.ts`, `tsconfig.vitest.json`), and coverage reporting. - **Git Signing**: Implemented automatic GPG/SSH signing for commit-creating operations (`git_commit`, `git_merge`, `git_cherry_pick`, `git_tag`) when `GIT_SIGN_COMMITS=true` is set. Includes a fallback to unsigned commits on signing failure. ### Changed - **mcp-ts-template Alignment**: Updated the server to align with the latest changes in the [`mcp-ts-template` v1.7.7](https://github.com/cyanheads/mcp-ts-template/releases/tag/v1.7.7), including improvements to the project structure and configuration. - **Configuration Overhaul**: Completely refactored `src/config/index.ts`. It now uses Zod for robust, type-safe validation of all environment variables, provides clear startup errors for misconfigurations, and automatically determines the project root. - **Authentication Architecture**: Refactored the entire authentication system to use a strategy pattern. - Created `JwtStrategy` and `OauthStrategy` classes implementing a common `AuthStrategy` interface. - A new `authFactory` selects the strategy based on configuration. - A unified `authMiddleware` now delegates verification to the selected strategy, decoupling the transport layer from authentication logic. - **Transport Layer Abstraction**: Decoupled the Hono web server from the MCP SDK's transport logic. - Introduced `StatefulTransportManager` and `StatelessTransportManager` to handle all session and request lifecycle logic. - The Hono `httpTransport` is now a thin layer responsible for routing, middleware, and bridging Hono's web streams with the SDK's Node.js streams. Streamable HTTP should work much better now. - This refactoring resulted in a major file reorganization within `src/mcp-server/transports/`. - **Error Handling**: Improved the `ErrorHandler` to prevent mutation of original error objects and added several new `BaseErrorCode`s for more precise error reporting. ### Dependencies - **Added**: `vitest`, `@vitest/coverage-v8`, `supertest`, `msw`, `@faker-js/faker` and other testing-related packages. - **Updated**: `@modelcontextprotocol/sdk` to `^1.17.0`, `hono` to `^4.8.10`, and various other dependencies. ## v2.2.1 - 2025-07-17 ### Changed - **Error Handling Refactor**: Executed a comprehensive, mandatory refactoring across all Git tools to strictly enforce the "Logic Throws, Handler Catches" architectural principle. All `try...catch` blocks have been removed from the `logic.ts` files. The logic layer now exclusively throws structured `McpError`s on failure, while the `registration.ts` handler layer is solely responsible for catching and processing these errors. This ensures a clean separation of concerns and standardizes the error handling pipeline. - **Structured Error Responses**: Updated all tool registration handlers to return a structured error object in the `structuredContent` field upon failure, including the `code`, `message`, and `details` of the `McpError`. This provides richer, machine-readable error context to the MCP client. - **Dependency Updates**: Updated `@modelcontextprotocol/sdk` to `^1.16.0` and `openai` to `^5.10.1`. - **Configuration**: Added `zod` to the reject list in `.ncurc.json` to prevent unintended upgrades. ## v2.2.0 - 2025-07-16 ### Fixed - **Validation Enforcement**: Corrected a critical flaw in two tool registration handlers (`gitTag`, `gitWorktree`) where the base Zod schema was used for registration instead of the refined schema. This meant that conditional validation rules (e.g., required fields for specific modes) were not being enforced. The handlers now explicitly parse incoming parameters with the full, refined schema, ensuring all validation logic is correctly applied before execution. ### Changed - **Architectural Refactor**: Aligned the entire server with the latest architectural standards and the MCP specification (2025-06-18). This includes: - **Standardized Schemas**: All tools now use explicit Zod schemas for both input and output, ensuring type safety and clear data contracts. This enables structured output, a newer feature of the MCP specification. Not all MCP Clients support structured output so we keep backwards compatibility by returning stringified JSON. - **Logic/Handler Separation**: Core tool logic is now isolated in `logic.ts` files, with error handling managed by a dedicated `ErrorHandler` in the `registration.ts` handlers. This enforces the 'Logic Throws, Handler Catches' principle. - **Simplified State Management**: Removed state accessor initializers in favor of passing `getWorkingDirectory` and `getSessionId` functions directly to tool registration, cleaning up the server initialization process. - **Tool Response Cleanup**: Refactored `git_push` and `git_pull` tools to remove redundant `summary` fields from their output, providing a cleaner and more concise response. - **Tool Annotations**: Added descriptive annotations to all tool registrations to provide richer metadata to the client/LLM, improving tool discovery and usage. ### Dependencies - Updated the following dependencies: - `@modelcontextprotocol/sdk` to `^1.15.1` - `@hono/node-server` to `^1.16.0` - `@types/node` to `^24.0.14` - `hono` to `^4.8.5` - `jose` to `^6.0.12` - `openai` to `^5.9.2` - Updated the following devDependencies: - `typedoc` to `^0.28.7` ## v2.1.8 - 2025-06-29 ### Fixed - Downgraded `dotenv` to `^16.6.1` to suppress `dotenvx` promotional logging messages in v17.0 that were interfering with the stdio transport. - Added `dotenv` to the `reject` list in `.ncurc.json` to prevent future automatic upgrades to problematic versions. ## v2.1.7 - 2025-06-29 ### Changed - Suppressed `dotenv` debug output to prevent interference with the stdio transport. - Updated the fallback package name in the configuration for better error identification. ## v2.1.6 - 2025-06-29 ### Dependencies - Updated the following dependencies: - `@modelcontextprotocol/sdk` to `^1.13.2` - `@types/node` to `^24.0.7` - `dotenv` to `^17.0.0` - `hono` to `^4.8.3` - `openai` to `^5.8.2` - `winston-transport` to `^4.9.0` - Updated the following devDependencies: - `prettier` to `^3.6.2` - `typedoc` to `^0.28.6` ### Changed - Minor formatting changes across several files. ## v2.1.5 - 2025-06-29 ### Security - Patched a command injection vulnerability where unsanitized user input could be passed to `child_process.exec`. All `exec` calls have been replaced with the safer `execFile` method, which treats arguments as distinct values rather than executable script parts. Thank you to [@dellalibera](https://github.com/dellalibera) for the disclosure. For more details, see the security advisory: [GHSA-3q26-f695-pp76](https://github.com/cyanheads/git-mcp-server/security/advisories/GHSA-3q26-f695-pp76). ## v2.1.4 - 2025-06-20 ### Changed - **HTTP Transport Layer**: Migrated the entire HTTP transport from Express to Hono for improved performance and a more modern API. This includes new middleware for CORS, rate limiting, and error handling. - **Authentication Architecture**: Refactored the authentication system into a modular, strategy-based architecture. - Supports both JWT and OAuth 2.1 bearer token validation. - Configuration is managed via `MCP_AUTH_MODE` environment variable. - Uses `AsyncLocalStorage` for safer, context-aware access to authentication info. - **Session Management**: Simplified session state management by centralizing the working directory logic within the main server instance, removing transport-specific state handlers. ## v2.1.3 - 2025-06-20 ### Changed - (docs) Updated `README.md` to improve clarity, add a core capabilities table, and reflect new dependency versions. - (docs) Updated `README.md` installation instructions to recommend `npx` for easier setup. ### Dependencies - Updated the following dependencies: - `@modelcontextprotocol/inspector` to `^0.14.3` - `@modelcontextprotocol/sdk` to `^1.13.0` - `@types/jsonwebtoken` to `^9.0.10` - `@types/node` to `^24.0.3` - `@types/validator` to `^13.15.2` - `openai` to `^5.6.0` - `zod` to `^3.25.67` ## v2.1.2 - 2025-06-14 ### Fixed - (tools) `gitCommit` tool now provides a specific, clearer error message when a pre-commit hook fails, preventing confusion with merge conflicts. (Addresses GitHub Issue [#13](https://github.com/cyanheads/git-mcp-server/issues/13)) ### Changed - (tools) Refactored error handling across all Git tools to use structured `McpError` exceptions with specific `BaseErrorCode`s (e.g., `CONFLICT`, `NOT_FOUND`, `VALIDATION_ERROR`) instead of returning `{ success: false, ... }` objects. This provides more consistent and machine-readable error responses. - (tools) Improved logging across all Git tools for better traceability and debugging, ensuring structured context is always included. - (tools) Refined success and result objects for several tools (`gitPull`, `gitPush`, `gitMerge`, etc.) to be more consistent and structured. ### Dependencies - Updated the following dependencies: - `@modelcontextprotocol/inspector` to `^0.14.1` - `@modelcontextprotocol/sdk` to `^1.12.3` ## v2.1.1 - 2025-06-13 ### Changed - (docs) Updated `README.md` to reflect the new version `2.1.1`. - (docs) Updated `git_wrapup_instructions` tool description for clarity. - (docs) Updated `git_wrapup_instructions` tool logic to include a prompt for the agent. ### Dependencies - Updated the following dependencies: - `@modelcontextprotocol/inspector` to `^0.14.0` - `@types/node` to `^24.0.1` - `openai` to `^5.3.0` - `zod` to `^3.25.64` - `@types/express` to `^5.0.3` (devDependency) ### Other - Bump version to 2.1.1. ## v2.1.0 - 2025-06-03 ### Changed - (tools) `gitStatus` tool: - Reworked JSON output structure to provide more detailed and categorized information for staged and unstaged changes (e.g., `Added`, `Modified`, `Deleted` arrays under `staged_changes` and `unstaged_changes`). - Updated tool description to accurately reflect the new, richer output format. - (tools) `gitWrapupInstructions` tool: - Now includes the full JSON output of the `git_status` tool in its own result, providing immediate context on repository status when initiating a wrap-up. - Updated internal logic to fetch and integrate the `git_status` output. - Enhanced registration to initialize and utilize necessary session state accessors (`getWorkingDirectory`, `getSessionId`) for fetching Git status. - (core) `server.ts`: Added initialization call for `gitWrapupInstructionsStateAccessors` to ensure the tool has access to session-specific context. - (docs) `docs/tree.md`: Updated timestamp. ### Dependencies - Updated the following dependencies: - `@types/node` to `^22.15.29` - `ignore` to `^7.0.5` - `openai` to `^5.0.2` - `zod` to `^3.25.49` ### Other - Bump version to 2.1.0. ## v2.0.15 - 2025-05-30 ### Changed - (deps) Updated `@modelcontextprotocol/sdk` to `^1.12.1`. - (deps) Downgraded `chrono-node` from `2.8.1` to `2.8.0`. - (tools) Refined the instructional text within the `git_wrapup_instructions` tool for clarity and better formatting. - (docs) Updated `README.md` to reflect new SDK version and project version. - (docs) Updated `docs/tree.md` to reflect current project structure and new files. ### Added - (config) Added `.ncurc.json` to specify `chrono-node` as a rejected update, pinning it to `2.8.0`. ### Other - Bump version to 2.0.15. ## v2.0.14 - 2025-05-30 ### Changed - (tools) `git_diff` tool now supports an `includeUntracked` boolean parameter. If true, the diff output will also include the content of untracked files by comparing them against `/dev/null`. - (docs) Updated `README.md` to reflect the new `includeUntracked` parameter in `git_diff` tool description and arguments table. - (docs) Updated version badge in `README.md` to `v2.0.14`. - (docs) Updated version in `README.md` Resources section to `v2.0.14`. ### Other - Bump version to 2.0.14. ## v2.0.13 - 2025-05-30 ### Added - (tools) Added `git_wrapup_instructions` tool to provide a standard Git wrap-up workflow, including reviewing changes, updating documentation (README, CHANGELOG), and making logical commits. - (core) Integrated the `git_wrapup_instructions` tool into the server by adding its registration in `src/mcp-server/server.ts`. ### Changed - (docs) Updated `README.md` to include the new `git_wrapup_instructions` tool in the tools table. ### Other - Bump version to 2.0.13 (implicitly). ## v2.0.12 - 2025-05-25 ### Added - (tools) Added `git_worktree` tool to manage Git worktrees, including listing, adding, removing, moving, and pruning. - (tools) `gitSetWorkingDir` tool can now optionally initialize a new Git repository with `git init --initial-branch=main` if `initializeIfNotPresent: true` is set and the target directory is not already a Git repository. ### Changed - (tools) `gitInit` tool now defaults the initial branch to `main` if no `initialBranch` is specified in the input. - (security) Refactored `authMiddleware.ts` to align with MCP SDK's `AuthInfo` type, improving JWT claim handling for `clientId` and `scopes`. Invalid or missing scopes now default to an empty array. - (deps) Updated various dependencies, including: - `@modelcontextprotocol/inspector` to `^0.13.0` - `@modelcontextprotocol/sdk` to `^1.12.0` - `@types/node` to `^22.15.21` - `@types/validator` to `^13.15.1` - `openai` to `^4.103.0` - `zod` to `^3.25.28` - `@types/express` to `^5.0.2` (devDependency) - (docs) Updated `docs/tree.md` to include the new `gitWorktree` tool. - (docs) Updated `README.md` to reflect the new `gitWorktree` tool, changes to `gitInit` and `gitSetWorkingDir`, and updated dependency versions. ### Fixed - (http) Added a workaround in `httpTransport.ts` to sanitize `req.auth` for SDK compatibility, addressing potential type mismatches. ### Other - Bump version to 2.0.12. ## v2.0.11 - 2025-05-14 ### Fixed - (logging) Replaced direct `console.log` calls for server startup messages in HTTP and STDIO transports with `logger.notice()` to ensure MCP client compatibility and prevent parsing issues. (Addresses GitHub Issue #9) - (logging) Refactored internal logger (`utils/internal/logger.ts`): - Deferred informational setup messages (e.g., logs directory creation, console logging status) to use the logger's own `info()` method after Winston is initialized. - Made critical pre-initialization `console.error` and `console.warn` calls conditional on TTY to prevent non-JSONRPC output when running in stdio mode with an MCP client. - Extracted console formatting logic into a reusable helper function (`createWinstonConsoleFormat`) to reduce duplication. - Added comments explaining TTY-conditional logging for clarity. ### Changed - (chore) Updated various dependencies (e.g., `@modelcontextprotocol/sdk`, `@types/node`, `openai`). - (docs) Refreshed `docs/tree.md` to include `mcp.json` and reflect current structure. ### Other - Bump version to 2.0.11. ## v2.0.10 - 2025-05-07 ### Added - (dev) Added MCP Inspector configuration (`mcp.json`) to define server settings for `git-mcp-server` and `git-mcp-server-http` when using the inspector. (bf3a164) - (dev) Added npm scripts `inspector` and `inspector:http` to easily launch the MCP Inspector with the defined configurations. (bf3a164) ### Dependencies - Added `@modelcontextprotocol/inspector: ^0.11.0` to `dependencies`. (bf3a164) ### Changed - (docs) Updated version badge in `README.md` to `2.0.10`. (bf3a164) ### Other - Bump version to 2.0.10. (bf3a164) ## v2.0.9 - 2025-05-07 ### Added - (gitLog) Group commit logs by author in the JSON response, providing a more structured view of commit history. (5b5e037) ### Changed - (security) Refactored path sanitization (`sanitizePath`) across all tools to use an object response (`SanitizedPathInfo`), improving robustness and providing more context. This includes updated JSDoc, standardized error handling within sanitization, and minor refactors to other sanitization functions. (5b5e037) - (gitDiff) The 'diff' field in the `gitDiff` tool's response now includes the string "No changes found." directly when no differences are detected, ensuring consistent output format. (5b5e037) ### Other - Bump version to 2.0.9. (bfe23ea) ## v2.0.8 - 2025-05-07 ### Fixed - Resolved issue where Windows drive letters could be stripped from absolute paths during sanitization when `allowAbsolute` was not explicitly true. This primarily affected `git_set_working_dir` and other tools when absolute paths were provided. The `sanitizePath` calls in git tool logic now correctly pass `{ allowAbsolute: true }`. Fixes GitHub Issue #8. (`6f405a1`) ### Changed - (security) Update `sanitizePath` calls in all git tool logic to explicitly pass `{ allowAbsolute: true }` ensuring correct handling of absolute paths. (`6f405a1`) ### Dependencies - Update `@types/node` from `^22.15.9` to `^22.15.15`. (`c28fe86`) ### Other - Bump version to 2.0.8 (implicitly, as part of user's update process and reflected in package.json by commit `c28fe86` which was intended for 2.0.7 but now aligns with 2.0.8) ## v2.0.5 - 2025-05-05 ### Added - (tools) Enhance `git_commit` tool result to include commit message and committed files list (`1f74915`) ### Changed - (core) Alphabetize tool imports and initializers in `server.ts` for better organization (`1f74915`) - (docs) Refine `git_commit` tool description for clarity (`1f74915`) ### Other - Bump version to 2.0.5 (`1f74915`) ## v2.0.4 - 2025-05-05 - (docs): Added smithery.yaml ## v2.0.3 - 2025-05-05 ### Added - (tools) Enhance git_commit escaping & add showSignature to git_log (`312d431`) ### Changed - (core) Update server logic and configuration (`75b6683`) - (tools) Update git tool implementations (`8b9ddaf`) - (transport) Update transport implementations and add auth middleware (`a043d20`) - (internal) Consolidate utilities and update types (`051ad9f`) - Reorganize utilities and server transport handling (`b5c5840`) ### Documentation - Update project structure in README and tree (`bc8f033`) - (signing) Improve commit signing docs and add fallback logic (`de28bef`) - Update README and file tree, remove temporary diff file (`3f86039`) ### Other - **test**: Test automatic commit signing (commit.gpgsign=true) (`ef094d3`) - **chore**: Update dependencies (`3cb662a`)