@cyanheads/git-mcp-server 2.2.0 → 2.2.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.
Files changed (51) hide show
  1. package/dist/mcp-server/tools/gitAdd/logic.js +26 -45
  2. package/dist/mcp-server/tools/gitAdd/registration.js +6 -5
  3. package/dist/mcp-server/tools/gitBranch/logic.js +34 -51
  4. package/dist/mcp-server/tools/gitBranch/registration.js +7 -7
  5. package/dist/mcp-server/tools/gitCheckout/logic.js +15 -37
  6. package/dist/mcp-server/tools/gitCheckout/registration.js +7 -7
  7. package/dist/mcp-server/tools/gitCherryPick/logic.js +9 -28
  8. package/dist/mcp-server/tools/gitCherryPick/registration.js +7 -7
  9. package/dist/mcp-server/tools/gitClean/logic.js +9 -19
  10. package/dist/mcp-server/tools/gitClean/registration.js +7 -7
  11. package/dist/mcp-server/tools/gitClearWorkingDir/logic.js +4 -11
  12. package/dist/mcp-server/tools/gitClearWorkingDir/registration.js +7 -7
  13. package/dist/mcp-server/tools/gitClone/logic.js +10 -29
  14. package/dist/mcp-server/tools/gitClone/registration.js +7 -7
  15. package/dist/mcp-server/tools/gitCommit/logic.js +22 -52
  16. package/dist/mcp-server/tools/gitCommit/registration.js +7 -7
  17. package/dist/mcp-server/tools/gitDiff/logic.js +21 -37
  18. package/dist/mcp-server/tools/gitDiff/registration.js +7 -7
  19. package/dist/mcp-server/tools/gitFetch/logic.js +4 -20
  20. package/dist/mcp-server/tools/gitFetch/registration.js +7 -7
  21. package/dist/mcp-server/tools/gitInit/logic.js +10 -26
  22. package/dist/mcp-server/tools/gitInit/registration.js +7 -7
  23. package/dist/mcp-server/tools/gitLog/logic.js +19 -32
  24. package/dist/mcp-server/tools/gitLog/registration.js +7 -7
  25. package/dist/mcp-server/tools/gitMerge/logic.js +9 -28
  26. package/dist/mcp-server/tools/gitMerge/registration.js +7 -7
  27. package/dist/mcp-server/tools/gitPull/logic.js +4 -23
  28. package/dist/mcp-server/tools/gitPull/registration.js +7 -7
  29. package/dist/mcp-server/tools/gitPush/logic.js +9 -28
  30. package/dist/mcp-server/tools/gitPush/registration.js +7 -7
  31. package/dist/mcp-server/tools/gitRebase/logic.js +9 -28
  32. package/dist/mcp-server/tools/gitRebase/registration.js +7 -7
  33. package/dist/mcp-server/tools/gitRemote/logic.js +22 -38
  34. package/dist/mcp-server/tools/gitRemote/registration.js +7 -7
  35. package/dist/mcp-server/tools/gitReset/logic.js +5 -21
  36. package/dist/mcp-server/tools/gitReset/registration.js +7 -7
  37. package/dist/mcp-server/tools/gitSetWorkingDir/logic.js +8 -25
  38. package/dist/mcp-server/tools/gitSetWorkingDir/registration.js +7 -7
  39. package/dist/mcp-server/tools/gitShow/logic.js +3 -19
  40. package/dist/mcp-server/tools/gitShow/registration.js +7 -7
  41. package/dist/mcp-server/tools/gitStash/logic.js +14 -30
  42. package/dist/mcp-server/tools/gitStash/registration.js +7 -7
  43. package/dist/mcp-server/tools/gitStatus/logic.js +3 -13
  44. package/dist/mcp-server/tools/gitStatus/registration.js +7 -7
  45. package/dist/mcp-server/tools/gitTag/logic.js +6 -25
  46. package/dist/mcp-server/tools/gitTag/registration.js +7 -7
  47. package/dist/mcp-server/tools/gitWorktree/logic.js +5 -21
  48. package/dist/mcp-server/tools/gitWorktree/registration.js +7 -7
  49. package/dist/mcp-server/tools/gitWrapupInstructions/logic.js +5 -7
  50. package/dist/mcp-server/tools/gitWrapupInstructions/registration.js +8 -8
  51. package/package.json +5 -5
