@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,
95 lines (94 loc) • 5.39 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 & RequestContext (./utils/internal/requestContext.js)
import { GitSetWorkingDirInputSchema, gitSetWorkingDirLogic, } from "./logic.js";
let _getWorkingDirectory; // Added getter
let _setWorkingDirectory;
let _getSessionId;
/**
* Initializes the state accessors needed by the tool registration.
* This should be called once during server setup.
* @param getWdFn - Function to get the working directory for a session.
* @param setWdFn - Function to set the working directory for a session.
* @param getSidFn - Function to get the session ID from context.
*/
export function initializeGitSetWorkingDirStateAccessors(getWdFn, // Added getter parameter
setWdFn, getSidFn) {
_getWorkingDirectory = getWdFn; // Store getter
_setWorkingDirectory = setWdFn;
_getSessionId = getSidFn;
logger.info("State accessors initialized for git_set_working_dir tool registration.");
}
const TOOL_NAME = "git_set_working_dir";
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.";
/**
* Registers the git_set_working_dir tool with the MCP server.
*
* @param {McpServer} server - The MCP server instance.
* @throws {Error} If state accessors are not initialized.
*/
export async function registerGitSetWorkingDirTool(server) {
// Check all required accessors
if (!_getWorkingDirectory || !_setWorkingDirectory || !_getSessionId) {
throw new Error("State accessors (getWD, setWD, getSID) for git_set_working_dir must be initialized before registration.");
}
try {
server.tool(TOOL_NAME, TOOL_DESCRIPTION, GitSetWorkingDirInputSchema.shape, // Pass the shape for SDK validation
async (validatedArgs, callContext) => {
// Use callContext provided by SDK
const operation = "tool:git_set_working_dir";
// Create a request context, potentially inheriting from callContext if it provides relevant info
const requestContext = requestContextService.createRequestContext({
operation,
parentContext: callContext,
});
// Get session ID using the accessor function
const sessionId = _getSessionId(requestContext); // Non-null assertion as we checked initialization
// Define the session-specific setter function
const setWorkingDirectoryForSession = (path) => {
_setWorkingDirectory(sessionId, path); // Non-null assertion
};
// Define the session-specific getter function (needed by logic?)
// If the logic needs the current WD, pass the getter too. Assuming it might.
const getWorkingDirectoryForSession = () => {
return _getWorkingDirectory(sessionId); // Non-null assertion
};
// Enhance context with session ID and the getter/setter functions
const logicContext = {
...requestContext,
sessionId: sessionId,
getWorkingDirectory: getWorkingDirectoryForSession, // Pass getter
setWorkingDirectory: setWorkingDirectoryForSession, // Pass setter
};
return await ErrorHandler.tryCatch(async () => {
// Call the core logic function with validated args and enhanced context
const result = await gitSetWorkingDirLogic(validatedArgs, logicContext);
// Format the successful result for the MCP client
const responseContent = {
type: "text",
text: JSON.stringify(result, null, 2), // Pretty-print JSON result
contentType: "application/json",
};
logger.info(`Tool ${TOOL_NAME} executed successfully`, {
...logicContext,
result,
});
return { content: [responseContent] };
}, {
operation,
context: logicContext,
input: validatedArgs, // Log sanitized input
errorCode: BaseErrorCode.INTERNAL_ERROR, // Default error code if logic fails unexpectedly
// toolName: TOOL_NAME, // Removed as it's not part of ErrorHandlerOptions
});
});
logger.info(`Tool registered: ${TOOL_NAME}`);
}
catch (error) {
logger.error(`Failed to register tool: ${TOOL_NAME}`, {
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
});
// Propagate the error to prevent server startup if registration fails
throw error;
}
}