UNPKG

@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,

80 lines (79 loc) 4.16 kB
// Import utils from barrel (ErrorHandler from ../utils/internal/errorHandler.js) import { ErrorHandler } from "../../../utils/index.js"; // Import utils from barrel (logger from ../utils/internal/logger.js) import { logger } from "../../../utils/index.js"; // Import utils from barrel (requestContextService, RequestContext from ../utils/internal/requestContext.js) import { requestContextService } from "../../../utils/index.js"; // Import the shape and the final schema/types import { BaseErrorCode } from "../../../types-global/errors.js"; // Keep direct import for types-global import { diffGitChanges, GitDiffInputShape, } from "./logic.js"; let _getWorkingDirectory; 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 getSidFn - Function to get the session ID from context. */ export function initializeGitDiffStateAccessors(getWdFn, getSidFn) { _getWorkingDirectory = getWdFn; _getSessionId = getSidFn; logger.info("State accessors initialized for git_diff tool registration."); } const TOOL_NAME = "git_diff"; 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."; /** * Registers the git_diff tool with the MCP server. * * @param {McpServer} server - The MCP server instance. * @throws {Error} If state accessors are not initialized. */ export async function registerGitDiffTool(server) { if (!_getWorkingDirectory || !_getSessionId) { throw new Error("State accessors for git_diff must be initialized before registration."); } const operation = "registerGitDiffTool"; const context = requestContextService.createRequestContext({ operation }); await ErrorHandler.tryCatch(async () => { // Use the exported shape for registration server.tool(TOOL_NAME, TOOL_DESCRIPTION, GitDiffInputShape, // Provide the Zod base schema shape async (validatedArgs, callContext) => { const toolOperation = "tool:git_diff"; 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}`, logicContext); return await ErrorHandler.tryCatch(async () => { // Call the core logic function const diffResult = await diffGitChanges(validatedArgs, logicContext); // Format the result (the diff string) as plain text within TextContent const resultContent = { type: "text", // Return the raw diff output directly text: diffResult.diff, // Indicate the content type is plain text diff contentType: "text/plain; charset=utf-8", // Or 'text/x-diff' }; logger.info(`Tool ${TOOL_NAME} executed successfully: ${diffResult.message}`, logicContext); // Success is determined by the logic function return { content: [resultContent] }; }, { operation: toolOperation, context: logicContext, input: validatedArgs, errorCode: BaseErrorCode.INTERNAL_ERROR, // Default if unexpected error in logic }); }); logger.info(`Tool registered: ${TOOL_NAME}`, context); }, { operation, context, critical: true }); }