@@ -3,7 +3,6 @@
3
3
  * @module src/mcp-server/tools/gitStatus/registration
4
4
  */
5
5
  import { ErrorHandler, logger, requestContextService } from "../../../utils/index.js";
6
- import { McpError, BaseErrorCode } from "../../../types-global/errors.js";
7
6
  import { getGitStatus, GitStatusInputSchema, GitStatusOutputSchema, } from "./logic.js";
8
7
  const TOOL_NAME = "git_status";
9
8
  const TOOL_DESCRIPTION = "Retrieves the status of a Git repository. Returns a JSON object detailing the current branch, cleanliness, and changes. Staged and unstaged changes are grouped by status (e.g., Added, Modified), alongside lists of untracked and conflicted files.";
@@ -45,18 +44,19 @@ export const registerGitStatusTool = async (server, getWorkingDirectory, getSess
45
44
  }
46
45
  catch (error) {
47
46
  logger.error(`Error in ${TOOL_NAME} handler`, { error, ...handlerContext });
48
- const handledError = ErrorHandler.handleError(error, {
47
+ const mcpError = ErrorHandler.handleError(error, {
49
48
  operation: `tool:${TOOL_NAME}`,
50
49
  context: handlerContext,
51
50
  input: params,
52
51
  });
53
- const mcpError = handledError instanceof McpError
54
- ? handledError
55
- : new McpError(BaseErrorCode.INTERNAL_ERROR, "An unexpected error occurred.", { originalError: handledError });
56
52
  return {
57
53
  isError: true,
58
- content: [{ type: "text", text: mcpError.message }],
59
- structuredContent: mcpError.details,
54
+ content: [{ type: "text", text: `Error: ${mcpError.message}` }],
55
+ structuredContent: {
56
+ code: mcpError.code,
57
+ message: mcpError.message,
58
+ details: mcpError.details,
59
+ },
60
60
  };
61
61
  }
62
62
  });
@@ -63,30 +63,11 @@ export async function gitTagLogic(params, context) {
63
63
  args.push("-d", params.tagName);
64
64
  break;
65
65
  }
66
- try {
67
- logger.debug(`Executing command: git ${args.join(" ")}`, { ...context, operation });
68
- const { stdout } = await execFileAsync("git", args);
69
- if (params.mode === 'list') {
70
- const tags = stdout.trim().split("\n").filter(Boolean);
71
- return { success: true, mode: params.mode, tags };
72
- }
73
- return { success: true, mode: params.mode, message: `Tag '${params.tagName}' ${params.mode}d successfully.`, tagName: params.tagName };
74
- }
75
- catch (error) {
76
- const errorMessage = error.stderr || error.message || "";
77
- logger.error(`Failed to execute git tag command`, { ...context, operation, errorMessage });
78
- if (errorMessage.toLowerCase().includes("not a git repository")) {
79
- throw new McpError(BaseErrorCode.NOT_FOUND, `Path is not a Git repository: ${targetPath}`);
80
- }
81
- if (params.mode === "create" && errorMessage.toLowerCase().includes("already exists")) {
82
- throw new McpError(BaseErrorCode.CONFLICT, `Tag '${params.tagName}' already exists.`);
83
- }
84
- if (params.mode === "delete" && errorMessage.toLowerCase().includes("not found")) {
85
- throw new McpError(BaseErrorCode.NOT_FOUND, `Tag '${params.tagName}' not found.`);
86
- }
87
- if (params.mode === "create" && params.commitRef && /unknown revision or path not in the working tree/i.test(errorMessage)) {
88
- throw new McpError(BaseErrorCode.NOT_FOUND, `Commit reference '${params.commitRef}' not found.`);
89
- }
90
- throw new McpError(BaseErrorCode.INTERNAL_ERROR, `Git tag ${params.mode} failed: ${errorMessage}`);
66
+ logger.debug(`Executing command: git ${args.join(" ")}`, { ...context, operation });
67
+ const { stdout } = await execFileAsync("git", args);
68
+ if (params.mode === 'list') {
69
+ const tags = stdout.trim().split("\n").filter(Boolean);
70
+ return { success: true, mode: params.mode, tags };
91
71
  }
72
+ return { success: true, mode: params.mode, message: `Tag '${params.tagName}' ${params.mode}d successfully.`, tagName: params.tagName };
92
73
  }
