@0xshariq/github-mcp-server
Version:
A comprehensive Model Context Protocol (MCP) server that provides Git repository management capabilities for AI assistants and automation tools. Includes 29 Git operations + 11 workflow combinations with complete CLI alias system and advanced developer pr
158 lines (138 loc) • 6.59 kB
JavaScript
import { spawn, execSync } from 'child_process';
import path from 'path';
import chalk from 'chalk';
import { fileURLToPath } from 'url';
import fs from 'fs';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Get the command name from the actual command used to invoke this script
// Handle both direct calls and npm symlinks
const fullPath = process.argv[1];
let commandName = path.basename(fullPath);
// Special case: if we get gms as command name but have args,
// and the first arg looks like a g* command, use that instead
if (commandName === 'gms' && process.argv.length > 2) {
const potentialCommand = process.argv[2];
if (potentialCommand && potentialCommand.startsWith('g')) {
// Check if this looks like a git command being forwarded incorrectly
// This happens when the system interprets gstatus as "gms git-status"
if (potentialCommand.includes('-')) {
// Convert "git-status" back to "gstatus", "add-all" to "gadd", etc.
const parts = potentialCommand.split('-');
if (parts[0] === 'git') {
commandName = 'g' + parts[1];
} else if (parts.length === 2) {
// Handle cases like "add-all" -> "gadd"
commandName = 'g' + parts[0];
} else {
commandName = potentialCommand.replace('-', '');
}
// Remove this argument from process.argv so it doesn't get passed to the script
process.argv.splice(2, 1);
} else {
commandName = potentialCommand;
}
}
}
// Alias mapping for routing commands to their respective scripts
const aliasMap = {
// Basic Git operations
'gadd': { script: 'bin/basic/gadd.js', description: 'Add files to staging' },
'gcommit': { script: 'bin/basic/gcommit.js', description: 'Commit changes' },
'ginit': { script: 'bin/basic/ginit.js', description: 'Initialize repository' },
'gstatus': { script: 'bin/basic/gstatus.js', description: 'Show repository status' },
'gpush': { script: 'bin/basic/gpush.js', description: 'Push changes to remote' },
'gpull': { script: 'bin/basic/gpull.js', description: 'Pull changes from remote' },
'gbranch': { script: 'bin/basic/gbranch.js', description: 'Branch operations' },
'gcheckout': { script: 'bin/basic/gcheckout.js', description: 'Switch branches' },
'gclone': { script: 'bin/basic/gclone.js', description: 'Clone repository' },
'gdiff': { script: 'bin/basic/gdiff.js', description: 'Show differences' },
'glog': { script: 'bin/basic/glog.js', description: 'Show commit history' },
'gremote': { script: 'bin/basic/gremote.js', description: 'Remote operations' },
'greset': { script: 'bin/basic/greset.js', description: 'Reset repository state' },
'gstash': { script: 'bin/basic/gstash.js', description: 'Stash operations' },
'gpop': { script: 'bin/basic/gpop.js', description: 'Pop stash' },
// Advanced Git operations
'gbackup': { script: 'bin/advanced/gbackup.js', description: 'Backup current state' },
'gclean': { script: 'bin/advanced/gclean.js', description: 'Clean repository' },
'gdev': { script: 'bin/advanced/gdev.js', description: 'Development workflow' },
'gfix': { script: 'bin/advanced/gfix.js', description: 'Fix operations' },
'gflow': { script: 'bin/advanced/gflow.js', description: 'Complete workflow' },
'gfresh': { script: 'bin/advanced/gfresh.js', description: 'Fresh start' },
'glist': { script: 'bin/advanced/glist.js', description: 'List repositories' },
'gquick': { script: 'bin/advanced/gquick.js', description: 'Quick commit' },
'grelease': { script: 'bin/advanced/grelease.js', description: 'Release workflow' },
'gsave': { script: 'bin/advanced/gsave.js', description: 'Save current state' },
'gsync': { script: 'bin/advanced/gsync.js', description: 'Synchronize repository' },
'gworkflow': { script: 'bin/advanced/gworkflow.js', description: 'Complete workflow' }
};
// Main execution function
async function main() {
const args = process.argv.slice(2);
// Detect if we're being called as an alias (e.g., gbranch, gadd, etc.)
let command;
let commandArgs = args;
if (commandName === 'mcp-cli.js' || commandName === 'gms' || commandName === 'github-mcp-server') {
// Called as main CLI - command is first argument
if (args.length === 0) {
showUsage();
return;
}
command = args[0];
commandArgs = args.slice(1);
} else {
// Called as alias (e.g., gbranch, gadd, etc.)
command = commandName;
commandArgs = args;
}
// Check if it's a valid alias and route to script
if (aliasMap[command] && aliasMap[command].script) {
const scriptPath = path.join(__dirname, aliasMap[command].script);
// Check if script exists
if (!fs.existsSync(scriptPath)) {
console.error(chalk.red.bold('❌ Script not found:'), scriptPath);
process.exit(1);
}
// Execute the script with the provided arguments
const childProcess = spawn('node', [scriptPath, ...commandArgs], {
stdio: 'inherit',
cwd: process.cwd()
});
childProcess.on('close', (code) => {
process.exit(code);
});
childProcess.on('error', (err) => {
console.error(chalk.red.bold('❌ Error executing script:'), err.message);
process.exit(1);
});
} else {
console.error(chalk.red.bold(`❌ Unknown command: ${command}`));
showUsage();
process.exit(1);
}
}
function showUsage() {
console.log();
console.log(chalk.bold.cyan('🚀 MCP Git CLI') + chalk.gray(' - ') + chalk.bold.white('Enhanced Git Operations'));
console.log(chalk.dim('═'.repeat(60)));
console.log();
console.log(chalk.bold.yellow('Basic Operations:'));
console.log(chalk.green(' gadd, gcommit, ginit, gstatus, gpush, gpull'));
console.log(chalk.green(' gbranch, gcheckout, gclone, gdiff, glog'));
console.log(chalk.green(' gremote, greset, gstash, gpop'));
console.log();
console.log(chalk.bold.yellow('Advanced Operations:'));
console.log(chalk.green(' gbackup, gclean, gdev, gfix, gflow, gfresh'));
console.log(chalk.green(' glist, gquick, grelease, gsave, gsync, gworkflow'));
console.log();
console.log(chalk.bold.yellow('Usage:'));
console.log(chalk.blue(' mcp-cli <command> [arguments]'));
console.log(chalk.blue(' <command> --help') + chalk.gray(' Show help for specific command'));
console.log();
}
// ESM module detection and execution - always run main if this is the primary module
main().catch((error) => {
console.error(chalk.red.bold('❌ Fatal error:'), error.message);
process.exit(1);
});