@cyanheads/git-mcp-server 2.1.8 → 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.
Files changed (79) hide show
  1. package/README.md +4 -4
  2. package/dist/mcp-server/server.js +69 -228
  3. package/dist/mcp-server/tools/gitAdd/index.js +2 -4
  4. package/dist/mcp-server/tools/gitAdd/logic.js +40 -116
  5. package/dist/mcp-server/tools/gitAdd/registration.js +39 -59
  6. package/dist/mcp-server/tools/gitBranch/index.js +3 -5
  7. package/dist/mcp-server/tools/gitBranch/logic.js +109 -304
  8. package/dist/mcp-server/tools/gitBranch/registration.js +52 -66
  9. package/dist/mcp-server/tools/gitCheckout/index.js +2 -3
  10. package/dist/mcp-server/tools/gitCheckout/logic.js +47 -144
  11. package/dist/mcp-server/tools/gitCheckout/registration.js +53 -72
  12. package/dist/mcp-server/tools/gitCherryPick/index.js +3 -5
  13. package/dist/mcp-server/tools/gitCherryPick/logic.js +47 -173
  14. package/dist/mcp-server/tools/gitCherryPick/registration.js +52 -67
  15. package/dist/mcp-server/tools/gitClean/index.js +3 -5
  16. package/dist/mcp-server/tools/gitClean/logic.js +45 -154
  17. package/dist/mcp-server/tools/gitClean/registration.js +52 -92
  18. package/dist/mcp-server/tools/gitClearWorkingDir/index.js +3 -5
  19. package/dist/mcp-server/tools/gitClearWorkingDir/logic.js +18 -32
  20. package/dist/mcp-server/tools/gitClearWorkingDir/registration.js +55 -73
  21. package/dist/mcp-server/tools/gitClone/index.js +2 -4
  22. package/dist/mcp-server/tools/gitClone/logic.js +47 -187
  23. package/dist/mcp-server/tools/gitClone/registration.js +51 -42
  24. package/dist/mcp-server/tools/gitCommit/index.js +2 -4
  25. package/dist/mcp-server/tools/gitCommit/logic.js +75 -310
  26. package/dist/mcp-server/tools/gitCommit/registration.js +52 -73
  27. package/dist/mcp-server/tools/gitDiff/index.js +2 -3
  28. package/dist/mcp-server/tools/gitDiff/logic.js +72 -264
  29. package/dist/mcp-server/tools/gitDiff/registration.js +53 -68
  30. package/dist/mcp-server/tools/gitFetch/index.js +2 -3
  31. package/dist/mcp-server/tools/gitFetch/logic.js +38 -136
  32. package/dist/mcp-server/tools/gitFetch/registration.js +54 -66
  33. package/dist/mcp-server/tools/gitInit/index.js +3 -5
  34. package/dist/mcp-server/tools/gitInit/logic.js +40 -162
  35. package/dist/mcp-server/tools/gitInit/registration.js +52 -104
  36. package/dist/mcp-server/tools/gitLog/index.js +2 -3
  37. package/dist/mcp-server/tools/gitLog/logic.js +71 -266
  38. package/dist/mcp-server/tools/gitLog/registration.js +54 -66
  39. package/dist/mcp-server/tools/gitMerge/index.js +3 -5
  40. package/dist/mcp-server/tools/gitMerge/logic.js +45 -191
  41. package/dist/mcp-server/tools/gitMerge/registration.js +52 -71
  42. package/dist/mcp-server/tools/gitPull/index.js +2 -3
  43. package/dist/mcp-server/tools/gitPull/logic.js +39 -156
  44. package/dist/mcp-server/tools/gitPull/registration.js +53 -75
  45. package/dist/mcp-server/tools/gitPush/index.js +2 -3
  46. package/dist/mcp-server/tools/gitPush/logic.js +65 -192
  47. package/dist/mcp-server/tools/gitPush/registration.js +53 -75
  48. package/dist/mcp-server/tools/gitRebase/index.js +3 -5
  49. package/dist/mcp-server/tools/gitRebase/logic.js +59 -207
  50. package/dist/mcp-server/tools/gitRebase/registration.js +52 -70
  51. package/dist/mcp-server/tools/gitRemote/index.js +3 -5
  52. package/dist/mcp-server/tools/gitRemote/logic.js +76 -200
  53. package/dist/mcp-server/tools/gitRemote/registration.js +52 -65
  54. package/dist/mcp-server/tools/gitReset/index.js +2 -3
  55. package/dist/mcp-server/tools/gitReset/logic.js +33 -133
  56. package/dist/mcp-server/tools/gitReset/registration.js +53 -60
  57. package/dist/mcp-server/tools/gitSetWorkingDir/index.js +3 -5
  58. package/dist/mcp-server/tools/gitSetWorkingDir/logic.js +39 -144
  59. package/dist/mcp-server/tools/gitSetWorkingDir/registration.js +55 -85
  60. package/dist/mcp-server/tools/gitShow/index.js +3 -5
  61. package/dist/mcp-server/tools/gitShow/logic.js +28 -133
  62. package/dist/mcp-server/tools/gitShow/registration.js +52 -74
  63. package/dist/mcp-server/tools/gitStash/index.js +3 -5
  64. package/dist/mcp-server/tools/gitStash/logic.js +59 -219
  65. package/dist/mcp-server/tools/gitStash/registration.js +52 -77
  66. package/dist/mcp-server/tools/gitStatus/index.js +2 -4
  67. package/dist/mcp-server/tools/gitStatus/logic.js +79 -236
  68. package/dist/mcp-server/tools/gitStatus/registration.js +52 -66
  69. package/dist/mcp-server/tools/gitTag/index.js +3 -5
  70. package/dist/mcp-server/tools/gitTag/logic.js +57 -198
  71. package/dist/mcp-server/tools/gitTag/registration.js +54 -73
  72. package/dist/mcp-server/tools/gitWorktree/index.js +3 -5
  73. package/dist/mcp-server/tools/gitWorktree/logic.js +102 -328
  74. package/dist/mcp-server/tools/gitWorktree/registration.js +54 -58
  75. package/dist/mcp-server/tools/gitWrapupInstructions/index.js +5 -3
  76. package/dist/mcp-server/tools/gitWrapupInstructions/logic.js +25 -43
  77. package/dist/mcp-server/tools/gitWrapupInstructions/registration.js +54 -70
  78. package/dist/mcp-server/transports/httpTransport.js +2 -3
  79. 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
