/**
* GIT MCP Server Implementation
*
* Main MCP server class that handles tool registration and execution.
* Provides 17 specialized Git tools with multi-provider support.
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { GitWorkflowTool } from './tools/git-workflow.js';
import { GitBranchesTool } from './tools/git-branches.js';
import { GitFilesTool } from './tools/git-files.js';
import { GitIssuesTool } from './tools/git-issues.js';
import { GitPullsTool } from './tools/git-pulls.js';
import { GitTagsTool } from './tools/git-tags.js';
import { GitReleaseTool } from './tools/git-release.js';
import { GitRemoteTool } from './tools/git-remote.js';
import { GitResetTool } from './tools/git-reset.js';
import { GitStashTool } from './tools/git-stash.js';
import { GitConfigTool } from './tools/git-config.js';
import { GitMonitorTool } from './tools/git-monitor.js';
import { GitBackupTool } from './tools/git-backup.js';
import { GitArchiveTool } from './tools/git-archive.js';
import { GitSyncTool } from './tools/git-sync.js';
import { GitPackagesTool } from './tools/git-packages.js';
import { GitAnalyticsTool } from './tools/git-analytics.js';
import { GitUpdateTool } from './tools/git-update.js';
import { GitHistoryTool } from './tools/git-history.js';
import { getProviderConfig, configManager } from './config.js';
export class GitMCPServer {
private server: Server;
private transport: StdioServerTransport;
private gitWorkflowTool!: GitWorkflowTool;
private gitBranchesTool!: GitBranchesTool;
private gitFilesTool!: GitFilesTool;
private gitIssuesTool!: GitIssuesTool;
private gitPullsTool!: GitPullsTool;
private gitTagsTool!: GitTagsTool;
private gitReleaseTool!: GitReleaseTool;
private gitRemoteTool!: GitRemoteTool;
private gitResetTool!: GitResetTool;
private gitStashTool!: GitStashTool;
private gitConfigTool!: GitConfigTool;
private gitMonitorTool!: GitMonitorTool;
private gitBackupTool!: GitBackupTool;
private gitArchiveTool!: GitArchiveTool;
private gitSyncTool!: GitSyncTool;
private gitPackagesTool!: GitPackagesTool;
private gitAnalyticsTool!: GitAnalyticsTool;
private gitUpdateTool!: GitUpdateTool;
private gitHistoryTool!: GitHistoryTool;
constructor() {
try {
this.server = new Server(
{
name: 'git-mcp',
version: '1.0.0',
}
);
this.transport = new StdioServerTransport();
// Initialize tools with provider configuration
const providerConfig = getProviderConfig();
this.initializeTools(providerConfig);
this.setupHandlers();
console.error('GIT MCP Server initialized successfully');
} catch (error) {
console.error('Failed to initialize GIT MCP Server:', error);
throw error;
}
}
private initializeTools(providerConfig: any): void {
try {
// Initialize tools that require provider configuration
this.gitWorkflowTool = new GitWorkflowTool(providerConfig);
this.gitBranchesTool = new GitBranchesTool(providerConfig);
this.gitFilesTool = new GitFilesTool(providerConfig);
this.gitIssuesTool = new GitIssuesTool(providerConfig);
this.gitPullsTool = new GitPullsTool(providerConfig);
this.gitTagsTool = new GitTagsTool(providerConfig);
this.gitReleaseTool = new GitReleaseTool(providerConfig);
// Initialize tools that don't require provider configuration
this.gitRemoteTool = new GitRemoteTool();
this.gitResetTool = new GitResetTool(providerConfig);
this.gitStashTool = new GitStashTool();
this.gitConfigTool = new GitConfigTool();
this.gitMonitorTool = new GitMonitorTool();
this.gitBackupTool = new GitBackupTool();
this.gitArchiveTool = new GitArchiveTool();
// Initialize git-sync with provider configuration (for remote sync)
this.gitSyncTool = new GitSyncTool(providerConfig);
// Initialize git-packages and git-analytics with provider configuration
this.gitPackagesTool = new GitPackagesTool(providerConfig);
this.gitAnalyticsTool = new GitAnalyticsTool(providerConfig);
this.gitUpdateTool = new GitUpdateTool(providerConfig);
this.gitHistoryTool = new GitHistoryTool(providerConfig);
console.error(`Initialized ${this.getRegisteredToolsCount()} Git tools`);
} catch (error) {
console.error('Failed to initialize Git tools:', error);
throw error;
}
}
private setupHandlers(): void {
// List tools handler
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
GitWorkflowTool.getToolSchema(),
GitFilesTool.getToolSchema(),
GitBranchesTool.getToolSchema(),
GitIssuesTool.getToolSchema(),
GitPullsTool.getToolSchema(),
GitTagsTool.getToolSchema(),
GitReleaseTool.getToolSchema(),
GitRemoteTool.getToolSchema(),
GitResetTool.getToolSchema(),
GitStashTool.getToolSchema(),
GitConfigTool.getToolSchema(),
GitMonitorTool.getToolSchema(),
GitBackupTool.getToolSchema(),
GitArchiveTool.getToolSchema(),
GitSyncTool.getToolSchema(),
GitPackagesTool.getToolSchema(),
GitAnalyticsTool.getToolSchema(),
GitUpdateTool.getToolSchema(),
GitHistoryTool.getToolSchema()
]
};
});
// Call tool handler
this.server.setRequestHandler(CallToolRequestSchema, async (request: any) => {
const { name, arguments: args } = request.params;
try {
// Validate tool exists
if (!this.isValidTool(name)) {
throw new Error(`Unknown tool: ${name}. Available tools: ${this.getAvailableToolNames().join(', ')}`);
}
// Execute tool with proper error handling
const result = await this.executeTool(name, args);
// Format successful response
if (result.success) {
return {
content: [
{
type: 'text',
text: JSON.stringify(result.data, null, 2)
}
]
};
} else {
// Format error response with detailed information
return {
content: [
{
type: 'text',
text: this.formatErrorResponse(result.error, name, args)
}
],
isError: true
};
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
return {
content: [
{
type: 'text',
text: `Tool execution failed: ${errorMessage}\n\nTool: ${name}\nArguments: ${JSON.stringify(args, null, 2)}`
}
],
isError: true
};
}
});
// List resources handler
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: 'mcp-git://status',
name: 'Server Status',
description: 'Current server status and configuration',
mimeType: 'application/json'
},
{
uri: 'mcp-git://tools',
name: 'Available Tools',
description: 'List of all available Git tools with detailed information',
mimeType: 'application/json'
}
]
};
});
// Read resource handler
this.server.setRequestHandler(ReadResourceRequestSchema, async (request: any) => {
const { uri } = request.params;
try {
switch (uri) {
case 'mcp-git://status':
return this.getServerStatus(uri);
case 'mcp-git://tools':
return this.getToolsListing(uri);
default:
throw new Error(`Resource not found: ${uri}`);
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
throw new Error(`Failed to read resource ${uri}: ${errorMessage}`);
}
});
}
private getServerStatus(uri: string) {
const providerConfig = getProviderConfig();
const startTime = new Date().toISOString();
return {
contents: [
{
uri,
mimeType: 'application/json',
text: JSON.stringify({
status: 'running',
version: '1.0.0',
startTime,
server: {
name: 'git-mcp',
description: 'Professional MCP server for Git operations with multi-provider support'
},
providers: {
github: {
configured: !!providerConfig.github?.token,
username: providerConfig.github?.username || null,
status: providerConfig.github?.token ? 'ready' : 'not configured'
},
gitea: {
configured: !!providerConfig.gitea?.token,
url: providerConfig.gitea?.url || null,
username: providerConfig.gitea?.username || null,
status: providerConfig.gitea?.token ? 'ready' : 'not configured'
}
},
mode: configManager.getMode(),
universalMode: {
enabled: configManager.isUniversalMode(),
description: configManager.isUniversalMode()
? 'All operations automatically execute on both GitHub and Gitea providers'
: 'Use provider parameter to specify GitHub, Gitea, or both'
},
capabilities: {
tools: true,
resources: true,
prompts: false
},
toolsRegistered: this.getRegisteredToolsCount(),
environment: {
nodeVersion: process.version,
platform: process.platform
}
}, null, 2)
}
]
};
}
private getToolsListing(uri: string) {
const implementedTools = [
{
name: 'git-workflow',
description: 'Core Git workflow operations (init, commit, sync, create, list, etc.)',
category: 'Core Workflow',
operations: ['init', 'commit', 'sync', 'status', 'backup', 'create', 'list', 'get', 'update', 'delete', 'fork', 'search'],
implemented: true
},
{
name: 'git-files',
description: 'File management operations (CRUD, search, backup, list)',
category: 'File Management',
operations: ['read', 'create', 'update', 'delete', 'search', 'backup', 'list'],
implemented: true
},
{
name: 'git-branches',
description: 'Branch lifecycle management (create, merge, compare)',
category: 'Branch Management',
operations: ['create', 'list', 'get', 'delete', 'merge', 'compare'],
implemented: true
},
{
name: 'git-issues',
description: 'Issue lifecycle management (create, update, comment)',
category: 'Issue Management',
operations: ['create', 'list', 'get', 'update', 'close', 'comment', 'search'],
implemented: true
},
{
name: 'git-pulls',
description: 'Pull request management (create, review, merge)',
category: 'Pull Request Management',
operations: ['create', 'list', 'get', 'update', 'merge', 'close', 'review', 'search'],
implemented: true
},
{
name: 'git-tags',
description: 'Tag management operations (create, list, delete)',
category: 'Version Control',
operations: ['create', 'list', 'get', 'delete', 'search'],
implemented: true
},
{
name: 'git-release',
description: 'Release management (create, publish, download)',
category: 'Version Control',
operations: ['create', 'list', 'get', 'update', 'delete', 'publish', 'download'],
implemented: true
},
{
name: 'git-remote',
description: 'Remote repository management (add, remove, rename)',
category: 'Repository Operations',
operations: ['add', 'remove', 'rename', 'show', 'set-url', 'prune'],
implemented: true
},
{
name: 'git-reset',
description: 'Reset operations (soft, mixed, hard)',
category: 'Repository Operations',
operations: ['soft', 'mixed', 'hard', 'reset-to-commit', 'reset-branch'],
implemented: true
},
{
name: 'git-stash',
description: 'Stash management (stash, pop, apply)',
category: 'Repository Operations',
operations: ['stash', 'pop', 'apply', 'list', 'show', 'drop', 'clear'],
implemented: true
},
{
name: 'git-config',
description: 'Git configuration management (get, set, list)',
category: 'Configuration',
operations: ['get', 'set', 'unset', 'list', 'edit', 'show'],
implemented: true
},
{
name: 'git-monitor',
description: 'Monitoring and logging (log, status, commits)',
category: 'Monitoring',
operations: ['log', 'status', 'commits', 'contributors'],
implemented: true
},
{
name: 'git-backup',
description: 'Backup system (backup, restore, verify)',
category: 'Backup & Archive',
operations: ['backup', 'restore', 'list', 'verify'],
implemented: true
},
{
name: 'git-archive',
description: 'Archive operations (create, extract, verify)',
category: 'Backup & Archive',
operations: ['create', 'extract', 'list', 'verify'],
implemented: true
},
{
name: 'git-packages',
description: 'Package management (list, create, publish)',
category: 'Package Management',
operations: ['list', 'get', 'create', 'update', 'delete', 'publish', 'download'],
implemented: true
},
{
name: 'git-analytics',
description: 'Analytics and statistics (stats, commits, contributors)',
category: 'Analytics',
operations: ['stats', 'commits', 'contributors'],
implemented: true
},
{
name: 'git-sync',
description: 'Advanced synchronization (sync, status)',
category: 'Synchronization',
operations: ['sync', 'status'],
implemented: true
}
];
const implementedCount = implementedTools.filter(tool => tool.implemented).length;
const totalCount = implementedTools.length;
return {
contents: [
{
uri,
mimeType: 'application/json',
text: JSON.stringify({
totalTools: totalCount,
implementedTools: implementedCount,
pendingTools: totalCount - implementedCount,
tools: implementedTools,
categories: {
'Core Workflow': implementedTools.filter(t => t.category === 'Core Workflow').length,
'File Management': implementedTools.filter(t => t.category === 'File Management').length,
'Branch Management': implementedTools.filter(t => t.category === 'Branch Management').length,
'Issue Management': implementedTools.filter(t => t.category === 'Issue Management').length,
'Pull Request Management': implementedTools.filter(t => t.category === 'Pull Request Management').length,
'Version Control': implementedTools.filter(t => t.category === 'Version Control').length,
'Repository Operations': implementedTools.filter(t => t.category === 'Repository Operations').length,
'Configuration': implementedTools.filter(t => t.category === 'Configuration').length,
'Monitoring': implementedTools.filter(t => t.category === 'Monitoring').length,
'Backup & Archive': implementedTools.filter(t => t.category === 'Backup & Archive').length,
'Package Management': implementedTools.filter(t => t.category === 'Package Management').length,
'Analytics': implementedTools.filter(t => t.category === 'Analytics').length,
'Synchronization': implementedTools.filter(t => t.category === 'Synchronization').length
}
}, null, 2)
}
]
};
}
private isValidTool(toolName: string): boolean {
const validTools = [
'git-workflow', 'git-files', 'git-branches', 'git-issues', 'git-pulls',
'git-tags', 'git-release', 'git-remote', 'git-reset', 'git-stash',
'git-config', 'git-monitor', 'git-backup', 'git-archive', 'git-sync',
'git-packages', 'git-analytics', 'git-update', 'git-history'
];
return validTools.includes(toolName);
}
private getAvailableToolNames(): string[] {
return [
'git-workflow', 'git-files', 'git-branches', 'git-issues', 'git-pulls',
'git-tags', 'git-release', 'git-remote', 'git-reset', 'git-stash',
'git-config', 'git-monitor', 'git-backup', 'git-archive', 'git-sync',
'git-packages', 'git-analytics', 'git-update', 'git-history'
];
}
private async executeTool(name: string, args: any): Promise<any> {
switch (name) {
case 'git-workflow':
return await this.gitWorkflowTool.execute(args);
case 'git-files':
return await this.gitFilesTool.execute(args);
case 'git-branches':
return await this.gitBranchesTool.execute(args);
case 'git-issues':
return await this.gitIssuesTool.execute(args);
case 'git-pulls':
return await this.gitPullsTool.execute(args);
case 'git-tags':
return await this.gitTagsTool.execute(args);
case 'git-release':
return await this.gitReleaseTool.execute(args);
case 'git-remote':
return await this.gitRemoteTool.execute(args);
case 'git-reset':
return await this.gitResetTool.execute(args);
case 'git-stash':
return await this.gitStashTool.execute(args);
case 'git-config':
return await this.gitConfigTool.execute(args);
case 'git-monitor':
return await this.gitMonitorTool.execute(args);
case 'git-backup':
return await this.gitBackupTool.execute(args);
case 'git-archive':
return await this.gitArchiveTool.execute(args);
case 'git-sync':
return await this.gitSyncTool.execute(args);
case 'git-packages':
return await this.gitPackagesTool.execute(args);
case 'git-analytics':
return await this.gitAnalyticsTool.execute(args);
case 'git-update':
return await this.gitUpdateTool.execute(args);
case 'git-history':
return await this.gitHistoryTool.execute(args);
default:
throw new Error(`Tool execution not implemented: ${name}`);
}
}
private formatErrorResponse(error: any, toolName: string, args: any): string {
const errorInfo = {
tool: toolName,
error: {
message: error?.message || 'Unknown error',
code: error?.code || 'UNKNOWN_ERROR',
details: error?.details || null,
suggestions: error?.suggestions || []
},
arguments: args,
timestamp: new Date().toISOString()
};
return `Error executing ${toolName}:\n\n${JSON.stringify(errorInfo, null, 2)}`;
}
private getRegisteredToolsCount(): number {
// Count currently registered tools
return 18; // Currently 18 tools: workflow, files, branches, issues, pulls, tags, release, remote, reset, stash, config, monitor, backup, archive, sync, packages, analytics, update
}
async start(): Promise<void> {
try {
await this.server.connect(this.transport);
console.error('GIT MCP Server started successfully');
console.error(`Server capabilities: tools=${this.getRegisteredToolsCount()}, resources=2`);
// Log provider configuration status
const providerConfig = getProviderConfig();
const githubConfigured = !!providerConfig.github?.token;
const giteaConfigured = !!providerConfig.gitea?.token;
console.error(`Provider status: GitHub=${githubConfigured ? 'configured' : 'not configured'}, Gitea=${giteaConfigured ? 'configured' : 'not configured'}`);
// Log universal mode status
const mode = configManager.getMode();
console.error(`Operation mode: ${mode}`);
if (mode === 'universal') {
console.error('⚡ Universal mode active: All operations will execute on both providers');
if (!githubConfigured || !giteaConfigured) {
console.error('⚠️ Warning: Universal mode requires both providers configured');
}
}
} catch (error) {
console.error('Failed to start GIT MCP Server:', error);
throw error;
}
}
}