@cyanheads/git-mcp-server 2.2.0 → 2.2.1
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/dist/mcp-server/tools/gitAdd/logic.js +26 -45
- package/dist/mcp-server/tools/gitAdd/registration.js +6 -5
- package/dist/mcp-server/tools/gitBranch/logic.js +34 -51
- package/dist/mcp-server/tools/gitBranch/registration.js +7 -7
- package/dist/mcp-server/tools/gitCheckout/logic.js +15 -37
- package/dist/mcp-server/tools/gitCheckout/registration.js +7 -7
- package/dist/mcp-server/tools/gitCherryPick/logic.js +9 -28
- package/dist/mcp-server/tools/gitCherryPick/registration.js +7 -7
- package/dist/mcp-server/tools/gitClean/logic.js +9 -19
- package/dist/mcp-server/tools/gitClean/registration.js +7 -7
- package/dist/mcp-server/tools/gitClearWorkingDir/logic.js +4 -11
- package/dist/mcp-server/tools/gitClearWorkingDir/registration.js +7 -7
- package/dist/mcp-server/tools/gitClone/logic.js +10 -29
- package/dist/mcp-server/tools/gitClone/registration.js +7 -7
- package/dist/mcp-server/tools/gitCommit/logic.js +22 -52
- package/dist/mcp-server/tools/gitCommit/registration.js +7 -7
- package/dist/mcp-server/tools/gitDiff/logic.js +21 -37
- package/dist/mcp-server/tools/gitDiff/registration.js +7 -7
- package/dist/mcp-server/tools/gitFetch/logic.js +4 -20
- package/dist/mcp-server/tools/gitFetch/registration.js +7 -7
- package/dist/mcp-server/tools/gitInit/logic.js +10 -26
- package/dist/mcp-server/tools/gitInit/registration.js +7 -7
- package/dist/mcp-server/tools/gitLog/logic.js +19 -32
- package/dist/mcp-server/tools/gitLog/registration.js +7 -7
- package/dist/mcp-server/tools/gitMerge/logic.js +9 -28
- package/dist/mcp-server/tools/gitMerge/registration.js +7 -7
- package/dist/mcp-server/tools/gitPull/logic.js +4 -23
- package/dist/mcp-server/tools/gitPull/registration.js +7 -7
- package/dist/mcp-server/tools/gitPush/logic.js +9 -28
- package/dist/mcp-server/tools/gitPush/registration.js +7 -7
- package/dist/mcp-server/tools/gitRebase/logic.js +9 -28
- package/dist/mcp-server/tools/gitRebase/registration.js +7 -7
- package/dist/mcp-server/tools/gitRemote/logic.js +22 -38
- package/dist/mcp-server/tools/gitRemote/registration.js +7 -7
- package/dist/mcp-server/tools/gitReset/logic.js +5 -21
- package/dist/mcp-server/tools/gitReset/registration.js +7 -7
- package/dist/mcp-server/tools/gitSetWorkingDir/logic.js +8 -25
- package/dist/mcp-server/tools/gitSetWorkingDir/registration.js +7 -7
- package/dist/mcp-server/tools/gitShow/logic.js +3 -19
- package/dist/mcp-server/tools/gitShow/registration.js +7 -7
- package/dist/mcp-server/tools/gitStash/logic.js +14 -30
- package/dist/mcp-server/tools/gitStash/registration.js +7 -7
- package/dist/mcp-server/tools/gitStatus/logic.js +3 -13
- package/dist/mcp-server/tools/gitStatus/registration.js +7 -7
- package/dist/mcp-server/tools/gitTag/logic.js +6 -25
- package/dist/mcp-server/tools/gitTag/registration.js +7 -7
- package/dist/mcp-server/tools/gitWorktree/logic.js +5 -21
- package/dist/mcp-server/tools/gitWorktree/registration.js +7 -7
- package/dist/mcp-server/tools/gitWrapupInstructions/logic.js +1 -7
- package/dist/mcp-server/tools/gitWrapupInstructions/registration.js +7 -7
- package/package.json +3 -3
|
@@ -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
|
|
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:
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
|
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:
|
|
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
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
|
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:
|
|
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
|
});
|
|
@@ -41,13 +41,7 @@ export async function getWrapupInstructions(params, context) {
|
|
|
41
41
|
let statusError;
|
|
42
42
|
const workingDir = context.getWorkingDirectory();
|
|
43
43
|
if (workingDir) {
|
|
44
|
-
|
|
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
|
-
}
|
|
44
|
+
statusResult = await getGitStatus({ path: "." }, context);
|
|
51
45
|
}
|
|
52
46
|
else {
|
|
53
47
|
statusError = "No working directory set for session, git status skipped.";
|
|
@@ -3,7 +3,6 @@
|
|
|
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
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. 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.";
|
|
@@ -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
|
|
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:
|
|
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.
|
|
3
|
+
"version": "2.2.1",
|
|
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": [
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@hono/node-server": "^1.16.0",
|
|
39
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
39
|
+
"@modelcontextprotocol/sdk": "^1.16.0",
|
|
40
40
|
"@types/node": "^24.0.14",
|
|
41
41
|
"@types/sanitize-html": "^2.16.0",
|
|
42
42
|
"@types/validator": "^13.15.2",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"dotenv": "16.6.1",
|
|
45
45
|
"hono": "^4.8.5",
|
|
46
46
|
"jose": "^6.0.12",
|
|
47
|
-
"openai": "^5.
|
|
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",
|