@cyanheads/git-mcp-server 2.4.6 → 2.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +75 -10
  2. package/dist/index.js +290 -107
  3. package/package.json +23 -27
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  <div align="center">
9
9
 
10
- [![Version](https://img.shields.io/badge/Version-2.4.5-blue.svg?style=flat-square)](./CHANGELOG.md) [![MCP Spec](https://img.shields.io/badge/MCP%20Spec-2025--06--18-8A2BE2.svg?style=flat-square)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-06-18/changelog.mdx) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.20.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Status](https://img.shields.io/badge/Status-Stable-brightgreen.svg?style=flat-square)](https://github.com/cyanheads/git-mcp-server/issues) [![TypeScript](https://img.shields.io/badge/TypeScript-^5.9.3-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.2.21-blueviolet.svg?style=flat-square)](https://bun.sh/)
10
+ [![Version](https://img.shields.io/badge/Version-2.4.8-blue.svg?style=flat-square)](./CHANGELOG.md) [![MCP Spec](https://img.shields.io/badge/MCP%20Spec-2025--06--18-8A2BE2.svg?style=flat-square)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-06-18/changelog.mdx) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.20.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Status](https://img.shields.io/badge/Status-Stable-brightgreen.svg?style=flat-square)](https://github.com/cyanheads/git-mcp-server/issues) [![TypeScript](https://img.shields.io/badge/TypeScript-^5.9.3-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.2.21-blueviolet.svg?style=flat-square)](https://bun.sh/)
11
11
 
12
12
  </div>
13
13
 
@@ -30,25 +30,38 @@ This server provides 27 comprehensive Git operations organized into six function
30
30
 
31
31
  The server provides resources that offer contextual information about the Git environment:
32
32
 
33
- | Resource | URI | Description |
34
- | :---------------------- | :------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------- |
33
+ | Resource | URI | Description |
34
+ | :------------------------ | :------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------- |
35
35
  | **Git Working Directory** | `git://working-directory` | Provides the current session working directory for git operations. This is the directory set via `git_set_working_dir` and used as the default. |
36
36
 
37
37
  ## 🎯 Prompts Overview
38
38
 
39
39
  The server provides structured prompt templates that guide AI agents through complex workflows:
40
40
 
41
- | Prompt | Description | Parameters |
42
- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- |
41
+ | Prompt | Description | Parameters |
42
+ | :-------------- | :----------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------- |
43
43
  | **Git Wrap-up** | A systematic workflow protocol for completing git sessions. Guides agents through reviewing, documenting, committing, and tagging changes. | `changelogPath`, `skipDocumentation`, `createTag`, and `updateAgentFiles`. |
44
44
 
45
45
  ## 🚀 Getting Started
46
46
 
47
+ ### Runtime Compatibility
48
+
49
+ This server works with **both Bun and Node.js runtimes**:
50
+
51
+ | Runtime | Command | Minimum Version | Notes |
52
+ | ----------- | --------------------------------------- | --------------- | ---------------------------------------- |
53
+ | **Bun** | `bunx @cyanheads/git-mcp-server@latest` | ≥ 1.2.0 | Native Bun runtime (optimal performance) |
54
+ | **Node.js** | `npx @cyanheads/git-mcp-server@latest` | ≥ 20.0.0 | Via npx/bunx (universal compatibility) |
55
+
56
+ The server automatically detects the runtime and uses the appropriate process spawning method for git operations.
57
+
47
58
  ### MCP Client Settings/Configuration
48
59
 
49
60
  Add the following to your MCP Client configuration file (e.g., `cline_mcp_settings.json`). Clients have different ways to configure servers, so refer to your client's documentation for specifics.
50
61
 
51
- ** Be sure to update environment variables as needed (especially your Git information!) **
62
+ **Be sure to update environment variables as needed (especially your Git information!)**
63
+
64
+ #### Using Bun (bunx)
52
65
 
53
66
  ```json
54
67
  {
@@ -71,7 +84,31 @@ Add the following to your MCP Client configuration file (e.g., `cline_mcp_settin
71
84
  }
72
85
  ```
73
86
 
74
- Or for Streamable HTTP:
87
+ #### Using Node.js (npx)
88
+
89
+ ```json
90
+ {
91
+ "mcpServers": {
92
+ "git-mcp-server": {
93
+ "type": "stdio",
94
+ "command": "npx",
95
+ "args": ["@cyanheads/git-mcp-server@latest"],
96
+ "env": {
97
+ "MCP_TRANSPORT_TYPE": "stdio",
98
+ "MCP_LOG_LEVEL": "info",
99
+ "GIT_MCP_BASE_DIR": "~/Developer/",
100
+ "LOGS_DIR": "~/Developer/logs/git-mcp-server/",
101
+ "GIT_USERNAME": "cyanheads",
102
+ "GIT_EMAIL": "casey@caseyjhand.com",
103
+ "GIT_SIGN_COMMITS": "false"
104
+ }
105
+ }
106
+ }
107
+ }
108
+ ```
109
+
110
+ #### Streamable HTTP Configuration
111
+
75
112
  ```bash
76
113
  MCP_TRANSPORT_TYPE=http
77
114
  MCP_HTTP_PORT=3015
@@ -91,8 +128,9 @@ This server is built on the [`mcp-ts-template`](https://github.com/cyanheads/mcp
91
128
 
92
129
  Plus, specialized features for **Git integration**:
93
130
 
131
+ - **Cross-Runtime Compatibility**: Works seamlessly with both Bun and Node.js runtimes. Automatically detects the runtime and uses optimal process spawning (Bun.spawn in Bun, child_process.spawn in Node.js).
94
132
  - **Provider-Based Architecture**: Pluggable git provider system with current CLI implementation and planned isomorphic-git provider for edge deployment.
95
- - **Optimized Git Execution**: Direct git CLI interaction via Bun.spawn for high-performance process management with streaming I/O and timeout handling (current CLI provider).
133
+ - **Optimized Git Execution**: Direct git CLI interaction with cross-runtime support for high-performance process management, streaming I/O, and timeout handling (current CLI provider).
96
134
  - **Comprehensive Coverage**: 27 tools covering all essential Git operations from init to push.
97
135
  - **Working Directory Management**: Session-specific directory context for multi-repo workflows.
98
136
  - **Safety Features**: Explicit confirmations for destructive operations like `git clean` and `git reset --hard`.
@@ -102,9 +140,11 @@ Plus, specialized features for **Git integration**:
102
140
 
103
141
  ### Prerequisites
104
142
 
105
- - [Bun v1.2.0](https://bun.sh/) or higher
143
+ - **Either** [Bun v1.2.0+](https://bun.sh/) **OR** [Node.js v20.0.0+](https://nodejs.org/)
106
144
  - [Git](https://git-scm.com/) installed and accessible in your system PATH
107
145
 
146
+ > **Note**: Development uses Bun for the best experience, but the published package works with both Bun (`bunx`) and Node.js (`npx`).
147
+
108
148
  ### Installation
109
149
 
110
150
  1. **Clone the repository:**
@@ -121,10 +161,18 @@ cd git-mcp-server
121
161
 
122
162
  3. **Install dependencies:**
123
163
 
164
+ **With Bun (recommended for development):**
165
+
124
166
  ```sh
125
167
  bun install
126
168
  ```
127
169
 
170
+ **With Node.js:**
171
+
172
+ ```sh
173
+ npm install
174
+ ```
175
+
128
176
  ## ⚙️ Configuration
129
177
 
130
178
  All configuration is centralized and validated at startup in `src/config/index.ts`. Key environment variables in your `.env` file include:
@@ -150,6 +198,24 @@ All configuration is centralized and validated at startup in `src/config/index.t
150
198
 
151
199
  ## ▶️ Running the Server
152
200
 
201
+ ### For End Users (via Package Manager)
202
+
203
+ The easiest way to use the server is via `bunx` or `npx` (no installation required):
204
+
205
+ **With Bun:**
206
+
207
+ ```sh
208
+ bunx @cyanheads/git-mcp-server@latest
209
+ ```
210
+
211
+ **With Node.js:**
212
+
213
+ ```sh
214
+ npx @cyanheads/git-mcp-server@latest
215
+ ```
216
+
217
+ Both commands work identically and are configured through environment variables or your MCP client configuration.
218
+
153
219
  ### Local Development
154
220
 
155
221
  - **Build and run the production version**:
@@ -212,7 +278,6 @@ bun deploy:prod
212
278
  | `src/config` | Environment variable parsing and validation with Zod. |
213
279
  | `tests/` | Unit and integration tests, mirroring the `src/` directory structure. |
214
280
 
215
-
216
281
  ## 📤 Understanding Tool Responses
217
282
 
218
283
  This server follows MCP's dual-output architecture for all tools ([MCP Tools Specification](https://modelcontextprotocol.io/specification/2025-06-18/server/tools)):
package/dist/index.js CHANGED
@@ -4246,9 +4246,9 @@ var package_default;
4246
4246
  var init_package = __esm(() => {
4247
4247
  package_default = {
4248
4248
  name: "@cyanheads/git-mcp-server",
4249
- version: "2.4.4",
4249
+ version: "2.4.7",
4250
4250
  mcpName: "io.github.cyanheads/git-mcp-server",
4251
- description: "An MCP (Model Context Protocol) server enabling LLMs and AI agents to interact with Git repositories. Provides tools for comprehensive Git operations including clone, commit, branch, diff, log, status, push, pull, merge, rebase, worktree, tag management, and more, via the MCP standard. STDIO & HTTP.",
4251
+ description: "A secure and scalable Git MCP server enabling AI agents to perform comprehensive Git version control operations via STDIO and Streamable HTTP.",
4252
4252
  main: "dist/index.js",
4253
4253
  files: [
4254
4254
  "dist"
@@ -4308,7 +4308,7 @@ var init_package = __esm(() => {
4308
4308
  "@hono/node-server": "1.19.5",
4309
4309
  "chrono-node": "2.9.0",
4310
4310
  dotenv: "17.2.3",
4311
- hono: "4.9.10",
4311
+ hono: "4.9.12",
4312
4312
  zod: "3.23.8",
4313
4313
  typescript: "5.9.3"
4314
4314
  },
@@ -4321,7 +4321,7 @@ var init_package = __esm(() => {
4321
4321
  "chrono-node": "^2.9.0",
4322
4322
  dotenv: "^17.2.3",
4323
4323
  "fast-xml-parser": "^5.3.0",
4324
- hono: "^4.9.10",
4324
+ hono: "^4.9.12",
4325
4325
  ignore: "^7.0.5",
4326
4326
  jose: "^6.1.0",
4327
4327
  "js-yaml": "^4.1.0",
@@ -4333,7 +4333,7 @@ var init_package = __esm(() => {
4333
4333
  pino: "^10.0.0",
4334
4334
  "pino-pretty": "^13.1.2",
4335
4335
  "reflect-metadata": "^0.2.2",
4336
- repomix: "^1.6.1",
4336
+ repomix: "^1.7.0",
4337
4337
  "sanitize-html": "^2.17.0",
4338
4338
  tslib: "^2.8.1",
4339
4339
  tsyringe: "^4.10.0",
@@ -4355,7 +4355,7 @@ var init_package = __esm(() => {
4355
4355
  "@eslint/js": "^9.37.0",
4356
4356
  "@types/bun": "^1.3.0",
4357
4357
  "@types/js-yaml": "^4.0.9",
4358
- "@types/node": "^24.7.1",
4358
+ "@types/node": "^24.7.2",
4359
4359
  "@types/node-cron": "^3.0.11",
4360
4360
  "@types/papaparse": "^5.3.16",
4361
4361
  "@types/sanitize-html": "^2.16.0",
@@ -4375,23 +4375,14 @@ var init_package = __esm(() => {
4375
4375
  typedoc: "^0.28.14",
4376
4376
  typescript: "^5.9.3",
4377
4377
  "typescript-eslint": "8.46.0",
4378
- vite: "7.1.7",
4378
+ vite: "7.1.9",
4379
4379
  "vite-tsconfig-paths": "^5.1.4",
4380
4380
  vitest: "^3.2.4"
4381
4381
  },
4382
4382
  keywords: [
4383
- "typescript",
4384
- "MCP",
4385
- "model-context-protocol",
4386
- "mcp-server",
4387
- "llm-tools",
4388
- "git-tools",
4389
- "LLM",
4390
- "AI-integration",
4391
- "server",
4392
- "git",
4393
- "version-control",
4394
- "repository",
4383
+ "ai-agent",
4384
+ "ai-integration",
4385
+ "automation",
4395
4386
  "branch",
4396
4387
  "cherry-pick",
4397
4388
  "clone",
@@ -4399,8 +4390,15 @@ var init_package = __esm(() => {
4399
4390
  "devops",
4400
4391
  "diff",
4401
4392
  "fetch",
4393
+ "git",
4394
+ "git-tools",
4395
+ "llm",
4396
+ "llm-tools",
4402
4397
  "log",
4398
+ "mcp",
4399
+ "mcp-server",
4403
4400
  "merge",
4401
+ "model-context-protocol",
4404
4402
  "pull",
4405
4403
  "push",
4406
4404
  "rebase",
@@ -4409,9 +4407,9 @@ var init_package = __esm(() => {
4409
4407
  "stash",
4410
4408
  "status",
4411
4409
  "tag",
4412
- "worktree",
4413
- "ai-agent",
4414
- "automation"
4410
+ "typescript",
4411
+ "version-control",
4412
+ "worktree"
4415
4413
  ],
4416
4414
  author: "cyanheads <casey@caseyjhand.com> (https://github.com/cyanheads/git-mcp-server#readme)",
4417
4415
  license: "Apache-2.0",
@@ -101618,23 +101616,55 @@ var init_error_handler = __esm(() => {
101618
101616
  });
101619
101617
 
101620
101618
  // src/utils/internal/runtime.ts
101619
+ function detectRuntime() {
101620
+ if (runtimeCaps.isBun) {
101621
+ return "bun";
101622
+ }
101623
+ if (runtimeCaps.isNode) {
101624
+ return "node";
101625
+ }
101626
+ if (runtimeCaps.isWorkerLike) {
101627
+ return "worker";
101628
+ }
101629
+ if (runtimeCaps.isBrowserLike) {
101630
+ return "browser";
101631
+ }
101632
+ return "unknown";
101633
+ }
101634
+ function getRuntimeDescription() {
101635
+ const runtime = detectRuntime();
101636
+ switch (runtime) {
101637
+ case "bun":
101638
+ return `Bun ${process.versions?.bun || "unknown"}`;
101639
+ case "node":
101640
+ return `Node.js ${process.versions?.node || "unknown"}`;
101641
+ case "worker":
101642
+ return "Cloudflare Workers / Web Worker";
101643
+ case "browser":
101644
+ return "Browser";
101645
+ default:
101646
+ return "Unknown runtime";
101647
+ }
101648
+ }
101621
101649
  var safeHas = (key) => {
101622
101650
  try {
101623
101651
  return typeof globalThis[key] !== "undefined";
101624
101652
  } catch {
101625
101653
  return false;
101626
101654
  }
101627
- }, isNode, hasProcess, hasBuffer, hasTextEncoder, hasPerformanceNow, isWorkerLike, isBrowserLike, runtimeCaps;
101655
+ }, isBun, isNode, hasProcess, hasBuffer, hasTextEncoder, hasPerformanceNow, isWorkerLike, isBrowserLike, runtimeCaps;
101628
101656
  var init_runtime = __esm(() => {
101629
- isNode = typeof process !== "undefined" && typeof process.versions?.node === "string";
101657
+ isBun = typeof globalThis.Bun !== "undefined" || typeof process.versions?.bun === "string";
101658
+ isNode = !isBun && typeof process !== "undefined" && typeof process.versions?.node === "string";
101630
101659
  hasProcess = typeof process !== "undefined";
101631
101660
  hasBuffer = typeof Buffer !== "undefined";
101632
101661
  hasTextEncoder = safeHas("TextEncoder");
101633
101662
  hasPerformanceNow = typeof globalThis.performance?.now === "function";
101634
- isWorkerLike = !isNode && typeof globalThis.WorkerGlobalScope !== "undefined";
101635
- isBrowserLike = !isNode && !isWorkerLike && safeHas("window");
101663
+ isWorkerLike = !isNode && !isBun && typeof globalThis.WorkerGlobalScope !== "undefined";
101664
+ isBrowserLike = !isNode && !isBun && !isWorkerLike && safeHas("window");
101636
101665
  runtimeCaps = {
101637
101666
  isNode,
101667
+ isBun,
101638
101668
  isWorkerLike,
101639
101669
  isBrowserLike,
101640
101670
  hasProcess,
@@ -135725,10 +135755,12 @@ __export(exports_utils, {
135725
135755
  jsonParser: () => jsonParser,
135726
135756
  initializePerformance_Hrt: () => initializePerformance_Hrt,
135727
135757
  idGenerator: () => idGenerator,
135758
+ getRuntimeDescription: () => getRuntimeDescription,
135728
135759
  getHealthSnapshot: () => getHealthSnapshot,
135729
135760
  generateUUID: () => generateUUID,
135730
135761
  generateRequestContextId: () => generateRequestContextId,
135731
135762
  fetchWithTimeout: () => fetchWithTimeout,
135763
+ detectRuntime: () => detectRuntime,
135732
135764
  degrees: () => import_pdf_lib.degrees,
135733
135765
  dateParser: () => dateParser,
135734
135766
  csvParser: () => csvParser,
@@ -151548,6 +151580,7 @@ async function shutdownOpenTelemetry() {
151548
151580
  var import_reflect_metadata2 = __toESM(require_Reflect(), 1);
151549
151581
  init_utils();
151550
151582
  init_logger();
151583
+ init_runtime();
151551
151584
 
151552
151585
  // src/container/index.ts
151553
151586
  var import_reflect_metadata = __toESM(require_Reflect(), 1);
@@ -151827,32 +151860,98 @@ function isGitNotFoundError(error) {
151827
151860
  return message.includes("git") && (message.includes("not found") || message.includes("enoent") || message.includes("command not found"));
151828
151861
  }
151829
151862
 
151830
- // src/services/git/providers/cli/utils/git-executor.ts
151831
- var GIT_COMMAND_TIMEOUT_MS = 60000;
151832
- async function executeGitCommand(args, cwd) {
151833
- try {
151834
- validateGitArgs(args);
151835
- const proc = Bun.spawn(["git", ...args], {
151863
+ // src/services/git/providers/cli/utils/runtime-adapter.ts
151864
+ import { spawn } from "node:child_process";
151865
+ function detectRuntime2() {
151866
+ if (typeof globalThis.Bun !== "undefined") {
151867
+ return "bun";
151868
+ }
151869
+ if (process.versions?.bun) {
151870
+ return "bun";
151871
+ }
151872
+ return "node";
151873
+ }
151874
+ async function spawnWithBun(args, cwd, env, timeout) {
151875
+ const bunApi = globalThis.Bun;
151876
+ const proc = bunApi.spawn(["git", ...args], {
151877
+ cwd,
151878
+ env,
151879
+ stdio: ["ignore", "pipe", "pipe"]
151880
+ });
151881
+ const timeoutPromise = new Promise((_, reject) => {
151882
+ const timeoutId = setTimeout(() => {
151883
+ proc.kill();
151884
+ reject(new Error(`Git command timed out after ${timeout / 1000}s: git ${args.join(" ")}`));
151885
+ }, timeout);
151886
+ proc.exited.finally(() => clearTimeout(timeoutId));
151887
+ });
151888
+ const exitCode = await Promise.race([proc.exited, timeoutPromise]);
151889
+ const [stdout, stderr] = await Promise.all([
151890
+ proc.stdout.text(),
151891
+ proc.stderr.text()
151892
+ ]);
151893
+ if (exitCode !== 0) {
151894
+ const combinedOutput = `Exit Code: ${exitCode}
151895
+ Stderr: ${stderr}
151896
+ Stdout: ${stdout}`;
151897
+ throw new Error(combinedOutput);
151898
+ }
151899
+ return { stdout, stderr };
151900
+ }
151901
+ async function spawnWithNode(args, cwd, env, timeout) {
151902
+ return new Promise((resolve, reject) => {
151903
+ const proc = spawn("git", args, {
151836
151904
  cwd,
151837
- env: buildGitEnv(process.env),
151905
+ env,
151838
151906
  stdio: ["ignore", "pipe", "pipe"]
151839
151907
  });
151840
- const stdoutPromise = Bun.readableStreamToText(proc.stdout);
151841
- const stderrPromise = Bun.readableStreamToText(proc.stderr);
151842
- const timeoutPromise = new Promise((_, reject) => setTimeout(() => {
151843
- proc.kill();
151844
- reject(new Error(`Git command timed out after ${GIT_COMMAND_TIMEOUT_MS / 1000}s: ${args.join(" ")}`));
151845
- }, GIT_COMMAND_TIMEOUT_MS));
151846
- const exitCode = await Promise.race([proc.exited, timeoutPromise]);
151847
- const stdout = await stdoutPromise;
151848
- const stderr = await stderrPromise;
151849
- if (exitCode !== 0) {
151850
- const combinedOutput = `Exit Code: ${exitCode}
151908
+ const stdoutChunks = [];
151909
+ const stderrChunks = [];
151910
+ proc.stdout.on("data", (chunk) => {
151911
+ stdoutChunks.push(chunk);
151912
+ });
151913
+ proc.stderr.on("data", (chunk) => {
151914
+ stderrChunks.push(chunk);
151915
+ });
151916
+ const timeoutHandle = setTimeout(() => {
151917
+ proc.kill("SIGTERM");
151918
+ reject(new Error(`Git command timed out after ${timeout / 1000}s: ${args.join(" ")}`));
151919
+ }, timeout);
151920
+ proc.on("error", (error) => {
151921
+ clearTimeout(timeoutHandle);
151922
+ reject(error);
151923
+ });
151924
+ proc.on("close", (exitCode) => {
151925
+ clearTimeout(timeoutHandle);
151926
+ const stdout = Buffer.concat(stdoutChunks).toString("utf-8");
151927
+ const stderr = Buffer.concat(stderrChunks).toString("utf-8");
151928
+ if (exitCode !== 0) {
151929
+ const combinedOutput = `Exit Code: ${exitCode}
151851
151930
  Stderr: ${stderr}
151852
151931
  Stdout: ${stdout}`;
151853
- throw new Error(combinedOutput);
151854
- }
151855
- return { stdout, stderr };
151932
+ reject(new Error(combinedOutput));
151933
+ } else {
151934
+ resolve({ stdout, stderr });
151935
+ }
151936
+ });
151937
+ });
151938
+ }
151939
+ async function spawnGitCommand(args, cwd, env, timeout = 60000) {
151940
+ const runtime2 = detectRuntime2();
151941
+ if (runtime2 === "bun") {
151942
+ return spawnWithBun(args, cwd, env, timeout);
151943
+ } else {
151944
+ return spawnWithNode(args, cwd, env, timeout);
151945
+ }
151946
+ }
151947
+
151948
+ // src/services/git/providers/cli/utils/git-executor.ts
151949
+ var GIT_COMMAND_TIMEOUT_MS = 60000;
151950
+ async function executeGitCommand(args, cwd) {
151951
+ try {
151952
+ validateGitArgs(args);
151953
+ const result = await spawnGitCommand(args, cwd, buildGitEnv(process.env), GIT_COMMAND_TIMEOUT_MS);
151954
+ return result;
151856
151955
  } catch (error) {
151857
151956
  throw mapGitError(error, args[0] || "unknown");
151858
151957
  }
@@ -152411,6 +152510,14 @@ async function executeBranch(options, context, execGit) {
152411
152510
  ].join(GIT_FIELD_DELIMITER);
152412
152511
  const refPrefix = options.remote ? "refs/remotes" : "refs/heads";
152413
152512
  args.push(`--format=${format}`, refPrefix);
152513
+ if (options.merged !== undefined) {
152514
+ const mergedRef = typeof options.merged === "string" ? options.merged : "HEAD";
152515
+ args.push(`--merged=${mergedRef}`);
152516
+ }
152517
+ if (options.noMerged !== undefined) {
152518
+ const noMergedRef = typeof options.noMerged === "string" ? options.noMerged : "HEAD";
152519
+ args.push(`--no-merged=${noMergedRef}`);
152520
+ }
152414
152521
  const cmd = buildGitCommand({ command: "for-each-ref", args });
152415
152522
  const result = await execGit(cmd, context.workingDirectory, context.requestContext);
152416
152523
  const branches = parseBranchRef(result.stdout);
@@ -165452,7 +165559,7 @@ async function gitWrapupInstructionsLogic(input, { provider, storage, appContext
165452
165559
  let finalInstructions = baseInstructions;
165453
165560
  if (input.updateAgentMetaFiles) {
165454
165561
  finalInstructions += `
165455
- Extra request: review and update if needed the .clinerules and claude.md files if present.`;
165562
+ Extra request: review and update if needed the .cline_rules and claude.md files if present.`;
165456
165563
  }
165457
165564
  if (input.createTag) {
165458
165565
  finalInstructions += `
@@ -165520,6 +165627,29 @@ var gitWrapupInstructionsTool = {
165520
165627
 
165521
165628
  // src/mcp-server/tools/definitions/git-add.tool.ts
165522
165629
  init_lib();
165630
+
165631
+ // src/mcp-server/tools/utils/git-formatters.ts
165632
+ function flattenChanges(changes) {
165633
+ const result = {};
165634
+ if (changes.added && changes.added.length > 0) {
165635
+ result.added = changes.added;
165636
+ }
165637
+ if (changes.modified && changes.modified.length > 0) {
165638
+ result.modified = changes.modified;
165639
+ }
165640
+ if (changes.deleted && changes.deleted.length > 0) {
165641
+ result.deleted = changes.deleted;
165642
+ }
165643
+ if (changes.renamed && changes.renamed.length > 0) {
165644
+ result.renamed = changes.renamed;
165645
+ }
165646
+ if (changes.copied && changes.copied.length > 0) {
165647
+ result.copied = changes.copied;
165648
+ }
165649
+ return result;
165650
+ }
165651
+
165652
+ // src/mcp-server/tools/definitions/git-add.tool.ts
165523
165653
  var TOOL_NAME10 = "git_add";
165524
165654
  var TOOL_TITLE10 = "Git Add";
165525
165655
  var TOOL_DESCRIPTION10 = "Stage files for commit. Add file contents to the staging area (index) to prepare for the next commit.";
@@ -165559,20 +165689,6 @@ async function gitAddLogic(input, { provider, targetPath, appContext }) {
165559
165689
  requestContext: appContext,
165560
165690
  tenantId: appContext.tenantId || "default-tenant"
165561
165691
  });
165562
- const flattenChanges = (changes) => {
165563
- const result2 = {};
165564
- if (changes.added && changes.added.length > 0)
165565
- result2.added = changes.added;
165566
- if (changes.modified && changes.modified.length > 0)
165567
- result2.modified = changes.modified;
165568
- if (changes.deleted && changes.deleted.length > 0)
165569
- result2.deleted = changes.deleted;
165570
- if (changes.renamed && changes.renamed.length > 0)
165571
- result2.renamed = changes.renamed;
165572
- if (changes.copied && changes.copied.length > 0)
165573
- result2.copied = changes.copied;
165574
- return result2;
165575
- };
165576
165692
  return {
165577
165693
  success: result.success,
165578
165694
  stagedFiles: result.stagedFiles,
@@ -165695,20 +165811,6 @@ async function gitCommitLogic(input, { provider, targetPath, appContext }) {
165695
165811
  requestContext: appContext,
165696
165812
  tenantId: appContext.tenantId || "default-tenant"
165697
165813
  });
165698
- const flattenChanges = (changes) => {
165699
- const result2 = {};
165700
- if (changes.added && changes.added.length > 0)
165701
- result2.added = changes.added;
165702
- if (changes.modified && changes.modified.length > 0)
165703
- result2.modified = changes.modified;
165704
- if (changes.deleted && changes.deleted.length > 0)
165705
- result2.deleted = changes.deleted;
165706
- if (changes.renamed && changes.renamed.length > 0)
165707
- result2.renamed = changes.renamed;
165708
- if (changes.copied && changes.copied.length > 0)
165709
- result2.copied = changes.copied;
165710
- return result2;
165711
- };
165712
165814
  return {
165713
165815
  success: result.success,
165714
165816
  commitHash: result.commitHash,
@@ -166057,8 +166159,8 @@ var InputSchema15 = z.object({
166057
166159
  force: ForceSchema,
166058
166160
  all: AllSchema.describe("For list operation: show both local and remote branches."),
166059
166161
  remote: z.boolean().default(false).describe("For list operation: show only remote branches."),
166060
- merged: z.boolean().optional().describe("For list operation: show only branches merged into HEAD."),
166061
- noMerged: z.boolean().optional().describe("For list operation: show only branches not merged into HEAD.")
166162
+ merged: z.union([z.boolean(), CommitRefSchema]).optional().describe("For list operation: show only branches merged into HEAD (true) or specified commit (string)."),
166163
+ noMerged: z.union([z.boolean(), CommitRefSchema]).optional().describe("For list operation: show only branches not merged into HEAD (true) or specified commit (string).")
166062
166164
  });
166063
166165
  var BranchInfoSchema = z.object({
166064
166166
  name: z.string().describe("Branch name."),
@@ -166093,15 +166195,7 @@ async function gitBranchLogic(input, { provider, targetPath, appContext }) {
166093
166195
  };
166094
166196
  }
166095
166197
  }
166096
- const {
166097
- path: _path,
166098
- operation,
166099
- name,
166100
- newName,
166101
- merged: _merged,
166102
- noMerged: _noMerged,
166103
- ...rest
166104
- } = input;
166198
+ const { path: _path, operation, name, newName, ...rest } = input;
166105
166199
  const branchOptions = {
166106
166200
  mode: operation
166107
166201
  };
@@ -166120,6 +166214,12 @@ async function gitBranchLogic(input, { provider, targetPath, appContext }) {
166120
166214
  if (rest.all !== undefined || rest.remote !== undefined) {
166121
166215
  branchOptions.remote = rest.remote || rest.all;
166122
166216
  }
166217
+ if (rest.merged !== undefined) {
166218
+ branchOptions.merged = rest.merged;
166219
+ }
166220
+ if (rest.noMerged !== undefined) {
166221
+ branchOptions.noMerged = rest.noMerged;
166222
+ }
166123
166223
  const result = await provider.branch(branchOptions, {
166124
166224
  workingDirectory: targetPath,
166125
166225
  requestContext: appContext,
@@ -169269,6 +169369,27 @@ var Hono = class {
169269
169369
  };
169270
169370
  };
169271
169371
 
169372
+ // node_modules/hono/dist/router/reg-exp-router/matcher.js
169373
+ var emptyParam = [];
169374
+ function match(method, path4) {
169375
+ const matchers = this.buildAllMatchers();
169376
+ const match2 = (method2, path22) => {
169377
+ const matcher = matchers[method2] || matchers[METHOD_NAME_ALL];
169378
+ const staticMatch = matcher[2][path22];
169379
+ if (staticMatch) {
169380
+ return staticMatch;
169381
+ }
169382
+ const match3 = path22.match(matcher[0]);
169383
+ if (!match3) {
169384
+ return [[], emptyParam];
169385
+ }
169386
+ const index = match3.indexOf("", 1);
169387
+ return [matcher[1][index], match3];
169388
+ };
169389
+ this.match = match2;
169390
+ return match2(method, path4);
169391
+ }
169392
+
169272
169393
  // node_modules/hono/dist/router/reg-exp-router/node.js
169273
169394
  var LABEL_REG_EXP_STR = "[^/]+";
169274
169395
  var ONLY_WILDCARD_REG_EXP_STR = ".*";
@@ -169430,7 +169551,6 @@ var Trie = class {
169430
169551
  };
169431
169552
 
169432
169553
  // node_modules/hono/dist/router/reg-exp-router/router.js
169433
- var emptyParam = [];
169434
169554
  var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
169435
169555
  var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
169436
169556
  function buildWildcardRegExp(path4) {
@@ -169565,30 +169685,14 @@ var RegExpRouter = class {
169565
169685
  });
169566
169686
  }
169567
169687
  }
169568
- match(method, path4) {
169569
- clearWildcardRegExpCache();
169570
- const matchers = this.#buildAllMatchers();
169571
- this.match = (method2, path22) => {
169572
- const matcher = matchers[method2] || matchers[METHOD_NAME_ALL];
169573
- const staticMatch = matcher[2][path22];
169574
- if (staticMatch) {
169575
- return staticMatch;
169576
- }
169577
- const match = path22.match(matcher[0]);
169578
- if (!match) {
169579
- return [[], emptyParam];
169580
- }
169581
- const index = match.indexOf("", 1);
169582
- return [matcher[1][index], match];
169583
- };
169584
- return this.match(method, path4);
169585
- }
169586
- #buildAllMatchers() {
169688
+ match = match;
169689
+ buildAllMatchers() {
169587
169690
  const matchers = /* @__PURE__ */ Object.create(null);
169588
169691
  Object.keys(this.#routes).concat(Object.keys(this.#middleware)).forEach((method) => {
169589
169692
  matchers[method] ||= this.#buildMatcher(method);
169590
169693
  });
169591
169694
  this.#middleware = this.#routes = undefined;
169695
+ clearWildcardRegExpCache();
169592
169696
  return matchers;
169593
169697
  }
169594
169698
  #buildMatcher(method) {
@@ -169611,6 +169715,78 @@ var RegExpRouter = class {
169611
169715
  }
169612
169716
  };
169613
169717
 
169718
+ // node_modules/hono/dist/router/reg-exp-router/prepared-router.js
169719
+ var PreparedRegExpRouter = class {
169720
+ name = "PreparedRegExpRouter";
169721
+ #matchers;
169722
+ #relocateMap;
169723
+ constructor(matchers, relocateMap) {
169724
+ this.#matchers = matchers;
169725
+ this.#relocateMap = relocateMap;
169726
+ }
169727
+ #addWildcard(method, handlerData) {
169728
+ const matcher = this.#matchers[method];
169729
+ matcher[1].forEach((list) => list && list.push(handlerData));
169730
+ Object.values(matcher[2]).forEach((list) => list[0].push(handlerData));
169731
+ }
169732
+ #addPath(method, path4, handler, indexes, map3) {
169733
+ const matcher = this.#matchers[method];
169734
+ if (!map3) {
169735
+ matcher[2][path4][0].push([handler, {}]);
169736
+ } else {
169737
+ indexes.forEach((index) => {
169738
+ if (typeof index === "number") {
169739
+ matcher[1][index].push([handler, map3]);
169740
+ } else {
169741
+ matcher[2][index || path4][0].push([handler, map3]);
169742
+ }
169743
+ });
169744
+ }
169745
+ }
169746
+ add(method, path4, handler) {
169747
+ if (!this.#matchers[method]) {
169748
+ const all = this.#matchers[METHOD_NAME_ALL];
169749
+ const staticMap = {};
169750
+ for (const key in all[2]) {
169751
+ staticMap[key] = [all[2][key][0].slice(), emptyParam];
169752
+ }
169753
+ this.#matchers[method] = [
169754
+ all[0],
169755
+ all[1].map((list) => Array.isArray(list) ? list.slice() : 0),
169756
+ staticMap
169757
+ ];
169758
+ }
169759
+ if (path4 === "/*" || path4 === "*") {
169760
+ const handlerData = [handler, {}];
169761
+ if (method === METHOD_NAME_ALL) {
169762
+ for (const m in this.#matchers) {
169763
+ this.#addWildcard(m, handlerData);
169764
+ }
169765
+ } else {
169766
+ this.#addWildcard(method, handlerData);
169767
+ }
169768
+ return;
169769
+ }
169770
+ const data = this.#relocateMap[path4];
169771
+ if (!data) {
169772
+ throw new Error(`Path ${path4} is not registered`);
169773
+ }
169774
+ for (const [indexes, map3] of data) {
169775
+ if (method === METHOD_NAME_ALL) {
169776
+ for (const m in this.#matchers) {
169777
+ this.#addPath(m, path4, handler, indexes, map3);
169778
+ }
169779
+ } else {
169780
+ this.#addPath(method, path4, handler, indexes, map3);
169781
+ }
169782
+ }
169783
+ }
169784
+ buildAllMatchers() {
169785
+ return this.#matchers;
169786
+ }
169787
+ match = match;
169788
+ };
169789
+
169614
169790
  // node_modules/hono/dist/router/smart-router/router.js
169615
169791
  var SmartRouter = class {
169616
169792
  name = "SmartRouter";
@@ -172351,6 +172527,13 @@ var start = async () => {
172351
172527
  }
172352
172528
  await logger.initialize(validatedMcpLogLevel);
172353
172529
  logger.info(`Logger initialized. Effective MCP logging level: ${validatedMcpLogLevel}.`, requestContextService.createRequestContext({ operation: "LoggerInit" }));
172530
+ const runtime2 = detectRuntime();
172531
+ const runtimeDesc = getRuntimeDescription();
172532
+ logger.info(`Runtime detected: ${runtimeDesc}`, requestContextService.createRequestContext({
172533
+ operation: "RuntimeDetection",
172534
+ runtime: runtime2,
172535
+ runtimeVersion: runtimeDesc
172536
+ }));
172354
172537
  logger.info(`Storage service initialized with provider: ${config2.storage.providerType}`, requestContextService.createRequestContext({ operation: "StorageInit" }));
172355
172538
  transportManager = container_default.resolve(TransportManagerToken);
172356
172539
  const startupContext = requestContextService.createRequestContext({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyanheads/git-mcp-server",
3
- "version": "2.4.6",
3
+ "version": "2.4.8",
4
4
  "mcpName": "io.github.cyanheads/git-mcp-server",
5
5
  "description": "A secure and scalable Git MCP server enabling AI agents to perform comprehensive Git version control operations via STDIO and Streamable HTTP.",
6
6
  "main": "dist/index.js",
@@ -29,44 +29,40 @@
29
29
  },
30
30
  "homepage": "https://github.com/cyanheads/git-mcp-server#readme",
31
31
  "scripts": {
32
- "//--- Development": "",
33
- "dev": "bun --watch src/index.ts",
34
- "dev:http": "MCP_LOG_LEVEL=debug MCP_TRANSPORT_TYPE=http bun --watch src/index.ts",
35
- "dev:stdio": "MCP_LOG_LEVEL=debug MCP_TRANSPORT_TYPE=stdio bun --watch src/index.ts",
36
- "devcheck": "bun run scripts/devcheck.ts",
37
- "devdocs": "bun run scripts/devdocs.ts",
38
- "//--- Build & Deploy": "",
39
- "build": "rm -rf dist && bun build ./src/index.ts --outdir ./dist --target node",
40
- "build:worker": "rm -rf dist && bun build ./src/worker.ts --outdir ./dist --target bun --no-external",
32
+ "build": "bun build ./src/index.ts --outdir ./dist --target node",
33
+ "build:worker": "bun build ./src/worker.ts --outdir ./dist --target bun --no-external",
41
34
  "deploy:dev": "MCP_TRANSPORT_TYPE=http bunx wrangler dev",
42
35
  "deploy:prod": "MCP_TRANSPORT_TYPE=http bunx wrangler deploy",
43
- "//--- Start": "",
44
36
  "start": "bun ./dist/index.js",
45
- "start:http": "MCP_TRANSPORT_TYPE=http bun ./dist/index.js",
46
37
  "start:stdio": "MCP_TRANSPORT_TYPE=stdio bun ./dist/index.js",
47
- "//--- Quality & Maintenance": "",
48
- "audit": "bun audit",
49
- "audit:fix": "bun audit --fix",
38
+ "start:http": "MCP_TRANSPORT_TYPE=http bun ./dist/index.js",
39
+ "dev": "bun --watch src/index.ts",
40
+ "dev:stdio": "MCP_LOG_LEVEL=debug MCP_TRANSPORT_TYPE=stdio bun --watch src/index.ts",
41
+ "dev:http": "MCP_LOG_LEVEL=debug MCP_TRANSPORT_TYPE=http bun --watch src/index.ts",
42
+ "devdocs": "bun run scripts/devdocs.ts",
43
+ "devcheck": "bun run scripts/devcheck.ts",
44
+ "rebuild": "bun run scripts/clean.ts && bun run build",
45
+ "docs:generate": "bunx typedoc",
50
46
  "depcheck": "bunx depcheck",
51
- "format": "bunx prettier --write \"**/*.{ts,js,json,md,html,css}\"",
52
47
  "lint": "bunx eslint .",
53
48
  "lint:fix": "bunx eslint . --fix",
54
- "prepare": "bunx husky",
55
- "test": "bun test --config vitest.config.ts",
56
- "test:coverage": "bun test --coverage",
57
49
  "typecheck": "bunx tsc --noEmit",
58
- "//--- Utilities": "",
59
- "docs:generate": "bunx typedoc",
50
+ "tree": "bun run scripts/tree.ts",
60
51
  "fetch-spec": "bun run scripts/fetch-openapi-spec.ts",
52
+ "format": "bunx prettier --write \"**/*.{ts,js,json,md,html,css}\"",
53
+ "prepare": "bunx husky",
61
54
  "inspector": "bunx mcp-inspector --config mcp.json --server git-mcp-server",
62
- "publish-mcp": "bun scripts/validate-mcp-publish-schema.ts",
63
- "tree": "bun run scripts/tree.ts"
55
+ "test": "bun test --config vitest.config.ts",
56
+ "test:coverage": "bun test --coverage",
57
+ "audit": "bun audit",
58
+ "audit:fix": "bun audit --fix",
59
+ "publish-mcp": "bun scripts/validate-mcp-publish-schema.ts"
64
60
  },
65
61
  "resolutions": {
66
62
  "@hono/node-server": "1.19.5",
67
63
  "chrono-node": "2.9.0",
68
64
  "dotenv": "17.2.3",
69
- "hono": "4.9.10",
65
+ "hono": "4.9.12",
70
66
  "zod": "3.23.8",
71
67
  "typescript": "5.9.3"
72
68
  },
@@ -79,7 +75,7 @@
79
75
  "chrono-node": "^2.9.0",
80
76
  "dotenv": "^17.2.3",
81
77
  "fast-xml-parser": "^5.3.0",
82
- "hono": "^4.9.10",
78
+ "hono": "^4.9.12",
83
79
  "ignore": "^7.0.5",
84
80
  "jose": "^6.1.0",
85
81
  "js-yaml": "^4.1.0",
@@ -91,7 +87,7 @@
91
87
  "pino": "^10.0.0",
92
88
  "pino-pretty": "^13.1.2",
93
89
  "reflect-metadata": "^0.2.2",
94
- "repomix": "^1.6.1",
90
+ "repomix": "^1.7.0",
95
91
  "sanitize-html": "^2.17.0",
96
92
  "tslib": "^2.8.1",
97
93
  "tsyringe": "^4.10.0",
@@ -133,7 +129,7 @@
133
129
  "typedoc": "^0.28.14",
134
130
  "typescript": "^5.9.3",
135
131
  "typescript-eslint": "8.46.0",
136
- "vite": "7.1.7",
132
+ "vite": "7.1.9",
137
133
  "vite-tsconfig-paths": "^5.1.4",
138
134
  "vitest": "^3.2.4"
139
135
  },