@@ -3,7 +3,6 @@
3
3
  * @module src/mcp-server/tools/gitTag/registration
4
4
  */
5
5
  import { ErrorHandler, logger, requestContextService } from "../../../utils/index.js";
6
- import { McpError, BaseErrorCode } from "../../../types-global/errors.js";
7
6
  import { gitTagLogic, GitTagInputSchema, GitTagOutputSchema, GitTagBaseSchema, } from "./logic.js";
8
7
  const TOOL_NAME = "git_tag";
9
8
  const TOOL_DESCRIPTION = "Manages Git tags. Supports listing existing tags, creating new lightweight or annotated tags against specific commits, and deleting local tags. Returns results as a JSON object.";
@@ -47,18 +46,19 @@ export const registerGitTagTool = async (server, getWorkingDirectory, getSession
47
46
  }
48
47
  catch (error) {
49
48
  logger.error(`Error in ${TOOL_NAME} handler`, { error, ...handlerContext });
50
- const handledError = ErrorHandler.handleError(error, {
49
+ const mcpError = ErrorHandler.handleError(error, {
51
50
  operation: `tool:${TOOL_NAME}`,
52
51
  context: handlerContext,
53
52
  input: params,
54
53
  });
55
- const mcpError = handledError instanceof McpError
56
- ? handledError
57
- : new McpError(BaseErrorCode.INTERNAL_ERROR, "An unexpected error occurred.", { originalError: handledError });
58
54
  return {
59
55
  isError: true,
60
- content: [{ type: "text", text: mcpError.message }],
61
- structuredContent: mcpError.details,
56
+ content: [{ type: "text", text: `Error: ${mcpError.message}` }],
57
+ structuredContent: {
58
+ code: mcpError.code,
59
+ message: mcpError.message,
60
+ details: mcpError.details,
61
+ },
62
62
  };
63
63
  }
64
64
  });
@@ -129,26 +129,10 @@ export async function gitWorktreeLogic(params, context) {
129
129
  return baseArgs;
130
130
  };
131
131
  const args = buildArgs();
132
- try {
133
- logger.debug(`Executing command: git ${args.join(" ")}`, { ...context, operation });
134
- const { stdout } = await execFileAsync("git", args);
135
- if (params.mode === 'list' && params.verbose) {
136
- return { success: true, mode: params.mode, worktrees: parsePorcelainWorktreeList(stdout) };
137
- }
138
- return { success: true, mode: params.mode, message: stdout.trim() || `Worktree ${params.mode} operation successful.` };
139
- }
140
- catch (error) {
141
- const errorMessage = error.stderr || error.message || "";
142
- logger.error(`Failed to execute git worktree command`, { ...context, operation, errorMessage });
143
- if (errorMessage.toLowerCase().includes("not a git repository")) {
144
- throw new McpError(BaseErrorCode.NOT_FOUND, `Path is not a Git repository: ${targetPath}`);
145
- }
146
- if (params.mode === "add" && errorMessage.includes("already exists")) {
147
- throw new McpError(BaseErrorCode.CONFLICT, `Path '${params.worktreePath}' already exists or is a worktree.`);
148
- }
149
- if (params.mode === "remove" && errorMessage.includes("has unclean changes")) {
150
- throw new McpError(BaseErrorCode.CONFLICT, `Worktree '${params.worktreePath}' has uncommitted changes. Use force=true to remove.`);
151
- }
152
- throw new McpError(BaseErrorCode.INTERNAL_ERROR, `Git worktree ${params.mode} failed: ${errorMessage}`);
132
+ logger.debug(`Executing command: git ${args.join(" ")}`, { ...context, operation });
133
+ const { stdout } = await execFileAsync("git", args);
134
+ if (params.mode === 'list' && params.verbose) {
135
+ return { success: true, mode: params.mode, worktrees: parsePorcelainWorktreeList(stdout) };
153
136
  }
137
+ return { success: true, mode: params.mode, message: stdout.trim() || `Worktree ${params.mode} operation successful.` };
154
138
  }
