@cyanheads/git-mcp-server 2.6.3 → 2.6.5

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 +1 -1
  2. package/dist/index.js +144 -76
  3. package/package.json +6 -6
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.6.2-blue.svg?style=flat-square)](./CHANGELOG.md) [![MCP Spec](https://img.shields.io/badge/MCP%20Spec-2025--11--25-8A2BE2.svg?style=flat-square)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-11-25/changelog.mdx) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.24.3-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.6.5-blue.svg?style=flat-square)](./CHANGELOG.md) [![MCP Spec](https://img.shields.io/badge/MCP%20Spec-2025--11--25-8A2BE2.svg?style=flat-square)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-11-25/changelog.mdx) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.24.3-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
 
package/dist/index.js CHANGED
@@ -14356,7 +14356,7 @@ var package_default;
14356
14356
  var init_package = __esm(() => {
14357
14357
  package_default = {
14358
14358
  name: "@cyanheads/git-mcp-server",
14359
- version: "2.6.2",
14359
+ version: "2.6.5",
14360
14360
  mcpName: "io.github.cyanheads/git-mcp-server",
14361
14361
  description: "A secure and scalable Git MCP server enabling AI agents to perform comprehensive Git version control operations via STDIO and Streamable HTTP.",
14362
14362
  main: "dist/index.js",
@@ -14423,8 +14423,8 @@ var init_package = __esm(() => {
14423
14423
  typescript: "5.9.3"
14424
14424
  },
14425
14425
  devDependencies: {
14426
- "@cloudflare/workers-types": "^4.20251212.0",
14427
- "@eslint/js": "^9.39.1",
14426
+ "@cloudflare/workers-types": "^4.20251213.0",
14427
+ "@eslint/js": "^9.39.2",
14428
14428
  "@hono/mcp": "^0.2.2",
14429
14429
  "@hono/node-server": "^1.19.7",
14430
14430
  "@modelcontextprotocol/sdk": "^1.24.3",
@@ -14453,10 +14453,10 @@ var init_package = __esm(() => {
14453
14453
  axios: "^1.13.2",
14454
14454
  "bun-types": "^1.3.4",
14455
14455
  "chrono-node": "^2.9.0",
14456
- clipboardy: "^5.0.1",
14456
+ clipboardy: "^5.0.2",
14457
14457
  depcheck: "^1.4.7",
14458
14458
  dotenv: "^17.2.3",
14459
- eslint: "^9.39.1",
14459
+ eslint: "^9.39.2",
14460
14460
  execa: "^9.6.1",
14461
14461
  "fast-xml-parser": "^5.3.3",
14462
14462
  globals: "^16.5.0",
@@ -14473,7 +14473,7 @@ var init_package = __esm(() => {
14473
14473
  "pdf-lib": "^1.17.1",
14474
14474
  prettier: "^3.7.4",
14475
14475
  "reflect-metadata": "^0.2.2",
14476
- repomix: "^1.10.0",
14476
+ repomix: "^1.10.1",
14477
14477
  "sanitize-html": "^2.17.0",
14478
14478
  tslib: "^2.8.1",
14479
14479
  tsyringe: "^4.10.0",
@@ -169038,14 +169038,18 @@ async function executeCommit(options, context, execGit) {
169038
169038
  }
169039
169039
  }
169040
169040
  // src/services/git/providers/cli/operations/commits/log.ts
169041
+ var COMMIT_START_MARKER = "<<<COMMIT_START>>>";
169042
+ var COMMIT_END_MARKER = "<<<COMMIT_END>>>";
169041
169043
  async function executeLog(options, context, execGit) {
169042
169044
  try {
169043
- const args = [
169044
- `--format=%H${GIT_FIELD_DELIMITER}%h${GIT_FIELD_DELIMITER}%an${GIT_FIELD_DELIMITER}%ae${GIT_FIELD_DELIMITER}%at${GIT_FIELD_DELIMITER}%s${GIT_FIELD_DELIMITER}%b${GIT_FIELD_DELIMITER}%P${GIT_RECORD_DELIMITER}`
169045
- ];
169045
+ const formatStr = `${COMMIT_START_MARKER}%H${GIT_FIELD_DELIMITER}%h${GIT_FIELD_DELIMITER}%an${GIT_FIELD_DELIMITER}%ae${GIT_FIELD_DELIMITER}%at${GIT_FIELD_DELIMITER}%s${GIT_FIELD_DELIMITER}%b${GIT_FIELD_DELIMITER}%P${COMMIT_END_MARKER}`;
169046
+ const args = [`--format=${formatStr}`];
169046
169047
  if (options.maxCount) {
169047
169048
  args.push(`-n${options.maxCount}`);
169048
169049
  }
169050
+ if (options.skip) {
169051
+ args.push(`--skip=${options.skip}`);
169052
+ }
169049
169053
  if (options.since) {
169050
169054
  args.push(`--since=${options.since}`);
169051
169055
  }
@@ -169058,6 +169062,12 @@ async function executeLog(options, context, execGit) {
169058
169062
  if (options.grep) {
169059
169063
  args.push(`--grep=${options.grep}`);
169060
169064
  }
169065
+ if (options.stat) {
169066
+ args.push("--stat");
169067
+ }
169068
+ if (options.patch) {
169069
+ args.push("-p");
169070
+ }
169061
169071
  if (options.branch) {
169062
169072
  args.push(options.branch);
169063
169073
  }
@@ -169066,8 +169076,15 @@ async function executeLog(options, context, execGit) {
169066
169076
  }
169067
169077
  const cmd = buildGitCommand({ command: "log", args });
169068
169078
  const gitOutput = await execGit(cmd, context.workingDirectory, context.requestContext);
169069
- const commits = gitOutput.stdout.split(GIT_RECORD_DELIMITER).filter((r) => r.trim()).map((record3) => {
169070
- const fields = record3.trim().split(GIT_FIELD_DELIMITER);
169079
+ const commits = [];
169080
+ const sections = gitOutput.stdout.split(COMMIT_START_MARKER).filter((s) => s.trim());
169081
+ for (const section of sections) {
169082
+ const endIdx = section.indexOf(COMMIT_END_MARKER);
169083
+ if (endIdx === -1)
169084
+ continue;
169085
+ const formatPart = section.substring(0, endIdx);
169086
+ const extraPart = section.substring(endIdx + COMMIT_END_MARKER.length).trim();
169087
+ const fields = formatPart.split(GIT_FIELD_DELIMITER);
169071
169088
  const commit = {
169072
169089
  hash: fields[0] || "",
169073
169090
  shortHash: fields[1] || "",
@@ -169080,13 +169097,28 @@ async function executeLog(options, context, execGit) {
169080
169097
  if (fields[6]) {
169081
169098
  commit.body = fields[6];
169082
169099
  }
169083
- return commit;
169084
- });
169085
- const result = {
169100
+ if (extraPart) {
169101
+ if (options.stat && options.patch) {
169102
+ const diffStart = extraPart.indexOf(`
169103
+ diff --git`);
169104
+ if (diffStart !== -1) {
169105
+ commit.stat = extraPart.substring(0, diffStart).trim();
169106
+ commit.patch = extraPart.substring(diffStart + 1).trim();
169107
+ } else {
169108
+ commit.stat = extraPart;
169109
+ }
169110
+ } else if (options.patch) {
169111
+ commit.patch = extraPart;
169112
+ } else if (options.stat) {
169113
+ commit.stat = extraPart;
169114
+ }
169115
+ }
169116
+ commits.push(commit);
169117
+ }
169118
+ return {
169086
169119
  commits,
169087
169120
  totalCount: commits.length
169088
169121
  };
169089
- return result;
169090
169122
  } catch (error46) {
169091
169123
  throw mapGitError(error46, "log");
169092
169124
  }
@@ -169129,6 +169161,12 @@ async function executeDiff(options, context, execGit) {
169129
169161
  if (options.staged) {
169130
169162
  args.push("--cached");
169131
169163
  }
169164
+ if (options.nameOnly) {
169165
+ args.push("--name-only");
169166
+ }
169167
+ if (options.unified !== undefined) {
169168
+ args.push(`--unified=${options.unified}`);
169169
+ }
169132
169170
  if (options.commit1) {
169133
169171
  args.push(options.commit1);
169134
169172
  }
@@ -169138,26 +169176,82 @@ async function executeDiff(options, context, execGit) {
169138
169176
  if (options.path) {
169139
169177
  args.push("--", options.path);
169140
169178
  }
169141
- if (options.unified) {
169142
- args.push(`--unified=${options.unified}`);
169179
+ if (options.stat) {
169180
+ const statCmd2 = buildGitCommand({
169181
+ command: "diff",
169182
+ args: [...args.filter((a) => a !== "--name-only"), "--stat"]
169183
+ });
169184
+ const statResult2 = await execGit(statCmd2, context.workingDirectory, context.requestContext);
169185
+ const stats2 = parseGitDiffStat(statResult2.stdout);
169186
+ return {
169187
+ diff: statResult2.stdout,
169188
+ filesChanged: stats2.files.length,
169189
+ insertions: stats2.totalAdditions,
169190
+ deletions: stats2.totalDeletions,
169191
+ binary: statResult2.stdout.includes("Binary files")
169192
+ };
169143
169193
  }
169144
- const diffCmd = buildGitCommand({ command: "diff", args: [...args] });
169194
+ const diffCmd = buildGitCommand({ command: "diff", args });
169145
169195
  const diffResult = await execGit(diffCmd, context.workingDirectory, context.requestContext);
169196
+ let untrackedDiff = "";
169197
+ let untrackedFileCount = 0;
169198
+ if (options.includeUntracked) {
169199
+ const lsFilesCmd = buildGitCommand({
169200
+ command: "ls-files",
169201
+ args: ["--others", "--exclude-standard"]
169202
+ });
169203
+ const lsFilesResult = await execGit(lsFilesCmd, context.workingDirectory, context.requestContext);
169204
+ const untrackedFiles = lsFilesResult.stdout.split(`
169205
+ `).filter((f) => f.trim());
169206
+ untrackedFileCount = untrackedFiles.length;
169207
+ for (const file2 of untrackedFiles) {
169208
+ if (options.nameOnly) {
169209
+ untrackedDiff += `${file2}
169210
+ `;
169211
+ } else {
169212
+ try {
169213
+ const untrackedCmd = buildGitCommand({
169214
+ command: "diff",
169215
+ args: ["--no-index", "/dev/null", file2]
169216
+ });
169217
+ const result = await execGit(untrackedCmd, context.workingDirectory, context.requestContext);
169218
+ untrackedDiff += result.stdout;
169219
+ } catch (err) {
169220
+ if (err instanceof Error) {
169221
+ const stdoutMatch = err.message.match(/\nStdout: ([\s\S]*)$/);
169222
+ if (stdoutMatch?.[1]) {
169223
+ untrackedDiff += stdoutMatch[1];
169224
+ }
169225
+ }
169226
+ }
169227
+ }
169228
+ }
169229
+ }
169230
+ const combinedDiff = diffResult.stdout + untrackedDiff;
169231
+ if (options.nameOnly) {
169232
+ const files = combinedDiff.split(`
169233
+ `).filter((line) => line.trim());
169234
+ return {
169235
+ diff: combinedDiff,
169236
+ filesChanged: files.length,
169237
+ binary: false
169238
+ };
169239
+ }
169240
+ const baseArgs = args.filter((a) => a !== "--name-only");
169146
169241
  const statCmd = buildGitCommand({
169147
169242
  command: "diff",
169148
- args: [...args, "--stat"]
169243
+ args: [...baseArgs, "--stat"]
169149
169244
  });
169150
169245
  const statResult = await execGit(statCmd, context.workingDirectory, context.requestContext);
169151
169246
  const stats = parseGitDiffStat(statResult.stdout);
169152
- const hasBinary = diffResult.stdout.includes("Binary files");
169153
- const result = {
169154
- diff: diffResult.stdout,
169155
- filesChanged: stats.files.length,
169247
+ const hasBinary = combinedDiff.includes("Binary files");
169248
+ return {
169249
+ diff: combinedDiff,
169250
+ filesChanged: stats.files.length + untrackedFileCount,
169156
169251
  insertions: stats.totalAdditions,
169157
169252
  deletions: stats.totalDeletions,
169158
169253
  binary: hasBinary
169159
169254
  };
169160
- return result;
169161
169255
  } catch (error46) {
169162
169256
  throw mapGitError(error46, "diff");
169163
169257
  }
@@ -169254,6 +169348,9 @@ async function executeCheckout(options, context, execGit) {
169254
169348
  const args = [];
169255
169349
  if (options.createBranch) {
169256
169350
  args.push("-b", options.target);
169351
+ if (options.track) {
169352
+ args.push("--track");
169353
+ }
169257
169354
  } else {
169258
169355
  args.push(options.target);
169259
169356
  }
@@ -187875,23 +187972,16 @@ var OutputSchema13 = exports_external.object({
187875
187972
  deletions: exports_external.number().int().optional().describe("Total number of line deletions.")
187876
187973
  });
187877
187974
  async function gitDiffLogic(input, { provider, targetPath, appContext }) {
187878
- const diffOptions = {
187975
+ const result = await provider.diff({
187976
+ ...input.target && { commit2: input.target },
187977
+ ...input.source && { commit1: input.source },
187978
+ ...input.paths?.length && { path: input.paths.join(" ") },
187879
187979
  staged: input.staged,
187880
187980
  includeUntracked: input.includeUntracked,
187881
187981
  nameOnly: input.nameOnly,
187882
187982
  stat: input.stat,
187883
- contextLines: input.contextLines
187884
- };
187885
- if (input.target !== undefined) {
187886
- diffOptions.target = input.target;
187887
- }
187888
- if (input.source !== undefined) {
187889
- diffOptions.source = input.source;
187890
- }
187891
- if (input.paths !== undefined) {
187892
- diffOptions.paths = input.paths;
187893
- }
187894
- const result = await provider.diff(diffOptions, {
187983
+ unified: input.contextLines
187984
+ }, {
187895
187985
  workingDirectory: targetPath,
187896
187986
  requestContext: appContext,
187897
187987
  tenantId: appContext.tenantId || "default-tenant"
@@ -187958,7 +188048,9 @@ var CommitSchema = exports_external.object({
187958
188048
  subject: exports_external.string().describe("First line of the commit message."),
187959
188049
  body: exports_external.string().optional().describe("Commit message body (if present)."),
187960
188050
  parents: exports_external.array(exports_external.string()).describe("Parent commit hashes."),
187961
- refs: exports_external.array(exports_external.string()).optional().describe("References (branches, tags) pointing to this commit.")
188051
+ refs: exports_external.array(exports_external.string()).optional().describe("References (branches, tags) pointing to this commit."),
188052
+ stat: exports_external.string().optional().describe("File change statistics (when stat option is used)."),
188053
+ patch: exports_external.string().optional().describe("Full diff patch (when patch option is used).")
187962
188054
  });
187963
188055
  var OutputSchema14 = exports_external.object({
187964
188056
  success: exports_external.boolean().describe("Indicates if the operation was successful."),
@@ -187966,44 +188058,20 @@ var OutputSchema14 = exports_external.object({
187966
188058
  totalCount: exports_external.number().int().describe("Total number of commits returned (may be limited by maxCount).")
187967
188059
  });
187968
188060
  async function gitLogLogic(input, { provider, targetPath, appContext }) {
187969
- const logOptions = {};
187970
- if (input.maxCount !== undefined) {
187971
- logOptions.maxCount = input.maxCount;
187972
- }
187973
- if (input.skip !== undefined) {
187974
- logOptions.skip = input.skip;
187975
- }
187976
- if (input.since !== undefined) {
187977
- logOptions.since = input.since;
187978
- }
187979
- if (input.until !== undefined) {
187980
- logOptions.until = input.until;
187981
- }
187982
- if (input.author !== undefined) {
187983
- logOptions.author = input.author;
187984
- }
187985
- if (input.grep !== undefined) {
187986
- logOptions.grep = input.grep;
187987
- }
187988
- if (input.branch !== undefined) {
187989
- logOptions.branch = input.branch;
187990
- }
187991
- if (input.filePath !== undefined) {
187992
- logOptions.filePath = input.filePath;
187993
- }
187994
- if (input.oneline !== undefined) {
187995
- logOptions.oneline = input.oneline;
187996
- }
187997
- if (input.stat !== undefined) {
187998
- logOptions.stat = input.stat;
187999
- }
188000
- if (input.patch !== undefined) {
188001
- logOptions.patch = input.patch;
188002
- }
188003
- if (input.showSignature !== undefined) {
188004
- logOptions.showSignature = input.showSignature;
188005
- }
188006
- const result = await provider.log(logOptions, {
188061
+ const result = await provider.log({
188062
+ ...input.maxCount && { maxCount: input.maxCount },
188063
+ ...input.skip && { skip: input.skip },
188064
+ ...input.since && { since: input.since },
188065
+ ...input.until && { until: input.until },
188066
+ ...input.author && { author: input.author },
188067
+ ...input.grep && { grep: input.grep },
188068
+ ...input.branch && { branch: input.branch },
188069
+ ...input.filePath && { path: input.filePath },
188070
+ ...input.showSignature && { showSignature: input.showSignature },
188071
+ ...input.oneline && { oneline: input.oneline },
188072
+ ...input.stat && { stat: input.stat },
188073
+ ...input.patch && { patch: input.patch }
188074
+ }, {
188007
188075
  workingDirectory: targetPath,
188008
188076
  requestContext: appContext,
188009
188077
  tenantId: appContext.tenantId || "default-tenant"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyanheads/git-mcp-server",
3
- "version": "2.6.3",
3
+ "version": "2.6.5",
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",
@@ -67,8 +67,8 @@
67
67
  "typescript": "5.9.3"
68
68
  },
69
69
  "devDependencies": {
70
- "@cloudflare/workers-types": "^4.20251212.0",
71
- "@eslint/js": "^9.39.1",
70
+ "@cloudflare/workers-types": "^4.20251213.0",
71
+ "@eslint/js": "^9.39.2",
72
72
  "@hono/mcp": "^0.2.2",
73
73
  "@hono/node-server": "^1.19.7",
74
74
  "@modelcontextprotocol/sdk": "^1.24.3",
@@ -97,10 +97,10 @@
97
97
  "axios": "^1.13.2",
98
98
  "bun-types": "^1.3.4",
99
99
  "chrono-node": "^2.9.0",
100
- "clipboardy": "^5.0.1",
100
+ "clipboardy": "^5.0.2",
101
101
  "depcheck": "^1.4.7",
102
102
  "dotenv": "^17.2.3",
103
- "eslint": "^9.39.1",
103
+ "eslint": "^9.39.2",
104
104
  "execa": "^9.6.1",
105
105
  "fast-xml-parser": "^5.3.3",
106
106
  "globals": "^16.5.0",
@@ -117,7 +117,7 @@
117
117
  "pdf-lib": "^1.17.1",
118
118
  "prettier": "^3.7.4",
119
119
  "reflect-metadata": "^0.2.2",
120
- "repomix": "^1.10.0",
120
+ "repomix": "^1.10.1",
121
121
  "sanitize-html": "^2.17.0",
122
122
  "tslib": "^2.8.1",
123
123
  "tsyringe": "^4.10.0",