@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,79 +1,64 @@
|
|
|
1
|
-
// Import utils from barrel (ErrorHandler from ../utils/internal/errorHandler.js)
|
|
2
|
-
import { ErrorHandler } from "../../../utils/index.js";
|
|
3
|
-
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
4
|
-
import { logger } from "../../../utils/index.js";
|
|
5
|
-
// Import utils from barrel (requestContextService, RequestContext from ../utils/internal/requestContext.js)
|
|
6
|
-
import { requestContextService } from "../../../utils/index.js";
|
|
7
|
-
// Import the shape and the final schema/types
|
|
8
|
-
import { BaseErrorCode } from "../../../types-global/errors.js"; // Keep direct import for types-global
|
|
9
|
-
import { diffGitChanges, GitDiffInputShape, } from "./logic.js";
|
|
10
|
-
let _getWorkingDirectory;
|
|
11
|
-
let _getSessionId;
|
|
12
1
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* @param getWdFn - Function to get the working directory for a session.
|
|
16
|
-
* @param getSidFn - Function to get the session ID from context.
|
|
2
|
+
* @fileoverview Handles registration and error handling for the git_diff tool.
|
|
3
|
+
* @module src/mcp-server/tools/gitDiff/registration
|
|
17
4
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
logger.info("State accessors initialized for git_diff tool registration.");
|
|
22
|
-
}
|
|
5
|
+
import { ErrorHandler, logger, requestContextService } from "../../../utils/index.js";
|
|
6
|
+
import { McpError, BaseErrorCode } from "../../../types-global/errors.js";
|
|
7
|
+
import { diffGitChanges, GitDiffOutputSchema, GitDiffBaseSchema, } from "./logic.js";
|
|
23
8
|
const TOOL_NAME = "git_diff";
|
|
24
9
|
const TOOL_DESCRIPTION = "Shows changes between commits, commit and working tree, etc. Can show staged changes or diff specific files. An optional 'includeUntracked' parameter (boolean) can be used to also show the content of untracked files. Returns the diff output as plain text.";
|
|
25
10
|
/**
|
|
26
|
-
* Registers the git_diff tool with the MCP server.
|
|
27
|
-
*
|
|
28
|
-
* @param
|
|
29
|
-
* @
|
|
11
|
+
* Registers the git_diff 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.
|
|
30
15
|
*/
|
|
31
|
-
export async
|
|
32
|
-
if (!_getWorkingDirectory || !_getSessionId) {
|
|
33
|
-
throw new Error("State accessors for git_diff must be initialized before registration.");
|
|
34
|
-
}
|
|
16
|
+
export const registerGitDiffTool = async (server, getWorkingDirectory, getSessionId) => {
|
|
35
17
|
const operation = "registerGitDiffTool";
|
|
36
18
|
const context = requestContextService.createRequestContext({ operation });
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
19
|
+
server.registerTool(TOOL_NAME, {
|
|
20
|
+
title: "Git Diff",
|
|
21
|
+
description: TOOL_DESCRIPTION,
|
|
22
|
+
inputSchema: GitDiffBaseSchema.shape,
|
|
23
|
+
outputSchema: GitDiffOutputSchema.shape,
|
|
24
|
+
annotations: {
|
|
25
|
+
readOnlyHint: true,
|
|
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 diffGitChanges(params, {
|
|
38
|
+
...handlerContext,
|
|
39
|
+
getWorkingDirectory: () => getWorkingDirectory(sessionId),
|
|
45
40
|
});
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
};
|
|
50
|
-
const logicContext = {
|
|
51
|
-
...requestContext,
|
|
52
|
-
sessionId: sessionId,
|
|
53
|
-
getWorkingDirectory: getWorkingDirectoryForSession,
|
|
41
|
+
return {
|
|
42
|
+
structuredContent: result,
|
|
43
|
+
content: [{ type: "text", text: result.diff, contentType: "text/plain; charset=utf-8" }],
|
|
54
44
|
};
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// Return the raw diff output directly
|
|
63
|
-
text: diffResult.diff,
|
|
64
|
-
// Indicate the content type is plain text diff
|
|
65
|
-
contentType: "text/plain; charset=utf-8", // Or 'text/x-diff'
|
|
66
|
-
};
|
|
67
|
-
logger.info(`Tool ${TOOL_NAME} executed successfully: ${diffResult.message}`, logicContext);
|
|
68
|
-
// Success is determined by the logic function
|
|
69
|
-
return { content: [resultContent] };
|
|
70
|
-
}, {
|
|
71
|
-
operation: toolOperation,
|
|
72
|
-
context: logicContext,
|
|
73
|
-
input: validatedArgs,
|
|
74
|
-
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,
|
|
75
52
|
});
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Barrel file for the gitFetch tool.
|
|
3
|
+
* @module src/mcp-server/tools/gitFetch/index
|
|
3
4
|
*/
|
|
4
|
-
export { registerGitFetchTool
|
|
5
|
-
// Export types if needed elsewhere, e.g.:
|
|
6
|
-
// export type { GitFetchInput, GitFetchResult } from './logic.js';
|
|
5
|
+
export { registerGitFetchTool } from "./registration.js";
|
|
@@ -1,149 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Defines the core logic, schemas, and types for the git_fetch tool.
|
|
3
|
+
* @module src/mcp-server/tools/gitFetch/logic
|
|
4
|
+
*/
|
|
1
5
|
import { execFile } from "child_process";
|
|
2
6
|
import { promisify } from "util";
|
|
3
7
|
import { z } from "zod";
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
// Import utils from barrel (RequestContext from ../utils/internal/requestContext.js)
|
|
7
|
-
import { BaseErrorCode, McpError } from "../../../types-global/errors.js"; // Keep direct import for types-global
|
|
8
|
-
// Import utils from barrel (sanitization from ../utils/security/sanitization.js)
|
|
9
|
-
import { sanitization } from "../../../utils/index.js";
|
|
8
|
+
import { logger, sanitization } from "../../../utils/index.js";
|
|
9
|
+
import { McpError, BaseErrorCode } from "../../../types-global/errors.js";
|
|
10
10
|
const execFileAsync = promisify(execFile);
|
|
11
|
-
//
|
|
11
|
+
// 1. DEFINE the Zod input schema.
|
|
12
12
|
export const GitFetchInputSchema = z.object({
|
|
13
|
-
path: z
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
prune: z
|
|
24
|
-
.boolean()
|
|
25
|
-
.optional()
|
|
26
|
-
.default(false)
|
|
27
|
-
.describe("Before fetching, remove any remote-tracking references that no longer exist on the remote."),
|
|
28
|
-
tags: z
|
|
29
|
-
.boolean()
|
|
30
|
-
.optional()
|
|
31
|
-
.default(false)
|
|
32
|
-
.describe("Fetch all tags from the remote (in addition to whatever else is fetched)."),
|
|
33
|
-
all: z.boolean().optional().default(false).describe("Fetch all remotes."),
|
|
34
|
-
// Add options like --depth, specific refspecs if needed
|
|
13
|
+
path: z.string().default(".").describe("Path to the Git repository. Defaults to the directory set via `git_set_working_dir` for the session; set 'git_set_working_dir' if not set."),
|
|
14
|
+
remote: z.string().optional().describe("The remote repository to fetch from (e.g., 'origin')."),
|
|
15
|
+
prune: z.boolean().default(false).describe("Remove remote-tracking references that no longer exist on the remote."),
|
|
16
|
+
tags: z.boolean().default(false).describe("Fetch all tags from the remote."),
|
|
17
|
+
all: z.boolean().default(false).describe("Fetch all remotes."),
|
|
18
|
+
});
|
|
19
|
+
// 2. DEFINE the Zod response schema.
|
|
20
|
+
export const GitFetchOutputSchema = z.object({
|
|
21
|
+
success: z.boolean().describe("Indicates if the command was successful."),
|
|
22
|
+
message: z.string().describe("A summary message of the result."),
|
|
35
23
|
});
|
|
36
24
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* @param {GitFetchInput} input - The validated input object.
|
|
40
|
-
* @param {RequestContext} context - The request context for logging and error handling.
|
|
41
|
-
* @returns {Promise<GitFetchResult>} A promise that resolves with the structured fetch result.
|
|
42
|
-
* @throws {McpError} Throws an McpError if path resolution, validation, or the git command fails unexpectedly.
|
|
25
|
+
* 4. IMPLEMENT the core logic function.
|
|
26
|
+
* @throws {McpError} If the logic encounters an unrecoverable issue.
|
|
43
27
|
*/
|
|
44
|
-
export async function fetchGitRemote(
|
|
28
|
+
export async function fetchGitRemote(params, context) {
|
|
45
29
|
const operation = "fetchGitRemote";
|
|
46
|
-
logger.debug(`Executing ${operation}`, { ...context,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (input.path && input.path !== ".") {
|
|
51
|
-
targetPath = input.path;
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
const workingDir = context.getWorkingDirectory();
|
|
55
|
-
if (!workingDir) {
|
|
56
|
-
throw new McpError(BaseErrorCode.VALIDATION_ERROR, "No path provided and no working directory set for the session.", { context, operation });
|
|
57
|
-
}
|
|
58
|
-
targetPath = workingDir;
|
|
59
|
-
}
|
|
60
|
-
targetPath = sanitization.sanitizePath(targetPath, {
|
|
61
|
-
allowAbsolute: true,
|
|
62
|
-
}).sanitizedPath;
|
|
63
|
-
logger.debug("Sanitized path", {
|
|
64
|
-
...context,
|
|
65
|
-
operation,
|
|
66
|
-
sanitizedPath: targetPath,
|
|
67
|
-
});
|
|
30
|
+
logger.debug(`Executing ${operation}`, { ...context, params });
|
|
31
|
+
const workingDir = context.getWorkingDirectory();
|
|
32
|
+
if (params.path === "." && !workingDir) {
|
|
33
|
+
throw new McpError(BaseErrorCode.VALIDATION_ERROR, "No session working directory set. Please specify a 'path' or use 'git_set_working_dir' first.");
|
|
68
34
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
35
|
+
const targetPath = sanitization.sanitizePath(params.path === "." ? workingDir : params.path, { allowAbsolute: true }).sanitizedPath;
|
|
36
|
+
const args = ["-C", targetPath, "fetch"];
|
|
37
|
+
if (params.prune)
|
|
38
|
+
args.push("--prune");
|
|
39
|
+
if (params.tags)
|
|
40
|
+
args.push("--tags");
|
|
41
|
+
if (params.all) {
|
|
42
|
+
args.push("--all");
|
|
43
|
+
}
|
|
44
|
+
else if (params.remote) {
|
|
45
|
+
args.push(params.remote);
|
|
78
46
|
}
|
|
79
47
|
try {
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
if (input.tags) {
|
|
86
|
-
args.push("--tags");
|
|
87
|
-
}
|
|
88
|
-
if (input.all) {
|
|
89
|
-
args.push("--all");
|
|
90
|
-
}
|
|
91
|
-
else if (input.remote) {
|
|
92
|
-
args.push(input.remote); // Fetch specific remote if 'all' is not used
|
|
93
|
-
}
|
|
94
|
-
// If neither 'all' nor 'remote' is specified, git fetch defaults to 'origin' or configured upstream.
|
|
95
|
-
logger.debug(`Executing command: git ${args.join(" ")}`, {
|
|
96
|
-
...context,
|
|
97
|
-
operation,
|
|
98
|
-
});
|
|
99
|
-
// Execute command. Fetch output is primarily on stderr.
|
|
100
|
-
const { stdout, stderr } = await execFileAsync("git", args);
|
|
101
|
-
logger.debug(`Git fetch stdout: ${stdout}`, { ...context, operation }); // stdout is usually empty
|
|
102
|
-
if (stderr) {
|
|
103
|
-
logger.debug(`Git fetch stderr: ${stderr}`, { ...context, operation }); // stderr contains fetch details
|
|
104
|
-
}
|
|
105
|
-
// Analyze stderr for success/summary
|
|
106
|
-
const message = "Fetch successful.";
|
|
107
|
-
const summary = stderr.trim() || "No changes detected.";
|
|
108
|
-
logger.info(message, {
|
|
109
|
-
...context,
|
|
110
|
-
operation,
|
|
111
|
-
path: targetPath,
|
|
112
|
-
summary,
|
|
113
|
-
});
|
|
114
|
-
return { success: true, message, summary };
|
|
48
|
+
logger.debug(`Executing command: git ${args.join(" ")}`, { ...context, operation });
|
|
49
|
+
const { stderr } = await execFileAsync("git", args);
|
|
50
|
+
const message = stderr.trim() || "Fetch successful.";
|
|
51
|
+
return { success: true, message };
|
|
115
52
|
}
|
|
116
53
|
catch (error) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
operation,
|
|
120
|
-
path: targetPath,
|
|
121
|
-
error: error.message,
|
|
122
|
-
stderr: error.stderr,
|
|
123
|
-
stdout: error.stdout,
|
|
124
|
-
});
|
|
125
|
-
const errorMessage = error.stderr || error.stdout || error.message || "";
|
|
126
|
-
// Handle specific error cases
|
|
54
|
+
const errorMessage = error.stderr || error.message || "";
|
|
55
|
+
logger.error(`Failed to execute git fetch command`, { ...context, operation, errorMessage });
|
|
127
56
|
if (errorMessage.toLowerCase().includes("not a git repository")) {
|
|
128
|
-
throw new McpError(BaseErrorCode.NOT_FOUND, `Path is not a Git repository: ${targetPath}
|
|
129
|
-
}
|
|
130
|
-
if (errorMessage.includes("resolve host") ||
|
|
131
|
-
errorMessage.includes("Could not read from remote repository") ||
|
|
132
|
-
errorMessage.includes("Connection timed out")) {
|
|
133
|
-
throw new McpError(BaseErrorCode.SERVICE_UNAVAILABLE, `Failed to connect to remote repository '${input.remote || "default"}'. Error: ${errorMessage}`, { context, operation, originalError: error });
|
|
134
|
-
}
|
|
135
|
-
if (errorMessage.includes("fatal: ") &&
|
|
136
|
-
errorMessage.includes("couldn't find remote ref")) {
|
|
137
|
-
throw new McpError(BaseErrorCode.NOT_FOUND, `Remote ref not found. Error: ${errorMessage}`, { context, operation, originalError: error });
|
|
57
|
+
throw new McpError(BaseErrorCode.NOT_FOUND, `Path is not a Git repository: ${targetPath}`);
|
|
138
58
|
}
|
|
139
|
-
if (errorMessage.includes("
|
|
140
|
-
|
|
141
|
-
throw new McpError(BaseErrorCode.UNAUTHORIZED, `Authentication failed for remote repository '${input.remote || "default"}'. Error: ${errorMessage}`, { context, operation, originalError: error });
|
|
59
|
+
if (errorMessage.includes("Could not read from remote repository")) {
|
|
60
|
+
throw new McpError(BaseErrorCode.SERVICE_UNAVAILABLE, `Failed to connect to remote repository '${params.remote || "default"}'.`);
|
|
142
61
|
}
|
|
143
|
-
if (errorMessage.includes("
|
|
144
|
-
throw new McpError(BaseErrorCode.
|
|
62
|
+
if (errorMessage.includes("Authentication failed")) {
|
|
63
|
+
throw new McpError(BaseErrorCode.UNAUTHORIZED, `Authentication failed for remote repository '${params.remote || "default"}'.`);
|
|
145
64
|
}
|
|
146
|
-
|
|
147
|
-
throw new McpError(BaseErrorCode.INTERNAL_ERROR, `Failed to git fetch for path: ${targetPath}. Error: ${errorMessage}`, { context, operation, originalError: error });
|
|
65
|
+
throw new McpError(BaseErrorCode.INTERNAL_ERROR, `Git fetch failed: ${errorMessage}`);
|
|
148
66
|
}
|
|
149
67
|
}
|
|
@@ -1,76 +1,64 @@
|
|
|
1
|
-
// Import utils from barrel (ErrorHandler from ../utils/internal/errorHandler.js)
|
|
2
|
-
import { ErrorHandler } from "../../../utils/index.js";
|
|
3
|
-
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
4
|
-
import { logger } from "../../../utils/index.js";
|
|
5
|
-
// Import utils from barrel (requestContextService, RequestContext from ../utils/internal/requestContext.js)
|
|
6
|
-
import { BaseErrorCode } from "../../../types-global/errors.js"; // Keep direct import for types-global
|
|
7
|
-
import { requestContextService } from "../../../utils/index.js";
|
|
8
|
-
import { fetchGitRemote, GitFetchInputSchema, } from "./logic.js";
|
|
9
|
-
let _getWorkingDirectory;
|
|
10
|
-
let _getSessionId;
|
|
11
1
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* @param getWdFn - Function to get the working directory for a session.
|
|
15
|
-
* @param getSidFn - Function to get the session ID from context.
|
|
2
|
+
* @fileoverview Handles registration and error handling for the git_fetch tool.
|
|
3
|
+
* @module src/mcp-server/tools/gitFetch/registration
|
|
16
4
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
logger.info("State accessors initialized for git_fetch tool registration.");
|
|
21
|
-
}
|
|
5
|
+
import { ErrorHandler, logger, requestContextService } from "../../../utils/index.js";
|
|
6
|
+
import { McpError, BaseErrorCode } from "../../../types-global/errors.js";
|
|
7
|
+
import { fetchGitRemote, GitFetchInputSchema, GitFetchOutputSchema, } from "./logic.js";
|
|
22
8
|
const TOOL_NAME = "git_fetch";
|
|
23
|
-
const TOOL_DESCRIPTION = "Downloads objects and refs from one or more
|
|
9
|
+
const TOOL_DESCRIPTION = "Downloads objects and refs from one or more repositories. Can fetch specific remotes or all, prune stale branches, and fetch tags.";
|
|
24
10
|
/**
|
|
25
|
-
* Registers the git_fetch tool with the MCP server.
|
|
26
|
-
*
|
|
27
|
-
* @param
|
|
28
|
-
* @
|
|
11
|
+
* Registers the git_fetch 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.
|
|
29
15
|
*/
|
|
30
|
-
export async
|
|
31
|
-
if (!_getWorkingDirectory || !_getSessionId) {
|
|
32
|
-
throw new Error("State accessors for git_fetch must be initialized before registration.");
|
|
33
|
-
}
|
|
16
|
+
export const registerGitFetchTool = async (server, getWorkingDirectory, getSessionId) => {
|
|
34
17
|
const operation = "registerGitFetchTool";
|
|
35
18
|
const context = requestContextService.createRequestContext({ operation });
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
19
|
+
server.registerTool(TOOL_NAME, {
|
|
20
|
+
title: "Git Fetch",
|
|
21
|
+
description: TOOL_DESCRIPTION,
|
|
22
|
+
inputSchema: GitFetchInputSchema.shape,
|
|
23
|
+
outputSchema: GitFetchOutputSchema.shape,
|
|
24
|
+
annotations: {
|
|
25
|
+
readOnlyHint: false, // Modifies local refs
|
|
26
|
+
destructiveHint: false,
|
|
27
|
+
idempotentHint: false,
|
|
28
|
+
openWorldHint: true, // Interacts with remote repositories
|
|
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 fetchGitRemote(params, {
|
|
38
|
+
...handlerContext,
|
|
39
|
+
getWorkingDirectory: () => getWorkingDirectory(sessionId),
|
|
43
40
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
};
|
|
48
|
-
const logicContext = {
|
|
49
|
-
...requestContext,
|
|
50
|
-
sessionId: sessionId,
|
|
51
|
-
getWorkingDirectory: getWorkingDirectoryForSession,
|
|
41
|
+
return {
|
|
42
|
+
structuredContent: result,
|
|
43
|
+
content: [{ type: "text", text: `Success: ${JSON.stringify(result, null, 2)}` }],
|
|
52
44
|
};
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// Stringify the entire GitFetchResult object
|
|
61
|
-
text: JSON.stringify(fetchResult, null, 2), // Pretty-print JSON
|
|
62
|
-
contentType: "application/json",
|
|
63
|
-
};
|
|
64
|
-
logger.info(`Tool ${TOOL_NAME} executed successfully: ${fetchResult.message}`, logicContext);
|
|
65
|
-
// Success is determined by the logic function and included in the result object
|
|
66
|
-
return { content: [resultContent] };
|
|
67
|
-
}, {
|
|
68
|
-
operation: toolOperation,
|
|
69
|
-
context: logicContext,
|
|
70
|
-
input: validatedArgs,
|
|
71
|
-
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,
|
|
72
52
|
});
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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 gitInit tool.
|
|
3
|
+
* @module src/mcp-server/tools/gitInit/index
|
|
4
4
|
*/
|
|
5
|
-
export { registerGitInitTool
|
|
6
|
-
// Export types if needed elsewhere, e.g.:
|
|
7
|
-
// export type { GitInitInput, GitInitResult } from './logic.js';
|
|
5
|
+
export { registerGitInitTool } from "./registration.js";
|