@@ -3,7 +3,6 @@
3
3
  * @module src/mcp-server/tools/gitWorktree/registration
4
4
  */
5
5
  import { ErrorHandler, logger, requestContextService } from "../../../utils/index.js";
6
- import { McpError, BaseErrorCode } from "../../../types-global/errors.js";
7
6
  import { gitWorktreeLogic, GitWorktreeInputSchema, GitWorktreeOutputSchema, GitWorktreeBaseSchema, } from "./logic.js";
8
7
  const TOOL_NAME = "git_worktree";
9
8
  const TOOL_DESCRIPTION = "Manages Git worktrees. Supports listing, adding, removing, moving, and pruning worktrees. Returns results as a JSON object.";
@@ -47,18 +46,19 @@ export const registerGitWorktreeTool = async (server, getWorkingDirectory, getSe
47
46
  }
48
47
  catch (error) {
49
48
  logger.error(`Error in ${TOOL_NAME} handler`, { error, ...handlerContext });
50
- const handledError = ErrorHandler.handleError(error, {
49
+ const mcpError = ErrorHandler.handleError(error, {
51
50
  operation: `tool:${TOOL_NAME}`,
52
51
  context: handlerContext,
53
52
  input: params,
54
53
  });
55
- const mcpError = handledError instanceof McpError
56
- ? handledError
57
- : new McpError(BaseErrorCode.INTERNAL_ERROR, "An unexpected error occurred.", { originalError: handledError });
58
54
  return {
59
55
  isError: true,
60
- content: [{ type: "text", text: mcpError.message }],
61
- structuredContent: mcpError.details,
56
+ content: [{ type: "text", text: `Error: ${mcpError.message}` }],
57
+ structuredContent: {
58
+ code: mcpError.code,
59
+ message: mcpError.message,
60
+ details: mcpError.details,
61
+ },
62
62
  };
63
63
  }
64
64
  });
@@ -9,6 +9,7 @@ import { getGitStatus, GitStatusOutputSchema } from "../gitStatus/logic.js";
9
9
  export const GitWrapupInstructionsInputSchema = z.object({
10
10
  acknowledgement: z.enum(["Y", "y", "Yes", "yes"]).describe("Acknowledgement to initiate the wrap-up workflow."),
11
11
  updateAgentMetaFiles: z.enum(["Y", "y", "Yes", "yes"]).optional().describe("Include an instruction to update agent-specific meta files."),
12
+ createTag: z.boolean().optional().describe("If true, instructs the agent to create a Git tag after committing all changes. Only set to true if given permission to do so."),
12
13
  });
13
14
  // 2. DEFINE the Zod response schema.
