@cyanheads/git-mcp-server
Version:
An MCP (Model Context Protocol) server enabling LLMs and AI agents to interact with Git repositories. Provides tools for comprehensive Git operations including clone, commit, branch, diff, log, status, push, pull, merge, rebase, worktree, tag management,
78 lines (77 loc) • 4.21 kB
JavaScript
import { BaseErrorCode } from "../../../types-global/errors.js"; // Direct import for types-global
import { ErrorHandler, logger, requestContextService, } from "../../../utils/index.js"; // ErrorHandler (./utils/internal/errorHandler.js), logger (./utils/internal/logger.js), requestContextService (./utils/internal/requestContext.js)
import { GitRemoteInputSchema, gitRemoteLogic, } from "./logic.js";
let _getWorkingDirectory;
let _getSessionId;
/**
* Initializes the state accessors needed by the git_remote tool registration.
* @param getWdFn - Function to get the working directory for a session.
* @param getSidFn - Function to get the session ID from context.
*/
export function initializeGitRemoteStateAccessors(getWdFn, getSidFn) {
_getWorkingDirectory = getWdFn;
_getSessionId = getSidFn;
logger.info("State accessors initialized for git_remote tool registration.");
}
const TOOL_NAME = "git_remote";
const TOOL_DESCRIPTION = "Manages remote repositories (list, add, remove, show).";
/**
* Registers the git_remote tool with the MCP server.
*
* @param {McpServer} server - The McpServer instance to register the tool with.
* @returns {Promise<void>}
* @throws {Error} If registration fails or state accessors are not initialized.
*/
export const registerGitRemoteTool = async (server) => {
if (!_getWorkingDirectory || !_getSessionId) {
throw new Error("State accessors for git_remote must be initialized before registration.");
}
const operation = "registerGitRemoteTool";
const context = requestContextService.createRequestContext({ operation });
await ErrorHandler.tryCatch(async () => {
server.tool(TOOL_NAME, TOOL_DESCRIPTION, GitRemoteInputSchema.shape, // Provide the Zod schema shape
async (validatedArgs, callContext) => {
const toolOperation = `tool:${TOOL_NAME}:${validatedArgs.mode}`; // Include mode in operation
const requestContext = requestContextService.createRequestContext({
operation: toolOperation,
parentContext: callContext,
});
const sessionId = _getSessionId(requestContext);
const getWorkingDirectoryForSession = () => {
return _getWorkingDirectory(sessionId);
};
const logicContext = {
...requestContext,
sessionId: sessionId,
getWorkingDirectory: getWorkingDirectoryForSession,
};
logger.info(`Executing tool: ${TOOL_NAME} (mode: ${validatedArgs.mode})`, logicContext);
return await ErrorHandler.tryCatch(async () => {
// Call the core logic function which returns a GitRemoteResult object
const remoteResult = await gitRemoteLogic(validatedArgs, logicContext);
// Format the result as a JSON string within TextContent
const resultContent = {
type: "text",
text: JSON.stringify(remoteResult, null, 2), // Pretty-print JSON
contentType: "application/json",
};
// Log based on the success flag in the result
if (remoteResult.success) {
logger.info(`Tool ${TOOL_NAME} (mode: ${validatedArgs.mode}) executed successfully, returning JSON`, logicContext);
}
else {
// Log specific failure message from the result
logger.warning(`Tool ${TOOL_NAME} (mode: ${validatedArgs.mode}) failed: ${remoteResult.message}`, { ...logicContext, errorDetails: remoteResult.error });
}
// Return the result, whether success or structured failure
return { content: [resultContent] };
}, {
operation: toolOperation,
context: logicContext,
input: validatedArgs,
errorCode: BaseErrorCode.INTERNAL_ERROR, // Default if unexpected error occurs in logic/wrapper
});
});
logger.info(`Tool registered: ${TOOL_NAME}`, context);
}, { operation, context, critical: true }); // Mark registration as critical
};