@cyanheads/git-mcp-server 2.4.8 → 2.4.9
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 +8 -5
- package/dist/index.js +83 -6
- 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-06-18/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
|
|
|
@@ -73,7 +73,7 @@ Add the following to your MCP Client configuration file (e.g., `cline_mcp_settin
|
|
|
73
73
|
"env": {
|
|
74
74
|
"MCP_TRANSPORT_TYPE": "stdio",
|
|
75
75
|
"MCP_LOG_LEVEL": "info",
|
|
76
|
-
"
|
|
76
|
+
"GIT_BASE_DIR": "~/Developer/",
|
|
77
77
|
"LOGS_DIR": "~/Developer/logs/git-mcp-server/",
|
|
78
78
|
"GIT_USERNAME": "cyanheads",
|
|
79
79
|
"GIT_EMAIL": "casey@caseyjhand.com",
|
|
@@ -96,7 +96,7 @@ Add the following to your MCP Client configuration file (e.g., `cline_mcp_settin
|
|
|
96
96
|
"env": {
|
|
97
97
|
"MCP_TRANSPORT_TYPE": "stdio",
|
|
98
98
|
"MCP_LOG_LEVEL": "info",
|
|
99
|
-
"
|
|
99
|
+
"GIT_BASE_DIR": "~/Developer/",
|
|
100
100
|
"LOGS_DIR": "~/Developer/logs/git-mcp-server/",
|
|
101
101
|
"GIT_USERNAME": "cyanheads",
|
|
102
102
|
"GIT_EMAIL": "casey@caseyjhand.com",
|
|
@@ -133,8 +133,9 @@ Plus, specialized features for **Git integration**:
|
|
|
133
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).
|
|
134
134
|
- **Comprehensive Coverage**: 27 tools covering all essential Git operations from init to push.
|
|
135
135
|
- **Working Directory Management**: Session-specific directory context for multi-repo workflows.
|
|
136
|
+
- **Configurable Git Identity**: Override author/committer information via environment variables with automatic fallback to global git config.
|
|
136
137
|
- **Safety Features**: Explicit confirmations for destructive operations like `git clean` and `git reset --hard`.
|
|
137
|
-
- **Commit Signing**: Optional GPG/SSH signing support for
|
|
138
|
+
- **Commit Signing**: Optional GPG/SSH signing support for all commit-creating operations (commits, merges, rebases, cherry-picks, and tags).
|
|
138
139
|
|
|
139
140
|
### Development Environment Setup
|
|
140
141
|
|
|
@@ -190,7 +191,9 @@ All configuration is centralized and validated at startup in `src/config/index.t
|
|
|
190
191
|
| `STORAGE_PROVIDER_TYPE` | Storage backend: `in-memory`, `filesystem`, `supabase`, `cloudflare-kv`, `r2`. | `in-memory` |
|
|
191
192
|
| `OTEL_ENABLED` | Set to `true` to enable OpenTelemetry. | `false` |
|
|
192
193
|
| `MCP_LOG_LEVEL` | The minimum level for logging (`debug`, `info`, `warn`, `error`). | `info` |
|
|
193
|
-
| `GIT_SIGN_COMMITS` | Set to `"true"` to enable GPG/SSH signing for commits. Requires
|
|
194
|
+
| `GIT_SIGN_COMMITS` | Set to `"true"` to enable GPG/SSH signing for all commits, merges, rebases, cherry-picks, and tags. Requires GPG/SSH configuration. | `false` |
|
|
195
|
+
| `GIT_AUTHOR_NAME` | Git author name. Aliases: `GIT_USERNAME`, `GIT_USER`. Falls back to global git config if not set. | `(none)` |
|
|
196
|
+
| `GIT_AUTHOR_EMAIL` | Git author email. Aliases: `GIT_EMAIL`, `GIT_USER_EMAIL`. Falls back to global git config if not set. | `(none)` |
|
|
194
197
|
| `GIT_BASE_DIR` | Optional absolute path to restrict all git operations to a specific directory tree. Provides security sandboxing for multi-tenant or shared environments. | `(none)` |
|
|
195
198
|
| `GIT_WRAPUP_INSTRUCTIONS_PATH` | Optional path to custom markdown file with Git workflow instructions. | `(none)` |
|
|
196
199
|
| `MCP_AUTH_SECRET_KEY` | **Required for `jwt` auth.** A 32+ character secret key. | `(none)` |
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ var __create = Object.create;
|
|
|
4
4
|
var __getProtoOf = Object.getPrototypeOf;
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
9
|
var __toESM = (mod2, isNodeMode, target) => {
|
|
9
10
|
target = mod2 != null ? __create(__getProtoOf(mod2)) : {};
|
|
@@ -16,6 +17,20 @@ var __toESM = (mod2, isNodeMode, target) => {
|
|
|
16
17
|
});
|
|
17
18
|
return to;
|
|
18
19
|
};
|
|
20
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
21
|
+
var __toCommonJS = (from) => {
|
|
22
|
+
var entry = __moduleCache.get(from), desc;
|
|
23
|
+
if (entry)
|
|
24
|
+
return entry;
|
|
25
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
26
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
27
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
28
|
+
get: () => from[key],
|
|
29
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
30
|
+
}));
|
|
31
|
+
__moduleCache.set(from, entry);
|
|
32
|
+
return entry;
|
|
33
|
+
};
|
|
19
34
|
var __commonJS = (cb, mod2) => () => (mod2 || cb((mod2 = { exports: {} }).exports, mod2), mod2.exports);
|
|
20
35
|
var __export = (target, all) => {
|
|
21
36
|
for (var name in all)
|
|
@@ -4246,7 +4261,7 @@ var package_default;
|
|
|
4246
4261
|
var init_package = __esm(() => {
|
|
4247
4262
|
package_default = {
|
|
4248
4263
|
name: "@cyanheads/git-mcp-server",
|
|
4249
|
-
version: "2.4.
|
|
4264
|
+
version: "2.4.9",
|
|
4250
4265
|
mcpName: "io.github.cyanheads/git-mcp-server",
|
|
4251
4266
|
description: "A secure and scalable Git MCP server enabling AI agents to perform comprehensive Git version control operations via STDIO and Streamable HTTP.",
|
|
4252
4267
|
main: "dist/index.js",
|
|
@@ -4574,6 +4589,10 @@ var import_dotenv, packageManifest, hasFileSystemAccess, emptyStringAsUndefined
|
|
|
4574
4589
|
git: {
|
|
4575
4590
|
provider: env.GIT_PROVIDER,
|
|
4576
4591
|
signCommits: env.GIT_SIGN_COMMITS,
|
|
4592
|
+
authorName: env.GIT_AUTHOR_NAME || env.GIT_USERNAME || env.GIT_USER || undefined,
|
|
4593
|
+
authorEmail: env.GIT_AUTHOR_EMAIL || env.GIT_EMAIL || env.GIT_USER_EMAIL || undefined,
|
|
4594
|
+
committerName: env.GIT_COMMITTER_NAME || env.GIT_USERNAME || env.GIT_USER || undefined,
|
|
4595
|
+
committerEmail: env.GIT_COMMITTER_EMAIL || env.GIT_EMAIL || env.GIT_USER_EMAIL || undefined,
|
|
4577
4596
|
wrapupInstructionsPath: env.GIT_WRAPUP_INSTRUCTIONS_PATH,
|
|
4578
4597
|
baseDir: env.GIT_BASE_DIR,
|
|
4579
4598
|
maxCommandTimeoutMs: env.GIT_MAX_COMMAND_TIMEOUT_MS,
|
|
@@ -4753,6 +4772,10 @@ var init_config = __esm(() => {
|
|
|
4753
4772
|
git: z.object({
|
|
4754
4773
|
provider: z.preprocess(emptyStringAsUndefined, z.enum(["auto", "cli", "isomorphic"]).default("auto")),
|
|
4755
4774
|
signCommits: z.coerce.boolean().default(false),
|
|
4775
|
+
authorName: z.string().optional(),
|
|
4776
|
+
authorEmail: z.string().email().optional(),
|
|
4777
|
+
committerName: z.string().optional(),
|
|
4778
|
+
committerEmail: z.string().email().optional(),
|
|
4756
4779
|
wrapupInstructionsPath: z.preprocess(expandTildePath, z.string().optional()),
|
|
4757
4780
|
baseDir: z.preprocess((val) => expandTildePath(emptyStringAsUndefined(val)), z.string().refine((path) => !path || path.startsWith("/"), {
|
|
4758
4781
|
message: 'GIT_BASE_DIR must be an absolute path starting with "/" (tilde expansion is supported)'
|
|
@@ -13784,7 +13807,7 @@ var require_propwrap = __commonJS((exports) => {
|
|
|
13784
13807
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13785
13808
|
exports.propwrap = undefined;
|
|
13786
13809
|
var __defProp2 = Object.defineProperty;
|
|
13787
|
-
var
|
|
13810
|
+
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
13788
13811
|
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
13789
13812
|
var __getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
13790
13813
|
var __copyProps = (to, from, except, desc) => {
|
|
@@ -13793,7 +13816,7 @@ var require_propwrap = __commonJS((exports) => {
|
|
|
13793
13816
|
if (!__hasOwnProp2.call(to, key) && key !== except) {
|
|
13794
13817
|
__defProp2(to, key, {
|
|
13795
13818
|
get: () => from[key],
|
|
13796
|
-
enumerable: !(desc =
|
|
13819
|
+
enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable
|
|
13797
13820
|
});
|
|
13798
13821
|
}
|
|
13799
13822
|
}
|
|
@@ -13828,7 +13851,7 @@ var require_propwrap = __commonJS((exports) => {
|
|
|
13828
13851
|
} else {
|
|
13829
13852
|
val = namespaces[i + 1];
|
|
13830
13853
|
}
|
|
13831
|
-
const desc =
|
|
13854
|
+
const desc = __getOwnPropDesc2(namespace, key);
|
|
13832
13855
|
const wrappedNamespace = __defProp2({}, key, {
|
|
13833
13856
|
value: val,
|
|
13834
13857
|
enumerable: !desc || desc.enumerable
|
|
@@ -151663,6 +151686,14 @@ function buildGitCommand(config2) {
|
|
|
151663
151686
|
}
|
|
151664
151687
|
return parts;
|
|
151665
151688
|
}
|
|
151689
|
+
function loadConfig() {
|
|
151690
|
+
try {
|
|
151691
|
+
const configModule = (init_config(), __toCommonJS(exports_config));
|
|
151692
|
+
return configModule.config;
|
|
151693
|
+
} catch {
|
|
151694
|
+
return null;
|
|
151695
|
+
}
|
|
151696
|
+
}
|
|
151666
151697
|
function buildGitEnv(additionalEnv) {
|
|
151667
151698
|
const env = { ...process.env };
|
|
151668
151699
|
Object.assign(env, {
|
|
@@ -151670,6 +151701,21 @@ function buildGitEnv(additionalEnv) {
|
|
|
151670
151701
|
LANG: "en_US.UTF-8",
|
|
151671
151702
|
LC_ALL: "en_US.UTF-8"
|
|
151672
151703
|
});
|
|
151704
|
+
const config2 = loadConfig();
|
|
151705
|
+
if (config2?.git) {
|
|
151706
|
+
if (config2.git.authorName) {
|
|
151707
|
+
env.GIT_AUTHOR_NAME = config2.git.authorName;
|
|
151708
|
+
}
|
|
151709
|
+
if (config2.git.authorEmail) {
|
|
151710
|
+
env.GIT_AUTHOR_EMAIL = config2.git.authorEmail;
|
|
151711
|
+
}
|
|
151712
|
+
if (config2.git.committerName) {
|
|
151713
|
+
env.GIT_COMMITTER_NAME = config2.git.committerName;
|
|
151714
|
+
}
|
|
151715
|
+
if (config2.git.committerEmail) {
|
|
151716
|
+
env.GIT_COMMITTER_EMAIL = config2.git.committerEmail;
|
|
151717
|
+
}
|
|
151718
|
+
}
|
|
151673
151719
|
if (additionalEnv) {
|
|
151674
151720
|
Object.assign(env, additionalEnv);
|
|
151675
151721
|
}
|
|
@@ -151732,6 +151778,20 @@ function validateGitArgs(args) {
|
|
|
151732
151778
|
}
|
|
151733
151779
|
}
|
|
151734
151780
|
|
|
151781
|
+
// src/services/git/providers/cli/utils/config-helper.ts
|
|
151782
|
+
function loadConfig2() {
|
|
151783
|
+
try {
|
|
151784
|
+
const configModule = (init_config(), __toCommonJS(exports_config));
|
|
151785
|
+
return configModule.config;
|
|
151786
|
+
} catch {
|
|
151787
|
+
return null;
|
|
151788
|
+
}
|
|
151789
|
+
}
|
|
151790
|
+
function shouldSignCommits() {
|
|
151791
|
+
const config2 = loadConfig2();
|
|
151792
|
+
return config2?.git?.signCommits ?? false;
|
|
151793
|
+
}
|
|
151794
|
+
|
|
151735
151795
|
// src/services/git/providers/cli/utils/error-mapper.ts
|
|
151736
151796
|
init_errors();
|
|
151737
151797
|
var ERROR_PATTERNS = [
|
|
@@ -152327,7 +152387,8 @@ async function executeCommit(options, context, execGit) {
|
|
|
152327
152387
|
if (options.noVerify) {
|
|
152328
152388
|
args.push("--no-verify");
|
|
152329
152389
|
}
|
|
152330
|
-
|
|
152390
|
+
const shouldSign = options.sign ?? shouldSignCommits();
|
|
152391
|
+
if (shouldSign) {
|
|
152331
152392
|
args.push("--gpg-sign");
|
|
152332
152393
|
}
|
|
152333
152394
|
if (options.author) {
|
|
@@ -152627,6 +152688,10 @@ async function executeMerge(options, context, execGit) {
|
|
|
152627
152688
|
if (options.message) {
|
|
152628
152689
|
args.push("-m", options.message);
|
|
152629
152690
|
}
|
|
152691
|
+
const shouldSign = options.sign ?? shouldSignCommits();
|
|
152692
|
+
if (shouldSign) {
|
|
152693
|
+
args.push("-S");
|
|
152694
|
+
}
|
|
152630
152695
|
const cmd = buildGitCommand({ command: "merge", args });
|
|
152631
152696
|
const result = await execGit(cmd, context.workingDirectory, context.requestContext);
|
|
152632
152697
|
const hasConflicts = result.stdout.includes("CONFLICT") || result.stderr.includes("CONFLICT");
|
|
@@ -152706,6 +152771,10 @@ async function executeRebase(options, context, execGit) {
|
|
|
152706
152771
|
if (options.preserve) {
|
|
152707
152772
|
args.push("--preserve-merges");
|
|
152708
152773
|
}
|
|
152774
|
+
const shouldSign = options.sign ?? shouldSignCommits();
|
|
152775
|
+
if (shouldSign) {
|
|
152776
|
+
args.push("--gpg-sign");
|
|
152777
|
+
}
|
|
152709
152778
|
}
|
|
152710
152779
|
const cmd = buildGitCommand({ command: "rebase", args });
|
|
152711
152780
|
const result = await execGit(cmd, context.workingDirectory, context.requestContext);
|
|
@@ -152741,6 +152810,10 @@ async function executeCherryPick(options, context, execGit) {
|
|
|
152741
152810
|
if (options.noCommit) {
|
|
152742
152811
|
args.push("--no-commit");
|
|
152743
152812
|
}
|
|
152813
|
+
const shouldSign = options.sign ?? shouldSignCommits();
|
|
152814
|
+
if (shouldSign) {
|
|
152815
|
+
args.push("--gpg-sign");
|
|
152816
|
+
}
|
|
152744
152817
|
}
|
|
152745
152818
|
const cmd = buildGitCommand({ command: "cherry-pick", args });
|
|
152746
152819
|
const result = await execGit(cmd, context.workingDirectory, context.requestContext);
|
|
@@ -153041,7 +153114,11 @@ async function executeTag(options, context, execGit) {
|
|
|
153041
153114
|
throw new Error("Tag name is required for create operation");
|
|
153042
153115
|
}
|
|
153043
153116
|
args.push(options.tagName);
|
|
153044
|
-
|
|
153117
|
+
const shouldSign = options.sign ?? shouldSignCommits();
|
|
153118
|
+
if (shouldSign) {
|
|
153119
|
+
const message = options.message || `Tag ${options.tagName}`;
|
|
153120
|
+
args.push("-s", "-m", message);
|
|
153121
|
+
} else if (options.message && options.annotated) {
|
|
153045
153122
|
args.push("-a", "-m", options.message);
|
|
153046
153123
|
}
|
|
153047
153124
|
if (options.commit) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanheads/git-mcp-server",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.9",
|
|
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",
|