14
15
  export const GitWrapupInstructionsOutputSchema = z.object({
@@ -37,17 +38,14 @@ export async function getWrapupInstructions(params, context) {
37
38
  if (params.updateAgentMetaFiles) {
38
39
  finalInstructions += `\nExtra request: review and update if needed the .clinerules and claude.md files if present.`;
39
40
  }
41
+ if (params.createTag) {
42
+ finalInstructions += `\n5. After all changes are committed and confirmed via 'git_status', use the 'git_tag' tool to create a new annotated tag. The tag name should follow semantic versioning (e.g., v1.2.3), and the annotation message should summarize the key changes in this wrap-up.`;
43
+ }
40
44
  let statusResult;
41
45
  let statusError;
42
46
  const workingDir = context.getWorkingDirectory();
43
47
  if (workingDir) {
44
- try {
45
- statusResult = await getGitStatus({ path: "." }, context);
46
- }
47
- catch (error) {
48
- logger.warning(`Failed to get git status for wrapup instructions: ${error.message}`, { ...context, operation });
49
- statusError = error.message;
50
- }
48
+ statusResult = await getGitStatus({ path: "." }, context);
51
49
  }
52
50
  else {
53
51
  statusError = "No working directory set for session, git status skipped.";
@@ -3,10 +3,9 @@
3
3
  * @module src/mcp-server/tools/gitWrapupInstructions/registration
4
4
  */
5
5
  import { ErrorHandler, logger, requestContextService } from "../../../utils/index.js";
6
- import { McpError, BaseErrorCode } from "../../../types-global/errors.js";
7
6
  import { getWrapupInstructions, GitWrapupInstructionsInputSchema, GitWrapupInstructionsOutputSchema, } from "./logic.js";
8
7
  const TOOL_NAME = "git_wrapup_instructions";
9
- const TOOL_DESCRIPTION = "Provides a standard Git wrap-up workflow. This involves reviewing changes with `git_diff`, updating documentation (README, CHANGELOG), and making logical, descriptive commits using the `git_commit` tool. The tool's response also includes the current `git status` output. You should set the working directory using `git_set_working_dir` before running this tool.";
8
+ const TOOL_DESCRIPTION = "Provides a standard Git wrap-up workflow. This involves reviewing changes with `git_diff`, updating documentation (README, CHANGELOG), and making logical, descriptive commits using the `git_commit` tool. Can optionally include instructions to create a Git tag after committing. The tool's response also includes the current `git status` output. You should set the working directory using `git_set_working_dir` before running this tool.";
10
9
  /**
11
10
  * Registers the git_wrapup_instructions tool with the MCP server instance.
12
11
  * @param server The MCP server instance.
@@ -45,18 +44,19 @@ export const registerGitWrapupInstructionsTool = async (server, getWorkingDirect
45
44
  }
46
45
  catch (error) {
47
46
  logger.error(`Error in ${TOOL_NAME} handler`, { error, ...handlerContext });
48
- const handledError = ErrorHandler.handleError(error, {
47
+ const mcpError = ErrorHandler.handleError(error, {
49
48
  operation: `tool:${TOOL_NAME}`,
50
49
  context: handlerContext,
51
50
  input: params,
52
51
  });
53
- const mcpError = handledError instanceof McpError
54
- ? handledError
55
- : new McpError(BaseErrorCode.INTERNAL_ERROR, "An unexpected error occurred.", { originalError: handledError });
56
52
  return {
57
53
  isError: true,
58
- content: [{ type: "text", text: mcpError.message }],
59
- structuredContent: mcpError.details,
54
+ content: [{ type: "text", text: `Error: ${mcpError.message}` }],
55
+ structuredContent: {
56
+ code: mcpError.code,
57
+ message: mcpError.message,
58
+ details: mcpError.details,
59
+ },
60
60
  };
61
61
  }
62
62
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyanheads/git-mcp-server",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "description": "An MCP (Model Context Protocol) server enabling LLMs and AI agents to interact with Git repositories. Provides tools for comprehensive Git operations including clone, commit, branch, diff, log, status, push, pull, merge, rebase, worktree, tag management, and more, via the MCP standard. STDIO & HTTP.",
5
5
  "main": "dist/index.js",
6
6
  "files": [
@@ -35,16 +35,16 @@
35
35
  "clean": "ts-node --esm scripts/clean.ts"
36
36
  },
37
37
  "dependencies": {
38
- "@hono/node-server": "^1.16.0",
39
- "@modelcontextprotocol/sdk": "^1.15.1",
40
- "@types/node": "^24.0.14",
38
+ "@hono/node-server": "^1.17.1",
39
+ "@modelcontextprotocol/sdk": "^1.16.0",
40
+ "@types/node": "^24.0.15",
41
41
  "@types/sanitize-html": "^2.16.0",
42
42
  "@types/validator": "^13.15.2",
43
43
  "chrono-node": "2.8.0",
44
44
  "dotenv": "16.6.1",
45
45
  "hono": "^4.8.5",
46
46
  "jose": "^6.0.12",
47
- "openai": "^5.9.2",
47
+ "openai": "^5.10.1",
48
48
  "partial-json": "^0.1.7",
49
49
  "sanitize-html": "^2.17.0",
50
50
  "tiktoken": "^1.0.21",