@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,71 +1,64 @@
|
|
|
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 & RequestContext (./utils/internal/requestContext.js)
|
|
3
|
-
import { GitResetInputSchema, resetGitState, } from "./logic.js";
|
|
4
|
-
let _getWorkingDirectory;
|
|
5
|
-
let _getSessionId;
|
|
6
1
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* @param getWdFn - Function to get the working directory for a session.
|
|
10
|
-
* @param getSidFn - Function to get the session ID from context.
|
|
2
|
+
* @fileoverview Handles registration and error handling for the git_reset tool.
|
|
3
|
+
* @module src/mcp-server/tools/gitReset/registration
|
|
11
4
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
logger.info("State accessors initialized for git_reset tool registration.");
|
|
16
|
-
}
|
|
5
|
+
import { ErrorHandler, logger, requestContextService } from "../../../utils/index.js";
|
|
6
|
+
import { McpError, BaseErrorCode } from "../../../types-global/errors.js";
|
|
7
|
+
import { resetGitState, GitResetInputSchema, GitResetOutputSchema, } from "./logic.js";
|
|
17
8
|
const TOOL_NAME = "git_reset";
|
|
18
9
|
const TOOL_DESCRIPTION = "Resets the current HEAD to a specified state. Supports different modes ('soft', 'mixed', 'hard', 'merge', 'keep') to control how the index and working tree are affected. Can reset to a specific commit. USE 'hard' MODE WITH EXTREME CAUTION as it discards local changes.";
|
|
19
10
|
/**
|
|
20
|
-
* Registers the git_reset tool with the MCP server.
|
|
21
|
-
*
|
|
22
|
-
* @param
|
|
23
|
-
* @
|
|
11
|
+
* Registers the git_reset 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.
|
|
24
15
|
*/
|
|
25
|
-
export async
|
|
26
|
-
if (!_getWorkingDirectory || !_getSessionId) {
|
|
27
|
-
throw new Error("State accessors for git_reset must be initialized before registration.");
|
|
28
|
-
}
|
|
16
|
+
export const registerGitResetTool = async (server, getWorkingDirectory, getSessionId) => {
|
|
29
17
|
const operation = "registerGitResetTool";
|
|
30
18
|
const context = requestContextService.createRequestContext({ operation });
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
19
|
+
server.registerTool(TOOL_NAME, {
|
|
20
|
+
title: "Git Reset",
|
|
21
|
+
description: TOOL_DESCRIPTION,
|
|
22
|
+
inputSchema: GitResetInputSchema.shape,
|
|
23
|
+
outputSchema: GitResetOutputSchema.shape,
|
|
24
|
+
annotations: {
|
|
25
|
+
readOnlyHint: false,
|
|
26
|
+
destructiveHint: true, // Can be very destructive, especially in 'hard' mode
|
|
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
|
+
const sessionId = getSessionId(handlerContext);
|
|
37
|
+
const result = await resetGitState(params, {
|
|
38
|
+
...handlerContext,
|
|
39
|
+
getWorkingDirectory: () => getWorkingDirectory(sessionId),
|
|
38
40
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
};
|
|
43
|
-
const logicContext = {
|
|
44
|
-
...requestContext,
|
|
45
|
-
sessionId: sessionId,
|
|
46
|
-
getWorkingDirectory: getWorkingDirectoryForSession,
|
|
41
|
+
return {
|
|
42
|
+
structuredContent: result,
|
|
43
|
+
content: [{ type: "text", text: `Success: ${JSON.stringify(result, null, 2)}` }],
|
|
47
44
|
};
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
// Stringify the entire GitResetResult object
|
|
56
|
-
text: JSON.stringify(resetResult, null, 2), // Pretty-print JSON
|
|
57
|
-
contentType: "application/json",
|
|
58
|
-
};
|
|
59
|
-
logger.info(`Tool ${TOOL_NAME} executed successfully: ${resetResult.message}`, logicContext);
|
|
60
|
-
// Success is determined by the logic function and included in the result object
|
|
61
|
-
return { content: [resultContent] };
|
|
62
|
-
}, {
|
|
63
|
-
operation: toolOperation,
|
|
64
|
-
context: logicContext,
|
|
65
|
-
input: validatedArgs,
|
|
66
|
-
errorCode: BaseErrorCode.INTERNAL_ERROR, // Default if unexpected error in logic
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
logger.error(`Error in ${TOOL_NAME} handler`, { error, ...handlerContext });
|
|
48
|
+
const handledError = ErrorHandler.handleError(error, {
|
|
49
|
+
operation: `tool:${TOOL_NAME}`,
|
|
50
|
+
context: handlerContext,
|
|
51
|
+
input: params,
|
|
67
52
|
});
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
53
|
+
const mcpError = handledError instanceof McpError
|
|
54
|
+
? handledError
|
|
55
|
+
: new McpError(BaseErrorCode.INTERNAL_ERROR, "An unexpected error occurred.", { originalError: handledError });
|
|
56
|
+
return {
|
|
57
|
+
isError: true,
|
|
58
|
+
content: [{ type: "text", text: mcpError.message }],
|
|
59
|
+
structuredContent: mcpError.details,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
logger.info(`Tool '${TOOL_NAME}' registered successfully.`, context);
|
|
64
|
+
};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Barrel file for the
|
|
3
|
-
*
|
|
2
|
+
* @fileoverview Barrel file for the gitSetWorkingDir tool.
|
|
3
|
+
* @module src/mcp-server/tools/gitSetWorkingDir/index
|
|
4
4
|
*/
|
|
5
|
-
export { registerGitSetWorkingDirTool
|
|
6
|
-
// Export types if needed elsewhere, e.g.:
|
|
7
|
-
// export type { GitSetWorkingDirInput, GitSetWorkingDirResult } from './logic.js';
|
|
5
|
+
export { registerGitSetWorkingDirTool } from "./registration.js";
|
|
@@ -1,159 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Defines the core logic, schemas, and types for the git_set_working_dir tool.
|
|
3
|
+
* @module src/mcp-server/tools/gitSetWorkingDir/logic
|
|
4
|
+
*/
|
|
1
5
|
import { execFile } from "child_process";
|
|
2
6
|
import fs from "fs/promises";
|
|
3
7
|
import { promisify } from "util";
|
|
4
8
|
import { z } from "zod";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
9
|
+
import { logger, sanitization } from "../../../utils/index.js";
|
|
10
|
+
import { McpError, BaseErrorCode } from "../../../types-global/errors.js";
|
|
7
11
|
const execFileAsync = promisify(execFile);
|
|
8
|
-
//
|
|
12
|
+
// 1. DEFINE the Zod input schema.
|
|
9
13
|
export const GitSetWorkingDirInputSchema = z.object({
|
|
10
|
-
path: z
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
.describe("The absolute path to set as the default working directory for the current session. Set this before using other git_* tools."),
|
|
14
|
-
validateGitRepo: z
|
|
15
|
-
.boolean()
|
|
16
|
-
.default(true)
|
|
17
|
-
.describe("Whether to validate that the path is a Git repository"),
|
|
18
|
-
initializeIfNotPresent: z
|
|
19
|
-
.boolean()
|
|
20
|
-
.optional()
|
|
21
|
-
.default(false)
|
|
22
|
-
.describe("If true and the directory is not a Git repository, attempt to initialize it with 'git init'."),
|
|
14
|
+
path: z.string().min(1).describe("The absolute path to set as the default working directory."),
|
|
15
|
+
validateGitRepo: z.boolean().default(true).describe("Validate that the path is a Git repository."),
|
|
16
|
+
initializeIfNotPresent: z.boolean().default(false).describe("If not a Git repository, initialize it with 'git init'."),
|
|
23
17
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
* @throws {McpError} Throws McpError for validation failures or operational errors.
|
|
33
|
-
*/
|
|
34
|
-
export async function gitSetWorkingDirLogic(input, context) {
|
|
35
|
-
const operation = "gitSetWorkingDirLogic";
|
|
36
|
-
logger.debug(`Executing ${operation}`, { ...context, input });
|
|
37
|
-
let sanitizedPath;
|
|
18
|
+
// 2. DEFINE the Zod response schema.
|
|
19
|
+
export const GitSetWorkingDirOutputSchema = z.object({
|
|
20
|
+
success: z.boolean().describe("Indicates if the command was successful."),
|
|
21
|
+
message: z.string().describe("A summary message of the result."),
|
|
22
|
+
path: z.string().describe("The path that was set as the working directory."),
|
|
23
|
+
initialized: z.boolean().describe("Indicates if a new repository was initialized."),
|
|
24
|
+
});
|
|
25
|
+
async function checkIsGitRepo(path) {
|
|
38
26
|
try {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
sanitizedPath = sanitization.sanitizePath(input.path, {
|
|
42
|
-
allowAbsolute: true,
|
|
43
|
-
}).sanitizedPath;
|
|
44
|
-
logger.debug(`Sanitized path: ${sanitizedPath}`, { ...context, operation });
|
|
27
|
+
const { stdout } = await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], { cwd: path });
|
|
28
|
+
return stdout.trim() === "true";
|
|
45
29
|
}
|
|
46
|
-
catch
|
|
47
|
-
|
|
48
|
-
if (error instanceof McpError)
|
|
49
|
-
throw error;
|
|
50
|
-
throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Invalid path provided: ${error.message}`, { context, operation });
|
|
30
|
+
catch {
|
|
31
|
+
return false;
|
|
51
32
|
}
|
|
52
|
-
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 4. IMPLEMENT the core logic function.
|
|
36
|
+
* @throws {McpError} If the logic encounters an unrecoverable issue.
|
|
37
|
+
*/
|
|
38
|
+
export async function gitSetWorkingDirLogic(params, context) {
|
|
39
|
+
const operation = "gitSetWorkingDirLogic";
|
|
40
|
+
logger.debug(`Executing ${operation}`, { ...context, params });
|
|
41
|
+
const sanitizedPath = sanitization.sanitizePath(params.path, { allowAbsolute: true }).sanitizedPath;
|
|
53
42
|
try {
|
|
54
43
|
const stats = await fs.stat(sanitizedPath);
|
|
55
44
|
if (!stats.isDirectory()) {
|
|
56
|
-
throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Path is not a directory: ${sanitizedPath}
|
|
45
|
+
throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Path is not a directory: ${sanitizedPath}`);
|
|
57
46
|
}
|
|
58
47
|
}
|
|
59
48
|
catch (error) {
|
|
60
|
-
if (error
|
|
61
|
-
throw
|
|
62
|
-
}
|
|
63
|
-
logger.error("Failed to stat directory", error, {
|
|
64
|
-
...context,
|
|
65
|
-
operation,
|
|
66
|
-
path: sanitizedPath,
|
|
67
|
-
});
|
|
68
|
-
throw new McpError(BaseErrorCode.INTERNAL_ERROR, `Failed to access path: ${error.message}`, { context, operation });
|
|
49
|
+
if (error instanceof McpError)
|
|
50
|
+
throw error;
|
|
51
|
+
throw new McpError(BaseErrorCode.NOT_FOUND, `Directory does not exist or is inaccessible: ${sanitizedPath}`);
|
|
69
52
|
}
|
|
70
|
-
let isGitRepo =
|
|
53
|
+
let isGitRepo = await checkIsGitRepo(sanitizedPath);
|
|
71
54
|
let initializedRepo = false;
|
|
72
|
-
|
|
73
|
-
const { stdout } = await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
74
|
-
cwd: sanitizedPath,
|
|
75
|
-
});
|
|
76
|
-
if (stdout.trim() === "true") {
|
|
77
|
-
isGitRepo = true;
|
|
78
|
-
logger.debug("Path is already a Git repository", {
|
|
79
|
-
...context,
|
|
80
|
-
operation,
|
|
81
|
-
path: sanitizedPath,
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
logger.debug("Path is not a Git repository (rev-parse failed or returned non-true)", {
|
|
87
|
-
...context,
|
|
88
|
-
operation,
|
|
89
|
-
path: sanitizedPath,
|
|
90
|
-
error: error.message,
|
|
91
|
-
});
|
|
92
|
-
isGitRepo = false;
|
|
93
|
-
}
|
|
94
|
-
if (!isGitRepo && input.initializeIfNotPresent) {
|
|
95
|
-
logger.info(`Path is not a Git repository. Attempting to initialize (initializeIfNotPresent=true) with initial branch 'main'.`, { ...context, operation, path: sanitizedPath });
|
|
55
|
+
if (!isGitRepo && params.initializeIfNotPresent) {
|
|
96
56
|
try {
|
|
97
|
-
await execFileAsync("git", ["init", "--initial-branch=main"], {
|
|
98
|
-
cwd: sanitizedPath,
|
|
99
|
-
});
|
|
57
|
+
await execFileAsync("git", ["init", "--initial-branch=main"], { cwd: sanitizedPath });
|
|
100
58
|
initializedRepo = true;
|
|
101
|
-
isGitRepo = true;
|
|
102
|
-
logger.info('Successfully initialized Git repository with initial branch "main".', { ...context, operation, path: sanitizedPath });
|
|
59
|
+
isGitRepo = true;
|
|
103
60
|
}
|
|
104
61
|
catch (initError) {
|
|
105
|
-
|
|
106
|
-
...context,
|
|
107
|
-
operation,
|
|
108
|
-
path: sanitizedPath,
|
|
109
|
-
});
|
|
110
|
-
throw new McpError(BaseErrorCode.INTERNAL_ERROR, `Failed to initialize Git repository at ${sanitizedPath}: ${initError.message}`, { context, operation });
|
|
62
|
+
throw new McpError(BaseErrorCode.INTERNAL_ERROR, `Failed to initialize Git repository: ${initError.message}`);
|
|
111
63
|
}
|
|
112
64
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
logger.warning("Path is not a valid Git repository and initialization was not performed or failed.", { ...context, operation, path: sanitizedPath });
|
|
116
|
-
throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Path is not a valid Git repository: ${sanitizedPath}.`, { context, operation });
|
|
117
|
-
}
|
|
118
|
-
// --- Update Session State ---
|
|
119
|
-
// This part needs access to the session state mechanism defined in server.ts
|
|
120
|
-
// We assume the context provides a way to set the working directory for the current session.
|
|
121
|
-
try {
|
|
122
|
-
context.setWorkingDirectory(sanitizedPath);
|
|
123
|
-
const message = `Working directory set for session ${context.sessionId || "stdio"} to: ${sanitizedPath}`;
|
|
124
|
-
logger.info(message, { ...context, operation });
|
|
125
|
-
}
|
|
126
|
-
catch (error) {
|
|
127
|
-
logger.error("Failed to set working directory in session state", error, {
|
|
128
|
-
...context,
|
|
129
|
-
operation,
|
|
130
|
-
});
|
|
131
|
-
// This indicates an internal logic error in how state is passed/managed.
|
|
132
|
-
throw new McpError(BaseErrorCode.INTERNAL_ERROR, "Failed to update session state.", { context, operation });
|
|
133
|
-
}
|
|
134
|
-
let message = `Working directory set to: ${sanitizedPath}`;
|
|
135
|
-
if (initializedRepo) {
|
|
136
|
-
message += " (New Git repository initialized).";
|
|
137
|
-
}
|
|
138
|
-
else if (isGitRepo && input.validateGitRepo) {
|
|
139
|
-
// Only state "Existing" if validation was on and it passed
|
|
140
|
-
message += " (Existing Git repository).";
|
|
141
|
-
}
|
|
142
|
-
else if (isGitRepo && !input.validateGitRepo) {
|
|
143
|
-
// It is a git repo, but we weren't asked to validate it
|
|
144
|
-
message += " (Is a Git repository, validation skipped).";
|
|
145
|
-
}
|
|
146
|
-
else if (!isGitRepo &&
|
|
147
|
-
!input.validateGitRepo &&
|
|
148
|
-
!input.initializeIfNotPresent) {
|
|
149
|
-
// Not a git repo, validation off, no init request
|
|
150
|
-
message +=
|
|
151
|
-
" (Not a Git repository, validation skipped, no initialization requested).";
|
|
65
|
+
if (params.validateGitRepo && !isGitRepo) {
|
|
66
|
+
throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Path is not a valid Git repository: ${sanitizedPath}.`);
|
|
152
67
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
path: sanitizedPath,
|
|
157
|
-
initialized: initializedRepo,
|
|
158
|
-
};
|
|
68
|
+
context.setWorkingDirectory(sanitizedPath);
|
|
69
|
+
const message = `Working directory set to: ${sanitizedPath}${initializedRepo ? " (New repository initialized)." : ""}`;
|
|
70
|
+
return { success: true, message, path: sanitizedPath, initialized: initializedRepo };
|
|
159
71
|
}
|
|
@@ -1,94 +1,64 @@
|
|
|
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 & RequestContext (./utils/internal/requestContext.js)
|
|
3
|
-
import { GitSetWorkingDirInputSchema, gitSetWorkingDirLogic, } from "./logic.js";
|
|
4
|
-
let _getWorkingDirectory; // Added getter
|
|
5
|
-
let _setWorkingDirectory;
|
|
6
|
-
let _getSessionId;
|
|
7
1
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* @param getWdFn - Function to get the working directory for a session.
|
|
11
|
-
* @param setWdFn - Function to set the working directory for a session.
|
|
12
|
-
* @param getSidFn - Function to get the session ID from context.
|
|
2
|
+
* @fileoverview Handles registration and error handling for the git_set_working_dir tool.
|
|
3
|
+
* @module src/mcp-server/tools/gitSetWorkingDir/registration
|
|
13
4
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
_setWorkingDirectory = setWdFn;
|
|
18
|
-
_getSessionId = getSidFn;
|
|
19
|
-
logger.info("State accessors initialized for git_set_working_dir tool registration.");
|
|
20
|
-
}
|
|
5
|
+
import { ErrorHandler, logger, requestContextService } from "../../../utils/index.js";
|
|
6
|
+
import { McpError, BaseErrorCode } from "../../../types-global/errors.js";
|
|
7
|
+
import { gitSetWorkingDirLogic, GitSetWorkingDirInputSchema, GitSetWorkingDirOutputSchema, } from "./logic.js";
|
|
21
8
|
const TOOL_NAME = "git_set_working_dir";
|
|
22
9
|
const TOOL_DESCRIPTION = "Sets the default working directory for the current session. Subsequent Git tool calls within this session can use '.' for the `path` parameter, which will resolve to this directory. Optionally validates if the path is a Git repository (`validateGitRepo: true`). Can optionally initialize a Git repository with 'git init' if it's not already one and `initializeIfNotPresent: true` is set. Returns the result as a JSON object. IMPORTANT: The provided path must be absolute.";
|
|
23
10
|
/**
|
|
24
|
-
* Registers the git_set_working_dir tool with the MCP server.
|
|
25
|
-
*
|
|
26
|
-
* @param
|
|
27
|
-
* @
|
|
11
|
+
* Registers the git_set_working_dir tool with the MCP server instance.
|
|
12
|
+
* @param server The MCP server instance.
|
|
13
|
+
* @param setWorkingDirectory Function to set the session's working directory.
|
|
14
|
+
* @param getSessionId Function to get the session ID from context.
|
|
28
15
|
*/
|
|
29
|
-
export async
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
16
|
+
export const registerGitSetWorkingDirTool = async (server, setWorkingDirectory, getSessionId) => {
|
|
17
|
+
const operation = "registerGitSetWorkingDirTool";
|
|
18
|
+
const context = requestContextService.createRequestContext({ operation });
|
|
19
|
+
server.registerTool(TOOL_NAME, {
|
|
20
|
+
title: "Git Set Working Directory",
|
|
21
|
+
description: TOOL_DESCRIPTION,
|
|
22
|
+
inputSchema: GitSetWorkingDirInputSchema.shape,
|
|
23
|
+
outputSchema: GitSetWorkingDirOutputSchema.shape,
|
|
24
|
+
annotations: {
|
|
25
|
+
readOnlyHint: true, // Modifies session state, but not external files
|
|
26
|
+
destructiveHint: false,
|
|
27
|
+
idempotentHint: true,
|
|
28
|
+
openWorldHint: false,
|
|
29
|
+
},
|
|
30
|
+
}, async (params, callContext) => {
|
|
31
|
+
const handlerContext = requestContextService.createRequestContext({
|
|
32
|
+
toolName: TOOL_NAME,
|
|
33
|
+
parentContext: callContext,
|
|
34
|
+
});
|
|
35
|
+
try {
|
|
36
|
+
const sessionId = getSessionId(handlerContext);
|
|
37
|
+
const result = await gitSetWorkingDirLogic(params, {
|
|
38
|
+
...handlerContext,
|
|
39
|
+
setWorkingDirectory: (path) => setWorkingDirectory(sessionId, path),
|
|
43
40
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const setWorkingDirectoryForSession = (path) => {
|
|
48
|
-
_setWorkingDirectory(sessionId, path); // Non-null assertion
|
|
49
|
-
};
|
|
50
|
-
// Define the session-specific getter function (needed by logic?)
|
|
51
|
-
// If the logic needs the current WD, pass the getter too. Assuming it might.
|
|
52
|
-
const getWorkingDirectoryForSession = () => {
|
|
53
|
-
return _getWorkingDirectory(sessionId); // Non-null assertion
|
|
54
|
-
};
|
|
55
|
-
// Enhance context with session ID and the getter/setter functions
|
|
56
|
-
const logicContext = {
|
|
57
|
-
...requestContext,
|
|
58
|
-
sessionId: sessionId,
|
|
59
|
-
getWorkingDirectory: getWorkingDirectoryForSession, // Pass getter
|
|
60
|
-
setWorkingDirectory: setWorkingDirectoryForSession, // Pass setter
|
|
41
|
+
return {
|
|
42
|
+
structuredContent: result,
|
|
43
|
+
content: [{ type: "text", text: `Success: ${JSON.stringify(result, null, 2)}` }],
|
|
61
44
|
};
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
contentType: "application/json",
|
|
70
|
-
};
|
|
71
|
-
logger.info(`Tool ${TOOL_NAME} executed successfully`, {
|
|
72
|
-
...logicContext,
|
|
73
|
-
result,
|
|
74
|
-
});
|
|
75
|
-
return { content: [responseContent] };
|
|
76
|
-
}, {
|
|
77
|
-
operation,
|
|
78
|
-
context: logicContext,
|
|
79
|
-
input: validatedArgs, // Log sanitized input
|
|
80
|
-
errorCode: BaseErrorCode.INTERNAL_ERROR, // Default error code if logic fails unexpectedly
|
|
81
|
-
// toolName: TOOL_NAME, // Removed as it's not part of ErrorHandlerOptions
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
logger.error(`Error in ${TOOL_NAME} handler`, { error, ...handlerContext });
|
|
48
|
+
const handledError = ErrorHandler.handleError(error, {
|
|
49
|
+
operation: `tool:${TOOL_NAME}`,
|
|
50
|
+
context: handlerContext,
|
|
51
|
+
input: params,
|
|
82
52
|
});
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
}
|
|
53
|
+
const mcpError = handledError instanceof McpError
|
|
54
|
+
? handledError
|
|
55
|
+
: new McpError(BaseErrorCode.INTERNAL_ERROR, "An unexpected error occurred.", { originalError: handledError });
|
|
56
|
+
return {
|
|
57
|
+
isError: true,
|
|
58
|
+
content: [{ type: "text", text: mcpError.message }],
|
|
59
|
+
structuredContent: mcpError.details,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
logger.info(`Tool '${TOOL_NAME}' registered successfully.`, context);
|
|
64
|
+
};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Barrel file for the
|
|
3
|
-
*
|
|
2
|
+
* @fileoverview Barrel file for the gitShow tool.
|
|
3
|
+
* @module src/mcp-server/tools/gitShow/index
|
|
4
4
|
*/
|
|
5
|
-
export { registerGitShowTool
|
|
6
|
-
// Export types if needed elsewhere, e.g.:
|
|
7
|
-
// export type { GitShowInput, GitShowResult } from './logic.js';
|
|
5
|
+
export { registerGitShowTool } from "./registration.js";
|