@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.
- package/README.md +1 -1
- package/dist/index.js +144 -76
- package/package.json +6 -6
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
|
@@ -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.
|
|
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.
|
|
14427
|
-
"@eslint/js": "^9.39.
|
|
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.
|
|
14456
|
+
clipboardy: "^5.0.2",
|
|
14457
14457
|
depcheck: "^1.4.7",
|
|
14458
14458
|
dotenv: "^17.2.3",
|
|
14459
|
-
eslint: "^9.39.
|
|
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.
|
|
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
|
|
169044
|
-
|
|
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 =
|
|
169070
|
-
|
|
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
|
-
|
|
169084
|
-
|
|
169085
|
-
|
|
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.
|
|
169142
|
-
|
|
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
|
|
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: [...
|
|
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 =
|
|
169153
|
-
|
|
169154
|
-
diff:
|
|
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
|
|
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
|
-
|
|
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
|
|
187970
|
-
|
|
187971
|
-
|
|
187972
|
-
|
|
187973
|
-
|
|
187974
|
-
|
|
187975
|
-
|
|
187976
|
-
|
|
187977
|
-
|
|
187978
|
-
|
|
187979
|
-
|
|
187980
|
-
|
|
187981
|
-
|
|
187982
|
-
|
|
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
|
+
"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.
|
|
71
|
-
"@eslint/js": "^9.39.
|
|
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.
|
|
100
|
+
"clipboardy": "^5.0.2",
|
|
101
101
|
"depcheck": "^1.4.7",
|
|
102
102
|
"dotenv": "^17.2.3",
|
|
103
|
-
"eslint": "^9.39.
|
|
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.
|
|
120
|
+
"repomix": "^1.10.1",
|
|
121
121
|
"sanitize-html": "^2.17.0",
|
|
122
122
|
"tslib": "^2.8.1",
|
|
123
123
|
"tsyringe": "^4.10.0",
|