@cyanheads/git-mcp-server 2.9.1 → 2.9.2
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.
- package/README.md +1 -1
- package/dist/index.js +52 -33
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](./CHANGELOG.md) [](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-11-25/changelog.mdx) [](https://modelcontextprotocol.io/) [](./LICENSE) [](https://github.com/cyanheads/git-mcp-server/issues) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
package/dist/index.js
CHANGED
|
@@ -15335,7 +15335,7 @@ var package_default;
|
|
|
15335
15335
|
var init_package = __esm(() => {
|
|
15336
15336
|
package_default = {
|
|
15337
15337
|
name: "@cyanheads/git-mcp-server",
|
|
15338
|
-
version: "2.9.
|
|
15338
|
+
version: "2.9.2",
|
|
15339
15339
|
mcpName: "io.github.cyanheads/git-mcp-server",
|
|
15340
15340
|
description: "A secure and scalable Git MCP server enabling AI agents to perform comprehensive Git version control operations via STDIO and Streamable HTTP.",
|
|
15341
15341
|
main: "dist/index.js",
|
|
@@ -179321,20 +179321,24 @@ async function executeClone(options, context, execGit) {
|
|
|
179321
179321
|
const cmd = buildGitCommand({ command: "clone", args });
|
|
179322
179322
|
await execGit(cmd, cloneCwd, context.requestContext);
|
|
179323
179323
|
let commitHash;
|
|
179324
|
+
let actualBranch = options.branch || "main";
|
|
179324
179325
|
try {
|
|
179325
|
-
const
|
|
179326
|
-
command: "rev-parse",
|
|
179327
|
-
|
|
179328
|
-
|
|
179329
|
-
|
|
179326
|
+
const [revParseResult, branchResult] = await Promise.all([
|
|
179327
|
+
execGit(buildGitCommand({ command: "rev-parse", args: ["HEAD"] }), resolvedLocalPath, context.requestContext),
|
|
179328
|
+
execGit(buildGitCommand({
|
|
179329
|
+
command: "rev-parse",
|
|
179330
|
+
args: ["--abbrev-ref", "HEAD"]
|
|
179331
|
+
}), resolvedLocalPath, context.requestContext)
|
|
179332
|
+
]);
|
|
179330
179333
|
commitHash = revParseResult.stdout.trim() || undefined;
|
|
179334
|
+
actualBranch = branchResult.stdout.trim() || actualBranch;
|
|
179331
179335
|
} catch {}
|
|
179332
179336
|
const result = {
|
|
179333
179337
|
success: true,
|
|
179334
|
-
localPath:
|
|
179338
|
+
localPath: resolvedLocalPath,
|
|
179335
179339
|
remoteUrl: options.remoteUrl,
|
|
179336
|
-
branch:
|
|
179337
|
-
commitHash
|
|
179340
|
+
branch: actualBranch,
|
|
179341
|
+
...commitHash && { commitHash }
|
|
179338
179342
|
};
|
|
179339
179343
|
return result;
|
|
179340
179344
|
} catch (error48) {
|
|
@@ -179645,7 +179649,11 @@ async function executeShow(options, context, execGit) {
|
|
|
179645
179649
|
if (options.format === "raw") {
|
|
179646
179650
|
args.push("--format=raw");
|
|
179647
179651
|
}
|
|
179648
|
-
|
|
179652
|
+
if (options.filePath) {
|
|
179653
|
+
args.push(`${options.object}:${options.filePath}`);
|
|
179654
|
+
} else {
|
|
179655
|
+
args.push(options.object);
|
|
179656
|
+
}
|
|
179649
179657
|
const typeCmd = buildGitCommand({
|
|
179650
179658
|
command: "cat-file",
|
|
179651
179659
|
args: ["-t", options.object]
|
|
@@ -179960,7 +179968,7 @@ async function executeMerge(options, context, execGit) {
|
|
|
179960
179968
|
}).filter((f3) => f3);
|
|
179961
179969
|
const mergedFiles = result.stdout.split(`
|
|
179962
179970
|
`).map((line) => {
|
|
179963
|
-
const statMatch = line.match(/^\s
|
|
179971
|
+
const statMatch = line.match(/^\s(.+?)\s*\|\s*(?:\d+\s*[+-]*|Bin\s)/);
|
|
179964
179972
|
return statMatch?.[1]?.trim() || "";
|
|
179965
179973
|
}).filter((f3) => f3);
|
|
179966
179974
|
const mergeResult = {
|
|
@@ -180002,6 +180010,16 @@ async function executeRebase(options, context, execGit) {
|
|
|
180002
180010
|
if (!options.upstream) {
|
|
180003
180011
|
throw new Error("upstream is required for start mode");
|
|
180004
180012
|
}
|
|
180013
|
+
if (options.interactive) {
|
|
180014
|
+
args.push("--interactive");
|
|
180015
|
+
}
|
|
180016
|
+
if (options.preserve) {
|
|
180017
|
+
args.push("--preserve-merges");
|
|
180018
|
+
}
|
|
180019
|
+
const shouldSign = options.sign ?? shouldSignCommits();
|
|
180020
|
+
if (shouldSign) {
|
|
180021
|
+
args.push("--gpg-sign");
|
|
180022
|
+
}
|
|
180005
180023
|
if (options.onto) {
|
|
180006
180024
|
args.push("--onto", options.onto, options.upstream);
|
|
180007
180025
|
if (options.branch) {
|
|
@@ -180013,16 +180031,6 @@ async function executeRebase(options, context, execGit) {
|
|
|
180013
180031
|
args.push(options.branch);
|
|
180014
180032
|
}
|
|
180015
180033
|
}
|
|
180016
|
-
if (options.interactive) {
|
|
180017
|
-
args.push("--interactive");
|
|
180018
|
-
}
|
|
180019
|
-
if (options.preserve) {
|
|
180020
|
-
args.push("--preserve-merges");
|
|
180021
|
-
}
|
|
180022
|
-
const shouldSign = options.sign ?? shouldSignCommits();
|
|
180023
|
-
if (shouldSign) {
|
|
180024
|
-
args.push("--gpg-sign");
|
|
180025
|
-
}
|
|
180026
180034
|
}
|
|
180027
180035
|
const cmd = buildGitCommand({ command: "rebase", args });
|
|
180028
180036
|
const result = await execGit(cmd, context.workingDirectory, context.requestContext);
|
|
@@ -180226,7 +180234,7 @@ async function executeFetch(options, context, execGit) {
|
|
|
180226
180234
|
if (newRefMatch?.[1]) {
|
|
180227
180235
|
fetchedRefs.push(newRefMatch[1]);
|
|
180228
180236
|
} else {
|
|
180229
|
-
const updatedRefMatch = line.match(
|
|
180237
|
+
const updatedRefMatch = line.match(/\+?\s*[a-f0-9]+\.{2,3}[a-f0-9]+\s+\S+\s+->\s+(\S+)/);
|
|
180230
180238
|
if (updatedRefMatch?.[1]) {
|
|
180231
180239
|
fetchedRefs.push(updatedRefMatch[1]);
|
|
180232
180240
|
}
|
|
@@ -180253,6 +180261,9 @@ async function executePush(options, context, execGit) {
|
|
|
180253
180261
|
const args = [];
|
|
180254
180262
|
const remote = options.remote || "origin";
|
|
180255
180263
|
if (options.delete) {
|
|
180264
|
+
if (!options.branch && !options.remoteBranch) {
|
|
180265
|
+
throw new Error("A branch or remote branch name is required for delete operations.");
|
|
180266
|
+
}
|
|
180256
180267
|
args.push("--delete");
|
|
180257
180268
|
}
|
|
180258
180269
|
args.push(remote);
|
|
@@ -180461,21 +180472,24 @@ async function executeStash(options, context, execGit) {
|
|
|
180461
180472
|
const args = [options.mode];
|
|
180462
180473
|
switch (options.mode) {
|
|
180463
180474
|
case "list": {
|
|
180475
|
+
args.push("--format=%gd\t%ct\t%gs");
|
|
180464
180476
|
const cmd = buildGitCommand({ command: "stash", args });
|
|
180465
180477
|
const result = await execGit(cmd, context.workingDirectory, context.requestContext);
|
|
180466
180478
|
const stashes = result.stdout.split(`
|
|
180467
180479
|
`).filter((line) => line.trim()).map((line, index) => {
|
|
180468
|
-
const
|
|
180469
|
-
|
|
180470
|
-
|
|
180471
|
-
const
|
|
180472
|
-
const
|
|
180480
|
+
const parts = line.split("\t");
|
|
180481
|
+
const [refPart, tsPart, ...subjectParts] = parts;
|
|
180482
|
+
if (refPart && tsPart && subjectParts.length > 0) {
|
|
180483
|
+
const stashIndex = parseInt(refPart, 10);
|
|
180484
|
+
const timestamp2 = parseInt(tsPart, 10);
|
|
180485
|
+
const subject = subjectParts.join("\t");
|
|
180486
|
+
const branchMatch = subject.match(/^(?:WIP on|On)\s+([^:]+):\s+(.*)$/);
|
|
180473
180487
|
return {
|
|
180474
|
-
ref:
|
|
180488
|
+
ref: `stash@{${stashIndex}}`,
|
|
180475
180489
|
index: stashIndex,
|
|
180476
180490
|
branch: branchMatch?.[1] ?? "",
|
|
180477
|
-
description: branchMatch?.[2] ??
|
|
180478
|
-
timestamp:
|
|
180491
|
+
description: branchMatch?.[2] ?? subject,
|
|
180492
|
+
timestamp: timestamp2
|
|
180479
180493
|
};
|
|
180480
180494
|
}
|
|
180481
180495
|
return {
|
|
@@ -180703,6 +180717,8 @@ async function executeBlame(options, context, execGit) {
|
|
|
180703
180717
|
}
|
|
180704
180718
|
if (options.startLine && options.endLine) {
|
|
180705
180719
|
args.push(`-L${options.startLine},${options.endLine}`);
|
|
180720
|
+
} else if (options.startLine) {
|
|
180721
|
+
args.push(`-L${options.startLine},`);
|
|
180706
180722
|
}
|
|
180707
180723
|
args.push("--", options.file);
|
|
180708
180724
|
const cmd = buildGitCommand({ command: "blame", args });
|
|
@@ -198650,10 +198666,13 @@ var TOOL_TITLE11 = "Git Add";
|
|
|
198650
198666
|
var TOOL_DESCRIPTION11 = "Stage files for commit. Add file contents to the staging area (index) to prepare for the next commit.";
|
|
198651
198667
|
var InputSchema11 = exports_external.object({
|
|
198652
198668
|
path: PathSchema,
|
|
198653
|
-
files: exports_external.array(exports_external.string()).
|
|
198669
|
+
files: exports_external.array(exports_external.string()).default([]).describe('Array of file paths to stage (relative to repository root). Use ["."] to stage all changes. Can be omitted when all or update is true.'),
|
|
198654
198670
|
update: exports_external.boolean().default(false).describe("Stage only modified and deleted files (skip untracked files)."),
|
|
198655
198671
|
all: AllSchema,
|
|
198656
198672
|
force: exports_external.boolean().default(false).describe("Allow adding otherwise ignored files.")
|
|
198673
|
+
}).refine((data) => data.all || data.update || data.files.length > 0, {
|
|
198674
|
+
message: "Either files must be provided, or all/update must be true.",
|
|
198675
|
+
path: ["files"]
|
|
198657
198676
|
});
|
|
198658
198677
|
var OutputSchema12 = exports_external.object({
|
|
198659
198678
|
success: exports_external.boolean().describe("Indicates if the operation was successful."),
|
|
@@ -199891,7 +199910,7 @@ var gitRemoteTool = {
|
|
|
199891
199910
|
inputSchema: InputSchema24,
|
|
199892
199911
|
outputSchema: OutputSchema25,
|
|
199893
199912
|
annotations: { readOnlyHint: false },
|
|
199894
|
-
logic: withToolAuth(["tool:git:
|
|
199913
|
+
logic: withToolAuth(["tool:git:read"], createToolHandler(gitRemoteLogic)),
|
|
199895
199914
|
responseFormatter: responseFormatter24
|
|
199896
199915
|
};
|
|
199897
199916
|
|
|
@@ -199905,7 +199924,7 @@ var InputSchema25 = exports_external.object({
|
|
|
199905
199924
|
mode: exports_external.enum(["soft", "mixed", "hard", "merge", "keep"]).default("mixed").describe("Reset mode: soft (keep changes staged), mixed (unstage changes), hard (discard all changes), merge (reset and merge), keep (reset but keep local changes)."),
|
|
199906
199925
|
target: CommitRefSchema.optional().describe("Target commit to reset to (default: HEAD)."),
|
|
199907
199926
|
paths: exports_external.array(exports_external.string()).optional().describe("Specific file paths to reset (leaves HEAD unchanged)."),
|
|
199908
|
-
confirmed: exports_external.boolean().default(false).describe("Explicit confirmation required for hard reset on protected branches (main, master, production, etc.).")
|
|
199927
|
+
confirmed: exports_external.boolean().default(false).describe("Explicit confirmation required for hard, merge, and keep reset modes on protected branches (main, master, production, etc.).")
|
|
199909
199928
|
});
|
|
199910
199929
|
var OutputSchema26 = exports_external.object({
|
|
199911
199930
|
success: exports_external.boolean().describe("Indicates if the operation was successful."),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanheads/git-mcp-server",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.2",
|
|
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",
|