@cyanheads/git-mcp-server 2.1.8 → 2.2.0
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 +4 -4
- package/dist/mcp-server/server.js +69 -228
- package/dist/mcp-server/tools/gitAdd/index.js +2 -4
- package/dist/mcp-server/tools/gitAdd/logic.js +17 -74
- package/dist/mcp-server/tools/gitAdd/registration.js +38 -59
- package/dist/mcp-server/tools/gitBranch/index.js +3 -5
- package/dist/mcp-server/tools/gitBranch/logic.js +118 -296
- package/dist/mcp-server/tools/gitBranch/registration.js +52 -66
- package/dist/mcp-server/tools/gitCheckout/index.js +2 -3
- package/dist/mcp-server/tools/gitCheckout/logic.js +47 -122
- package/dist/mcp-server/tools/gitCheckout/registration.js +53 -72
- package/dist/mcp-server/tools/gitCherryPick/index.js +3 -5
- package/dist/mcp-server/tools/gitCherryPick/logic.js +55 -162
- package/dist/mcp-server/tools/gitCherryPick/registration.js +52 -67
- package/dist/mcp-server/tools/gitClean/index.js +3 -5
- package/dist/mcp-server/tools/gitClean/logic.js +44 -143
- package/dist/mcp-server/tools/gitClean/registration.js +52 -92
- package/dist/mcp-server/tools/gitClearWorkingDir/index.js +3 -5
- package/dist/mcp-server/tools/gitClearWorkingDir/logic.js +19 -26
- package/dist/mcp-server/tools/gitClearWorkingDir/registration.js +55 -73
- package/dist/mcp-server/tools/gitClone/index.js +2 -4
- package/dist/mcp-server/tools/gitClone/logic.js +50 -171
- package/dist/mcp-server/tools/gitClone/registration.js +51 -42
- package/dist/mcp-server/tools/gitCommit/index.js +2 -4
- package/dist/mcp-server/tools/gitCommit/logic.js +90 -295
- package/dist/mcp-server/tools/gitCommit/registration.js +52 -73
- package/dist/mcp-server/tools/gitDiff/index.js +2 -3
- package/dist/mcp-server/tools/gitDiff/logic.js +78 -254
- package/dist/mcp-server/tools/gitDiff/registration.js +53 -68
- package/dist/mcp-server/tools/gitFetch/index.js +2 -3
- package/dist/mcp-server/tools/gitFetch/logic.js +47 -129
- package/dist/mcp-server/tools/gitFetch/registration.js +54 -66
- package/dist/mcp-server/tools/gitInit/index.js +3 -5
- package/dist/mcp-server/tools/gitInit/logic.js +46 -152
- package/dist/mcp-server/tools/gitInit/registration.js +52 -104
- package/dist/mcp-server/tools/gitLog/index.js +2 -3
- package/dist/mcp-server/tools/gitLog/logic.js +75 -257
- package/dist/mcp-server/tools/gitLog/registration.js +54 -66
- package/dist/mcp-server/tools/gitMerge/index.js +3 -5
- package/dist/mcp-server/tools/gitMerge/logic.js +52 -179
- package/dist/mcp-server/tools/gitMerge/registration.js +52 -71
- package/dist/mcp-server/tools/gitPull/index.js +2 -3
- package/dist/mcp-server/tools/gitPull/logic.js +48 -146
- package/dist/mcp-server/tools/gitPull/registration.js +53 -75
- package/dist/mcp-server/tools/gitPush/index.js +2 -3
- package/dist/mcp-server/tools/gitPush/logic.js +73 -181
- package/dist/mcp-server/tools/gitPush/registration.js +53 -75
- package/dist/mcp-server/tools/gitRebase/index.js +3 -5
- package/dist/mcp-server/tools/gitRebase/logic.js +73 -202
- package/dist/mcp-server/tools/gitRebase/registration.js +52 -70
- package/dist/mcp-server/tools/gitRemote/index.js +3 -5
- package/dist/mcp-server/tools/gitRemote/logic.js +85 -193
- package/dist/mcp-server/tools/gitRemote/registration.js +52 -65
- package/dist/mcp-server/tools/gitReset/index.js +2 -3
- package/dist/mcp-server/tools/gitReset/logic.js +37 -121
- package/dist/mcp-server/tools/gitReset/registration.js +53 -60
- package/dist/mcp-server/tools/gitSetWorkingDir/index.js +3 -5
- package/dist/mcp-server/tools/gitSetWorkingDir/logic.js +45 -133
- package/dist/mcp-server/tools/gitSetWorkingDir/registration.js +55 -85
- package/dist/mcp-server/tools/gitShow/index.js +3 -5
- package/dist/mcp-server/tools/gitShow/logic.js +33 -122
- package/dist/mcp-server/tools/gitShow/registration.js +52 -74
- package/dist/mcp-server/tools/gitStash/index.js +3 -5
- package/dist/mcp-server/tools/gitStash/logic.js +70 -214
- package/dist/mcp-server/tools/gitStash/registration.js +52 -77
- package/dist/mcp-server/tools/gitStatus/index.js +2 -4
- package/dist/mcp-server/tools/gitStatus/logic.js +82 -229
- package/dist/mcp-server/tools/gitStatus/registration.js +52 -66
- package/dist/mcp-server/tools/gitTag/index.js +3 -5
- package/dist/mcp-server/tools/gitTag/logic.js +66 -188
- package/dist/mcp-server/tools/gitTag/registration.js +54 -73
- package/dist/mcp-server/tools/gitWorktree/index.js +3 -5
- package/dist/mcp-server/tools/gitWorktree/logic.js +112 -322
- package/dist/mcp-server/tools/gitWorktree/registration.js +54 -58
- package/dist/mcp-server/tools/gitWrapupInstructions/index.js +5 -3
- package/dist/mcp-server/tools/gitWrapupInstructions/logic.js +26 -38
- package/dist/mcp-server/tools/gitWrapupInstructions/registration.js +54 -70
- package/dist/mcp-server/transports/httpTransport.js +2 -3
- package/package.json +8 -8
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Barrel file for the
|
|
3
|
-
*
|
|
2
|
+
* @fileoverview Barrel file for the gitTag tool.
|
|
3
|
+
* @module src/mcp-server/tools/gitTag/index
|
|
4
4
|
*/
|
|
5
|
-
export { registerGitTagTool
|
|
6
|
-
// Export types if needed elsewhere, e.g.:
|
|
7
|
-
// export type { GitTagInput, GitTagResult } from './logic.js';
|
|
5
|
+
export { registerGitTagTool } from "./registration.js";
|
|
@@ -1,214 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Defines the core logic, schemas, and types for the git_tag tool.
|
|
3
|
+
* @module src/mcp-server/tools/gitTag/logic
|
|
4
|
+
*/
|
|
1
5
|
import { execFile } from "child_process";
|
|
2
6
|
import { promisify } from "util";
|
|
3
7
|
import { z } from "zod";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
8
|
+
import { logger, sanitization } from "../../../utils/index.js";
|
|
9
|
+
import { McpError, BaseErrorCode } from "../../../types-global/errors.js";
|
|
6
10
|
const execFileAsync = promisify(execFile);
|
|
7
|
-
//
|
|
8
|
-
// We export this separately to access its .shape for registration
|
|
11
|
+
// 1. DEFINE the Zod input schema.
|
|
9
12
|
export const GitTagBaseSchema = z.object({
|
|
10
|
-
path: z
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
mode: z
|
|
17
|
-
.enum(["list", "create", "delete"])
|
|
18
|
-
.describe("The tag operation to perform: 'list' (show all tags), 'create' (add a new tag), 'delete' (remove a local tag)."),
|
|
19
|
-
tagName: z
|
|
20
|
-
.string()
|
|
21
|
-
.min(1)
|
|
22
|
-
.optional()
|
|
23
|
-
.describe("The name for the tag. Required for 'create' and 'delete' modes. e.g., 'v2.3.0'."),
|
|
24
|
-
message: z
|
|
25
|
-
.string()
|
|
26
|
-
.optional()
|
|
27
|
-
.describe("The annotation message for the tag. Required and used only when 'mode' is 'create' and 'annotate' is true."),
|
|
28
|
-
commitRef: z
|
|
29
|
-
.string()
|
|
30
|
-
.optional()
|
|
31
|
-
.describe("The commit hash, branch name, or other reference to tag. Used only in 'create' mode. Defaults to the current HEAD if omitted."),
|
|
32
|
-
annotate: z
|
|
33
|
-
.boolean()
|
|
34
|
-
.default(false)
|
|
35
|
-
.describe("If true, creates an annotated tag (-a flag) instead of a lightweight tag. Requires 'message' to be provided. Used only in 'create' mode."),
|
|
36
|
-
// force: z.boolean().default(false).describe("Force tag creation/update (-f flag). Use with caution as it can overwrite existing tags."), // Consider adding later
|
|
13
|
+
path: z.string().default(".").describe("Path to the local Git repository."),
|
|
14
|
+
mode: z.enum(["list", "create", "delete"]).describe("The tag operation to perform."),
|
|
15
|
+
tagName: z.string().min(1).optional().describe("The name for the tag."),
|
|
16
|
+
message: z.string().optional().describe("The annotation message for the tag."),
|
|
17
|
+
commitRef: z.string().optional().describe("The commit hash, branch, or other reference to tag."),
|
|
18
|
+
annotate: z.boolean().default(false).describe("Create an annotated tag."),
|
|
37
19
|
});
|
|
38
|
-
// Apply refinements for conditional validation and export the final schema
|
|
39
20
|
export const GitTagInputSchema = GitTagBaseSchema.refine((data) => !(data.mode === "create" && data.annotate && !data.message), {
|
|
40
|
-
message: "An annotation 'message' is required when creating an annotated tag
|
|
41
|
-
path: ["message"],
|
|
42
|
-
})
|
|
43
|
-
.refine((data) => !(data.mode === "create" && !data.tagName), {
|
|
21
|
+
message: "An annotation 'message' is required when creating an annotated tag.",
|
|
22
|
+
path: ["message"],
|
|
23
|
+
}).refine((data) => !(data.mode === "create" && !data.tagName), {
|
|
44
24
|
message: "A 'tagName' is required for 'create' mode.",
|
|
45
|
-
path: ["tagName"],
|
|
46
|
-
})
|
|
47
|
-
.refine((data) => !(data.mode === "delete" && !data.tagName), {
|
|
25
|
+
path: ["tagName"],
|
|
26
|
+
}).refine((data) => !(data.mode === "delete" && !data.tagName), {
|
|
48
27
|
message: "A 'tagName' is required for 'delete' mode.",
|
|
49
|
-
path: ["tagName"],
|
|
28
|
+
path: ["tagName"],
|
|
29
|
+
});
|
|
30
|
+
// 2. DEFINE the Zod response schema.
|
|
31
|
+
export const GitTagOutputSchema = z.object({
|
|
32
|
+
success: z.boolean().describe("Indicates if the command was successful."),
|
|
33
|
+
mode: z.string().describe("The mode of operation that was performed."),
|
|
34
|
+
message: z.string().optional().describe("A summary message of the result."),
|
|
35
|
+
tags: z.array(z.string()).optional().describe("A list of tags for the 'list' mode."),
|
|
36
|
+
tagName: z.string().optional().describe("The name of the tag that was created or deleted."),
|
|
50
37
|
});
|
|
51
38
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* @param {GitTagInput} input - The validated input object.
|
|
55
|
-
* @param {RequestContext} context - The request context for logging and error handling.
|
|
56
|
-
* @returns {Promise<GitTagResult>} A promise that resolves with the structured result.
|
|
57
|
-
* @throws {McpError} Throws an McpError for path resolution/validation failures or unexpected errors.
|
|
39
|
+
* 4. IMPLEMENT the core logic function.
|
|
40
|
+
* @throws {McpError} If the logic encounters an unrecoverable issue.
|
|
58
41
|
*/
|
|
59
|
-
export async function gitTagLogic(
|
|
60
|
-
const operation = `gitTagLogic:${
|
|
61
|
-
logger.debug(`Executing ${operation}`, { ...context,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const workingDir = context.getWorkingDirectory();
|
|
66
|
-
targetPath =
|
|
67
|
-
input.path && input.path !== "." ? input.path : (workingDir ?? ".");
|
|
68
|
-
if (targetPath === "." && !workingDir) {
|
|
69
|
-
logger.warning("Executing git tag in server's CWD as no path provided and no session WD set.", { ...context, operation });
|
|
70
|
-
targetPath = process.cwd();
|
|
71
|
-
}
|
|
72
|
-
else if (targetPath === "." && workingDir) {
|
|
73
|
-
targetPath = workingDir;
|
|
74
|
-
logger.debug(`Using session working directory: ${targetPath}`, {
|
|
75
|
-
...context,
|
|
76
|
-
operation,
|
|
77
|
-
sessionId: context.sessionId,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
logger.debug(`Using provided path: ${targetPath}`, {
|
|
82
|
-
...context,
|
|
83
|
-
operation,
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
targetPath = sanitization.sanitizePath(targetPath, {
|
|
87
|
-
allowAbsolute: true,
|
|
88
|
-
}).sanitizedPath;
|
|
89
|
-
logger.debug("Sanitized path", {
|
|
90
|
-
...context,
|
|
91
|
-
operation,
|
|
92
|
-
sanitizedPath: targetPath,
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
catch (error) {
|
|
96
|
-
logger.error("Path resolution or sanitization failed", {
|
|
97
|
-
...context,
|
|
98
|
-
operation,
|
|
99
|
-
error,
|
|
100
|
-
});
|
|
101
|
-
if (error instanceof McpError)
|
|
102
|
-
throw error;
|
|
103
|
-
throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Invalid path: ${error instanceof Error ? error.message : String(error)}`, { context, operation, originalError: error });
|
|
104
|
-
}
|
|
105
|
-
// Validate tag name format (simple validation)
|
|
106
|
-
if (input.tagName && !/^[a-zA-Z0-9_./-]+$/.test(input.tagName)) {
|
|
107
|
-
throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Invalid tag name format: ${input.tagName}`, { context, operation });
|
|
42
|
+
export async function gitTagLogic(params, context) {
|
|
43
|
+
const operation = `gitTagLogic:${params.mode}`;
|
|
44
|
+
logger.debug(`Executing ${operation}`, { ...context, params });
|
|
45
|
+
const workingDir = context.getWorkingDirectory();
|
|
46
|
+
if (params.path === "." && !workingDir) {
|
|
47
|
+
throw new McpError(BaseErrorCode.VALIDATION_ERROR, "No session working directory set. Please specify a 'path' or use 'git_set_working_dir' first.");
|
|
108
48
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
49
|
+
const targetPath = sanitization.sanitizePath(params.path === "." ? workingDir : params.path, { allowAbsolute: true }).sanitizedPath;
|
|
50
|
+
const args = ["-C", targetPath, "tag"];
|
|
51
|
+
switch (params.mode) {
|
|
52
|
+
case "list":
|
|
53
|
+
args.push("--list");
|
|
54
|
+
break;
|
|
55
|
+
case "create":
|
|
56
|
+
if (params.annotate)
|
|
57
|
+
args.push("-a", "-m", params.message);
|
|
58
|
+
args.push(params.tagName);
|
|
59
|
+
if (params.commitRef)
|
|
60
|
+
args.push(params.commitRef);
|
|
61
|
+
break;
|
|
62
|
+
case "delete":
|
|
63
|
+
args.push("-d", params.tagName);
|
|
64
|
+
break;
|
|
112
65
|
}
|
|
113
66
|
try {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
logger.debug(`Executing command: git ${args.join(" ")}`, {
|
|
120
|
-
...context,
|
|
121
|
-
operation,
|
|
122
|
-
});
|
|
123
|
-
const { stdout: listStdout } = await execFileAsync("git", args);
|
|
124
|
-
const tags = listStdout
|
|
125
|
-
.trim()
|
|
126
|
-
.split("\n")
|
|
127
|
-
.filter((tag) => tag); // Filter out empty lines
|
|
128
|
-
result = { success: true, mode: "list", tags };
|
|
129
|
-
break;
|
|
130
|
-
case "create":
|
|
131
|
-
// TagName is validated by Zod refine
|
|
132
|
-
const tagNameCreate = input.tagName;
|
|
133
|
-
args = ["-C", targetPath, "tag"];
|
|
134
|
-
if (input.annotate) {
|
|
135
|
-
// Message is validated by Zod refine
|
|
136
|
-
args.push("-a", "-m", input.message);
|
|
137
|
-
}
|
|
138
|
-
args.push(tagNameCreate);
|
|
139
|
-
if (input.commitRef) {
|
|
140
|
-
args.push(input.commitRef);
|
|
141
|
-
}
|
|
142
|
-
logger.debug(`Executing command: git ${args.join(" ")}`, {
|
|
143
|
-
...context,
|
|
144
|
-
operation,
|
|
145
|
-
});
|
|
146
|
-
await execFileAsync("git", args);
|
|
147
|
-
result = {
|
|
148
|
-
success: true,
|
|
149
|
-
mode: "create",
|
|
150
|
-
message: `Tag '${tagNameCreate}' created successfully.`,
|
|
151
|
-
tagName: tagNameCreate,
|
|
152
|
-
};
|
|
153
|
-
break;
|
|
154
|
-
case "delete":
|
|
155
|
-
// TagName is validated by Zod refine
|
|
156
|
-
const tagNameDelete = input.tagName;
|
|
157
|
-
args = ["-C", targetPath, "tag", "-d", tagNameDelete];
|
|
158
|
-
logger.debug(`Executing command: git ${args.join(" ")}`, {
|
|
159
|
-
...context,
|
|
160
|
-
operation,
|
|
161
|
-
});
|
|
162
|
-
await execFileAsync("git", args);
|
|
163
|
-
result = {
|
|
164
|
-
success: true,
|
|
165
|
-
mode: "delete",
|
|
166
|
-
message: `Tag '${tagNameDelete}' deleted successfully.`,
|
|
167
|
-
tagName: tagNameDelete,
|
|
168
|
-
};
|
|
169
|
-
break;
|
|
170
|
-
default:
|
|
171
|
-
// Should not happen due to Zod validation
|
|
172
|
-
throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Invalid mode: ${input.mode}`, { context, operation });
|
|
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 };
|
|
173
72
|
}
|
|
174
|
-
|
|
175
|
-
...context,
|
|
176
|
-
operation,
|
|
177
|
-
path: targetPath,
|
|
178
|
-
result,
|
|
179
|
-
});
|
|
180
|
-
return result;
|
|
73
|
+
return { success: true, mode: params.mode, message: `Tag '${params.tagName}' ${params.mode}d successfully.`, tagName: params.tagName };
|
|
181
74
|
}
|
|
182
75
|
catch (error) {
|
|
183
76
|
const errorMessage = error.stderr || error.message || "";
|
|
184
|
-
logger.error(`Failed to execute git tag command`, {
|
|
185
|
-
...context,
|
|
186
|
-
operation,
|
|
187
|
-
path: targetPath,
|
|
188
|
-
error: errorMessage,
|
|
189
|
-
stderr: error.stderr,
|
|
190
|
-
stdout: error.stdout,
|
|
191
|
-
});
|
|
192
|
-
// Specific error handling
|
|
77
|
+
logger.error(`Failed to execute git tag command`, { ...context, operation, errorMessage });
|
|
193
78
|
if (errorMessage.toLowerCase().includes("not a git repository")) {
|
|
194
|
-
throw new McpError(BaseErrorCode.NOT_FOUND, `Path is not a Git repository: ${targetPath}
|
|
79
|
+
throw new McpError(BaseErrorCode.NOT_FOUND, `Path is not a Git repository: ${targetPath}`);
|
|
195
80
|
}
|
|
196
|
-
if (
|
|
197
|
-
|
|
198
|
-
throw new McpError(BaseErrorCode.CONFLICT, `Failed to create tag: Tag '${input.tagName}' already exists. Error: ${errorMessage}`, { context, operation, originalError: error });
|
|
81
|
+
if (params.mode === "create" && errorMessage.toLowerCase().includes("already exists")) {
|
|
82
|
+
throw new McpError(BaseErrorCode.CONFLICT, `Tag '${params.tagName}' already exists.`);
|
|
199
83
|
}
|
|
200
|
-
if (
|
|
201
|
-
|
|
202
|
-
throw new McpError(BaseErrorCode.NOT_FOUND, `Failed to delete tag: Tag '${input.tagName}' not found. Error: ${errorMessage}`, { context, operation, originalError: error });
|
|
84
|
+
if (params.mode === "delete" && errorMessage.toLowerCase().includes("not found")) {
|
|
85
|
+
throw new McpError(BaseErrorCode.NOT_FOUND, `Tag '${params.tagName}' not found.`);
|
|
203
86
|
}
|
|
204
|
-
if (
|
|
205
|
-
|
|
206
|
-
errorMessage
|
|
207
|
-
.toLowerCase()
|
|
208
|
-
.includes("unknown revision or path not in the working tree")) {
|
|
209
|
-
throw new McpError(BaseErrorCode.NOT_FOUND, `Failed to create tag: Commit reference '${input.commitRef}' not found. Error: ${errorMessage}`, { context, operation, originalError: error });
|
|
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.`);
|
|
210
89
|
}
|
|
211
|
-
|
|
212
|
-
throw new McpError(BaseErrorCode.INTERNAL_ERROR, `Git tag ${input.mode} failed for path: ${targetPath}. Error: ${errorMessage}`, { context, operation, originalError: error });
|
|
90
|
+
throw new McpError(BaseErrorCode.INTERNAL_ERROR, `Git tag ${params.mode} failed: ${errorMessage}`);
|
|
213
91
|
}
|
|
214
92
|
}
|
|
@@ -1,85 +1,66 @@
|
|
|
1
|
-
import { BaseErrorCode } from "../../../types-global/errors.js"; // Direct import for types-global
|
|
2
|
-
import { ErrorHandler, logger, requestContextService, } from "../../../utils/index.js"; // ErrorHandler (./utils/internal/errorHandler.js), logger (./utils/internal/logger.js), requestContextService (./utils/internal/requestContext.js)
|
|
3
|
-
// Import the final schema and types for handler logic
|
|
4
|
-
// Import the BASE schema separately for registration shape
|
|
5
|
-
import { GitTagBaseSchema, gitTagLogic, } from "./logic.js";
|
|
6
|
-
let _getWorkingDirectory;
|
|
7
|
-
let _getSessionId;
|
|
8
1
|
/**
|
|
9
|
-
*
|
|
10
|
-
* @
|
|
11
|
-
* @param getSidFn - Function to get the session ID from context.
|
|
2
|
+
* @fileoverview Handles registration and error handling for the git_tag tool.
|
|
3
|
+
* @module src/mcp-server/tools/gitTag/registration
|
|
12
4
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
logger.info("State accessors initialized for git_tag tool registration.");
|
|
17
|
-
}
|
|
5
|
+
import { ErrorHandler, logger, requestContextService } from "../../../utils/index.js";
|
|
6
|
+
import { McpError, BaseErrorCode } from "../../../types-global/errors.js";
|
|
7
|
+
import { gitTagLogic, GitTagInputSchema, GitTagOutputSchema, GitTagBaseSchema, } from "./logic.js";
|
|
18
8
|
const TOOL_NAME = "git_tag";
|
|
19
9
|
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.";
|
|
20
10
|
/**
|
|
21
|
-
* Registers the git_tag tool with the MCP server.
|
|
22
|
-
*
|
|
23
|
-
* @param
|
|
24
|
-
* @
|
|
25
|
-
* @throws {Error} If registration fails or state accessors are not initialized.
|
|
11
|
+
* Registers the git_tag tool with the MCP server instance.
|
|
12
|
+
* @param server The MCP server instance.
|
|
13
|
+
* @param getWorkingDirectory Function to get the session's working directory.
|
|
14
|
+
* @param getSessionId Function to get the session ID from context.
|
|
26
15
|
*/
|
|
27
|
-
export const registerGitTagTool = async (server) => {
|
|
28
|
-
if (!_getWorkingDirectory || !_getSessionId) {
|
|
29
|
-
throw new Error("State accessors for git_tag must be initialized before registration.");
|
|
30
|
-
}
|
|
16
|
+
export const registerGitTagTool = async (server, getWorkingDirectory, getSessionId) => {
|
|
31
17
|
const operation = "registerGitTagTool";
|
|
32
18
|
const context = requestContextService.createRequestContext({ operation });
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
19
|
+
server.registerTool(TOOL_NAME, {
|
|
20
|
+
title: "Git Tag",
|
|
21
|
+
description: TOOL_DESCRIPTION,
|
|
22
|
+
inputSchema: GitTagBaseSchema.shape,
|
|
23
|
+
outputSchema: GitTagOutputSchema.shape,
|
|
24
|
+
annotations: {
|
|
25
|
+
readOnlyHint: false,
|
|
26
|
+
destructiveHint: true, // Can create/delete tags
|
|
27
|
+
idempotentHint: false,
|
|
28
|
+
openWorldHint: false,
|
|
29
|
+
},
|
|
30
|
+
}, async (params, callContext) => {
|
|
31
|
+
const handlerContext = requestContextService.createRequestContext({
|
|
32
|
+
toolName: TOOL_NAME,
|
|
33
|
+
parentContext: callContext,
|
|
34
|
+
});
|
|
35
|
+
try {
|
|
36
|
+
// Explicitly parse with the refined schema to enforce validation rules
|
|
37
|
+
const validatedParams = GitTagInputSchema.parse(params);
|
|
38
|
+
const sessionId = getSessionId(handlerContext);
|
|
39
|
+
const result = await gitTagLogic(validatedParams, {
|
|
40
|
+
...handlerContext,
|
|
41
|
+
getWorkingDirectory: () => getWorkingDirectory(sessionId),
|
|
46
42
|
});
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
};
|
|
51
|
-
const logicContext = {
|
|
52
|
-
...requestContext,
|
|
53
|
-
sessionId: sessionId,
|
|
54
|
-
getWorkingDirectory: getWorkingDirectoryForSession,
|
|
43
|
+
return {
|
|
44
|
+
structuredContent: result,
|
|
45
|
+
content: [{ type: "text", text: `Success: ${JSON.stringify(result, null, 2)}` }],
|
|
55
46
|
};
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
text: JSON.stringify(tagResult, null, 2), // Pretty-print JSON
|
|
64
|
-
contentType: "application/json",
|
|
65
|
-
};
|
|
66
|
-
// Log based on the success flag in the result
|
|
67
|
-
if (tagResult.success) {
|
|
68
|
-
logger.info(`Tool ${TOOL_NAME} (mode: ${toolInput.mode}) executed successfully, returning JSON`, logicContext);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
// Log specific failure message from the result
|
|
72
|
-
logger.warning(`Tool ${TOOL_NAME} (mode: ${toolInput.mode}) failed: ${tagResult.message}`, { ...logicContext, errorDetails: tagResult.error });
|
|
73
|
-
}
|
|
74
|
-
// Return the result, whether success or structured failure
|
|
75
|
-
return { content: [resultContent] };
|
|
76
|
-
}, {
|
|
77
|
-
operation: toolOperation,
|
|
78
|
-
context: logicContext,
|
|
79
|
-
input: validatedArgs, // Log the raw validated args
|
|
80
|
-
errorCode: BaseErrorCode.INTERNAL_ERROR, // Default if unexpected error occurs in logic/wrapper
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
logger.error(`Error in ${TOOL_NAME} handler`, { error, ...handlerContext });
|
|
50
|
+
const handledError = ErrorHandler.handleError(error, {
|
|
51
|
+
operation: `tool:${TOOL_NAME}`,
|
|
52
|
+
context: handlerContext,
|
|
53
|
+
input: params,
|
|
81
54
|
});
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
55
|
+
const mcpError = handledError instanceof McpError
|
|
56
|
+
? handledError
|
|
57
|
+
: new McpError(BaseErrorCode.INTERNAL_ERROR, "An unexpected error occurred.", { originalError: handledError });
|
|
58
|
+
return {
|
|
59
|
+
isError: true,
|
|
60
|
+
content: [{ type: "text", text: mcpError.message }],
|
|
61
|
+
structuredContent: mcpError.details,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
logger.info(`Tool '${TOOL_NAME}' registered successfully.`, context);
|
|
85
66
|
};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Barrel file for the
|
|
3
|
-
*
|
|
2
|
+
* @fileoverview Barrel file for the gitWorktree tool.
|
|
3
|
+
* @module src/mcp-server/tools/gitWorktree/index
|
|
4
4
|
*/
|
|
5
|
-
export { registerGitWorktreeTool
|
|
6
|
-
// Export types if needed elsewhere, e.g.:
|
|
7
|
-
// export type { GitWorktreeInput, GitWorktreeResult } from './logic.js';
|
|
5
|
+
export { registerGitWorktreeTool } from "./registration.js";
|