@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 CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  <div align="center">
9
9
 
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/)
10
+ [![Version](https://img.shields.io/badge/Version-2.4.9-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
 
@@ -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
- "GIT_MCP_BASE_DIR": "~/Developer/",
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
- "GIT_MCP_BASE_DIR": "~/Developer/",
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 verified commits.
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 server-side Git configuration. | `false` |
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.7",
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 __getOwnPropDesc = Object.getOwnPropertyDescriptor;
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 = __getOwnPropDesc(from, key)) || desc.enumerable
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 = __getOwnPropDesc(namespace, key);
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
- if (options.sign) {
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
- if (options.message && options.annotated) {
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.8",
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",