Skip to main content
Glama

Git MCP Server

by Sheshiyer
base-operation.ts5.04 kB
import { CommandExecutor } from '../../utils/command.js'; import { PathValidator } from '../../utils/path.js'; import { logger } from '../../utils/logger.js'; import { repositoryCache } from '../../caching/repository-cache.js'; import { RepoStateType } from '../../caching/repository-cache.js'; import { GitToolContext, GitToolResult } from '../../types.js'; import { GitCommandBuilder } from '../../common/command-builder.js'; import { GitOperationOptions, GitOperationResult, CommandResult } from './operation-result.js'; import { ErrorHandler } from '../../errors/error-handler.js'; import { GitMcpError } from '../../errors/error-types.js'; /** * Base class for all Git operations providing common functionality */ export abstract class BaseGitOperation<TOptions extends GitOperationOptions, TResult = void> { protected constructor( protected readonly context: GitToolContext, protected readonly options: TOptions ) {} /** * Execute the Git operation with proper error handling and caching */ public async execute(): Promise<GitOperationResult<TResult>> { try { // Validate options before proceeding this.validateOptions(); // Get resolved path const path = this.getResolvedPath(); // Execute operation with caching if enabled const result = await this.executeWithCache(path); // Format the result return await this.formatResult(result); } catch (error: unknown) { return this.handleError(error); } } /** * Build the Git command for this operation */ protected abstract buildCommand(): GitCommandBuilder | Promise<GitCommandBuilder>; /** * Parse the command result into operation-specific format */ protected abstract parseResult(result: CommandResult): TResult | Promise<TResult>; /** * Get cache configuration for this operation */ protected abstract getCacheConfig(): { command: string; stateType?: RepoStateType; }; /** * Validate operation-specific options */ protected abstract validateOptions(): void; /** * Execute the Git command with caching if enabled */ private async executeWithCache(path: string): Promise<CommandResult> { const { command, stateType } = this.getCacheConfig(); const action = () => this.executeCommand(path); if (this.options.useCache && path) { if (stateType) { // Use state cache return await repositoryCache.getState( path, stateType, command, action ); } else { // Use command cache return await repositoryCache.getCommandResult( path, command, action ); } } // Execute without caching return await action(); } /** * Execute the Git command */ private async executeCommand(path: string): Promise<CommandResult> { const builder = await Promise.resolve(this.buildCommand()); const command = builder.toString(); return await CommandExecutor.executeGitCommand( command, this.context.operation, path ); } /** * Format the operation result into standard GitToolResult */ private async formatResult(result: CommandResult): Promise<GitOperationResult<TResult>> { return { success: true, data: await Promise.resolve(this.parseResult(result)), content: [{ type: 'text', text: CommandExecutor.formatOutput(result) }] }; } /** * Handle operation errors */ private handleError(error: unknown): GitOperationResult<TResult> { if (error instanceof GitMcpError) { return { success: false, error, content: [{ type: 'text', text: error.message }] }; } const wrappedError = ErrorHandler.handleOperationError( error instanceof Error ? error : new Error('Unknown error'), { operation: this.context.operation, path: this.options.path, command: this.getCacheConfig().command } ); return { success: false, error: wrappedError, content: [{ type: 'text', text: wrappedError.message }] }; } /** * Get resolved path with proper validation */ protected getResolvedPath(): string { const path = this.options.path || process.env.GIT_DEFAULT_PATH; if (!path) { throw ErrorHandler.handleValidationError( new Error('Path must be provided when GIT_DEFAULT_PATH is not set'), { operation: this.context.operation } ); } const { path: repoPath } = PathValidator.validateGitRepo(path); return repoPath; } /** * Invalidate cache if needed */ protected invalidateCache(path: string): void { if (this.options.invalidateCache) { const { command, stateType } = this.getCacheConfig(); if (stateType) { repositoryCache.invalidateState(path, stateType); } repositoryCache.invalidateCommand(path, command); } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Sheshiyer/git-mcp-v2'

If you have feedback or need assistance with the MCP directory API, please join our Discord server