- * Initializes the state accessors needed by the tool registration.
8
- * This should be called once during server setup.
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
- export function initializeGitResetStateAccessors(getWdFn, getSidFn) {
13
- _getWorkingDirectory = getWdFn;
14
- _getSessionId = getSidFn;
15
- logger.info("State accessors initialized for git_reset tool registration.");
16
- }
5
+ import { ErrorHandler, logger, requestContextService } from "../../../utils/index.js";
6
+ import { resetGitState, GitResetInputSchema, GitResetOutputSchema, } from "./logic.js";
17
7
  const TOOL_NAME = "git_reset";
18
8
  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
9
  /**
20
- * Registers the git_reset tool with the MCP server.
21
- *
22
- * @param {McpServer} server - The MCP server instance.
23
- * @throws {Error} If state accessors are not initialized.
10
+ * Registers the git_reset tool with the MCP server instance.
11
+ * @param server The MCP server instance.
12
+ * @param getWorkingDirectory Function to get the session's working directory.
13
+ * @param getSessionId Function to get the session ID from context.
24
14
  */
25
- export async function registerGitResetTool(server) {
26
- if (!_getWorkingDirectory || !_getSessionId) {
27
- throw new Error("State accessors for git_reset must be initialized before registration.");
28
- }
15
+ export const registerGitResetTool = async (server, getWorkingDirectory, getSessionId) => {
29
16
  const operation = "registerGitResetTool";
30
17
  const context = requestContextService.createRequestContext({ operation });
31
- await ErrorHandler.tryCatch(async () => {
32
- server.tool(TOOL_NAME, TOOL_DESCRIPTION, GitResetInputSchema.shape, // Provide the Zod schema shape
33
- async (validatedArgs, callContext) => {
34
- const toolOperation = "tool:git_reset";
35
- const requestContext = requestContextService.createRequestContext({
36
- operation: toolOperation,
37
- parentContext: callContext,
18
+ server.registerTool(TOOL_NAME, {
19
+ title: "Git Reset",
20
+ description: TOOL_DESCRIPTION,
21
+ inputSchema: GitResetInputSchema.shape,
22
+ outputSchema: GitResetOutputSchema.shape,
23
+ annotations: {
24
+ readOnlyHint: false,
25
+ destructiveHint: true, // Can be very destructive, especially in 'hard' mode
26
+ idempotentHint: false,
27
+ openWorldHint: false,
28
+ },
29
+ }, async (params, callContext) => {
30
+ const handlerContext = requestContextService.createRequestContext({
31
+ toolName: TOOL_NAME,
32
+ parentContext: callContext,
33
+ });
34
+ try {
35
+ const sessionId = getSessionId(handlerContext);
36
+ const result = await resetGitState(params, {
37
+ ...handlerContext,
38
+ getWorkingDirectory: () => getWorkingDirectory(sessionId),
38
39
  });
39
- const sessionId = _getSessionId(requestContext);
40
- const getWorkingDirectoryForSession = () => {
41
- return _getWorkingDirectory(sessionId);
42
- };
43
- const logicContext = {
44
- ...requestContext,
45
- sessionId: sessionId,
46
- getWorkingDirectory: getWorkingDirectoryForSession,
40
+ return {
41
+ structuredContent: result,
42
+ content: [{ type: "text", text: `Success: ${JSON.stringify(result, null, 2)}` }],
47
43
  };
48
- logger.info(`Executing tool: ${TOOL_NAME}`, logicContext);
49
- return await ErrorHandler.tryCatch(async () => {
50
- // Call the core logic function
51
- const resetResult = await resetGitState(validatedArgs, logicContext);
52
- // Format the result as a JSON string within TextContent
53
- const resultContent = {
54
- type: "text",
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
44
+ }
45
+ catch (error) {
46
+ logger.error(`Error in ${TOOL_NAME} handler`, { error, ...handlerContext });
47
+ const mcpError = ErrorHandler.handleError(error, {
48
+ operation: `tool:${TOOL_NAME}`,
49
+ context: handlerContext,
50
+ input: params,
67
51
  });
68
- });
69
- logger.info(`Tool registered: ${TOOL_NAME}`, context);
70
- }, { operation, context, critical: true });
71
- }
52
+ return {
53
+ isError: true,
54
+ content: [{ type: "text", text: `Error: ${mcpError.message}` }],
55
+ structuredContent: {
56
+ code: mcpError.code,
57
+ message: mcpError.message,
58
+ details: mcpError.details,
59
+ },
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 git_set_working_dir tool.
3
- * Exports the registration function and potentially other related components.
2
+ * @fileoverview Barrel file for the gitSetWorkingDir tool.
3
+ * @module src/mcp-server/tools/gitSetWorkingDir/index
4
4
  */
5
- export { registerGitSetWorkingDirTool, initializeGitSetWorkingDirStateAccessors, } from "./registration.js";
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,54 @@
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 { BaseErrorCode, McpError } from "../../../types-global/errors.js"; // Direct import for types-global
6
- import { logger, sanitization } from "../../../utils/index.js"; // RequestContext (./utils/internal/requestContext.js), logger (./utils/internal/logger.js), sanitization (./utils/security/sanitization.js)
9
+ import { logger, sanitization } from "../../../utils/index.js";
10
+ import { McpError, BaseErrorCode } from "../../../types-global/errors.js";
7
11
  const execFileAsync = promisify(execFile);
8
- // Define the Zod schema for input validation
12
+ // 1. DEFINE the Zod input schema.
9
13
  export const GitSetWorkingDirInputSchema = z.object({
10
- path: z
11
- .string()
12
- .min(1, "Path cannot be empty.")
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
  });
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) {
26
+ const { stdout } = await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], { cwd: path }).catch(() => ({ stdout: "false" }));
27
+ return stdout.trim() === "true";
28
+ }
24
29
  /**
25
- * Logic for the git_set_working_dir tool.
26
- * Sets a global working directory path for the current session.
27
- * Validates the path and optionally checks if it's a Git repository.
28
- *
29
- * @param {GitSetWorkingDirInput} input - The validated input arguments.
30
- * @param {RequestContext} context - The request context, potentially containing session ID.
31
- * @returns {Promise<GitSetWorkingDirResult>} The result of the operation.
32
- * @throws {McpError} Throws McpError for validation failures or operational errors.
30
+ * 4. IMPLEMENT the core logic function.
31
+ * @throws {McpError} If the logic encounters an unrecoverable issue.
33
32
  */
34
- export async function gitSetWorkingDirLogic(input, context) {
33
+ export async function gitSetWorkingDirLogic(params, context) {
35
34
  const operation = "gitSetWorkingDirLogic";
36
- logger.debug(`Executing ${operation}`, { ...context, input });
37
- let sanitizedPath;
38
- try {
39
- // Sanitize the path. Must explicitly allow absolute paths for this tool.
40
- // It normalizes and checks for traversal issues.
41
- sanitizedPath = sanitization.sanitizePath(input.path, {
42
- allowAbsolute: true,
43
- }).sanitizedPath;
44
- logger.debug(`Sanitized path: ${sanitizedPath}`, { ...context, operation });
35
+ logger.debug(`Executing ${operation}`, { ...context, params });
36
+ const sanitizedPath = sanitization.sanitizePath(params.path, { allowAbsolute: true }).sanitizedPath;
37
+ const stats = await fs.stat(sanitizedPath);
38
+ if (!stats.isDirectory()) {
39
+ throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Path is not a directory: ${sanitizedPath}`);
45
40
  }
46
- catch (error) {
47
- logger.error("Path sanitization failed", error, { ...context, operation });
48
- if (error instanceof McpError)
49
- throw error;
50
- throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Invalid path provided: ${error.message}`, { context, operation });
51
- }
52
- // Check if the directory exists
53
- try {
54
- const stats = await fs.stat(sanitizedPath);
55
- if (!stats.isDirectory()) {
56
- throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Path is not a directory: ${sanitizedPath}`, { context, operation });
57
- }
58
- }
59
- catch (error) {
60
- if (error.code === "ENOENT") {
61
- throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Directory does not exist: ${sanitizedPath}`, { context, operation });
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 });
69
- }
70
- let isGitRepo = false;
41
+ let isGitRepo = await checkIsGitRepo(sanitizedPath);
71
42
  let initializedRepo = false;
72
- try {
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 });
96
- try {
97
- await execFileAsync("git", ["init", "--initial-branch=main"], {
98
- cwd: sanitizedPath,
99
- });
100
- initializedRepo = true;
101
- isGitRepo = true; // Now it is a git repo
102
- logger.info('Successfully initialized Git repository with initial branch "main".', { ...context, operation, path: sanitizedPath });
103
- }
104
- catch (initError) {
105
- logger.error("Failed to initialize Git repository", initError, {
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 });
111
- }
112
- }
113
- // After potential initialization, if validateGitRepo is true, it must now be a Git repo.
114
- if (input.validateGitRepo && !isGitRepo) {
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).";
43
+ if (!isGitRepo && params.initializeIfNotPresent) {
44
+ await execFileAsync("git", ["init", "--initial-branch=main"], { cwd: sanitizedPath });
45
+ initializedRepo = true;
46
+ isGitRepo = true;
145
47
  }
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).";
48
+ if (params.validateGitRepo && !isGitRepo) {
49
+ throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Path is not a valid Git repository: ${sanitizedPath}.`);
152
50
  }
153
- return {
154
- success: true,
155
- message: message,
156
- path: sanitizedPath,
157
- initialized: initializedRepo,
158
- };
51
+ context.setWorkingDirectory(sanitizedPath);
52
+ const message = `Working directory set to: ${sanitizedPath}${initializedRepo ? " (New repository initialized)." : ""}`;
53
+ return { success: true, message, path: sanitizedPath, initialized: initializedRepo };
159
54
  }
@@ -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
- * Initializes the state accessors needed by the tool registration.
9
- * This should be called once during server setup.
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
- export function initializeGitSetWorkingDirStateAccessors(getWdFn, // Added getter parameter
15
- setWdFn, getSidFn) {
16
- _getWorkingDirectory = getWdFn; // Store getter
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 { gitSetWorkingDirLogic, GitSetWorkingDirInputSchema, GitSetWorkingDirOutputSchema, } from "./logic.js";
21
7
  const TOOL_NAME = "git_set_working_dir";
22
8
  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
9
  /**
24
- * Registers the git_set_working_dir tool with the MCP server.
25
- *
26
- * @param {McpServer} server - The MCP server instance.
27
- * @throws {Error} If state accessors are not initialized.
10
+ * Registers the git_set_working_dir tool with the MCP server instance.
11
+ * @param server The MCP server instance.
12
+ * @param setWorkingDirectory Function to set the session's working directory.
13
+ * @param getSessionId Function to get the session ID from context.
28
14
  */
29
- export async function registerGitSetWorkingDirTool(server) {
30
- // Check all required accessors
31
- if (!_getWorkingDirectory || !_setWorkingDirectory || !_getSessionId) {
32
- throw new Error("State accessors (getWD, setWD, getSID) for git_set_working_dir must be initialized before registration.");
33
- }
34
- try {
35
- server.tool(TOOL_NAME, TOOL_DESCRIPTION, GitSetWorkingDirInputSchema.shape, // Pass the shape for SDK validation
36
- async (validatedArgs, callContext) => {
37
- // Use callContext provided by SDK
38
- const operation = "tool:git_set_working_dir";
39
- // Create a request context, potentially inheriting from callContext if it provides relevant info
40
- const requestContext = requestContextService.createRequestContext({
41
- operation,
42
- parentContext: callContext,
15
+ export const registerGitSetWorkingDirTool = async (server, setWorkingDirectory, getSessionId) => {
16
+ const operation = "registerGitSetWorkingDirTool";
17
+ const context = requestContextService.createRequestContext({ operation });
18
+ server.registerTool(TOOL_NAME, {
19
+ title: "Git Set Working Directory",
20
+ description: TOOL_DESCRIPTION,
21
+ inputSchema: GitSetWorkingDirInputSchema.shape,
22
+ outputSchema: GitSetWorkingDirOutputSchema.shape,
23
+ annotations: {
24
+ readOnlyHint: true, // Modifies session state, but not external files
25
+ destructiveHint: false,
26
+ idempotentHint: true,
27
+ openWorldHint: false,
28
+ },
29
+ }, async (params, callContext) => {
30
+ const handlerContext = requestContextService.createRequestContext({
31
+ toolName: TOOL_NAME,
32
+ parentContext: callContext,
33
+ });
34
+ try {
35
+ const sessionId = getSessionId(handlerContext);
36
+ const result = await gitSetWorkingDirLogic(params, {
37
+ ...handlerContext,
38
+ setWorkingDirectory: (path) => setWorkingDirectory(sessionId, path),
43
39
  });
44
- // Get session ID using the accessor function
45
- const sessionId = _getSessionId(requestContext); // Non-null assertion as we checked initialization
46
- // Define the session-specific setter function
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
40
+ return {
41
+ structuredContent: result,
42
+ content: [{ type: "text", text: `Success: ${JSON.stringify(result, null, 2)}` }],
61
43
  };
62
- return await ErrorHandler.tryCatch(async () => {
63
- // Call the core logic function with validated args and enhanced context
64
- const result = await gitSetWorkingDirLogic(validatedArgs, logicContext);
65
- // Format the successful result for the MCP client
66
- const responseContent = {
67
- type: "text",
68
- text: JSON.stringify(result, null, 2), // Pretty-print JSON result
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
44
+ }
45
+ catch (error) {
46
+ logger.error(`Error in ${TOOL_NAME} handler`, { error, ...handlerContext });
47
+ const mcpError = ErrorHandler.handleError(error, {
48
+ operation: `tool:${TOOL_NAME}`,
49
+ context: handlerContext,
50
+ input: params,
82
51
  });
83
- });
84
- logger.info(`Tool registered: ${TOOL_NAME}`);
85
- }
86
- catch (error) {
87
- logger.error(`Failed to register tool: ${TOOL_NAME}`, {
88
- error: error instanceof Error ? error.message : String(error),
89
- stack: error instanceof Error ? error.stack : undefined,
90
- });
91
- // Propagate the error to prevent server startup if registration fails
92
- throw error;
93
- }
94
- }
52
+ return {
53
+ isError: true,
54
+ content: [{ type: "text", text: `Error: ${mcpError.message}` }],
55
+ structuredContent: {
56
+ code: mcpError.code,
57
+ message: mcpError.message,
58
+ details: mcpError.details,
59
+ },
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 git_show tool.
3
- * Exports the registration function and state accessor initialization function.
2
+ * @fileoverview Barrel file for the gitShow tool.
3
+ * @module src/mcp-server/tools/gitShow/index
4
4
  */
5
- export { registerGitShowTool, initializeGitShowStateAccessors, } from "./registration.js";
6
- // Export types if needed elsewhere, e.g.:
7
- // export type { GitShowInput, GitShowResult } from './logic.js';
5
+ export { registerGitShowTool } from "./registration.js";