Skip to main content
Glama
blade47

ShadowGit MCP Server

by blade47
shadowgit-mcp-server.ts8.46 kB
/** * ShadowGit MCP Server - Main Entry Point * Provides read-only Git access, session management and checkpoint creation for AI assistants */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import { log } from './utils/logger'; import { VERSION } from './utils/constants'; import { RepositoryManager } from './core/repository-manager'; import { GitExecutor } from './core/git-executor'; import { SessionClient } from './core/session-client'; import { GitHandler } from './handlers/git-handler'; import { ListReposHandler } from './handlers/list-repos-handler'; import { CheckpointHandler } from './handlers/checkpoint-handler'; import { SessionHandler } from './handlers/session-handler'; export class ShadowGitMCPServer { private server: Server; private repositoryManager: RepositoryManager; private gitExecutor: GitExecutor; private sessionClient: SessionClient; private gitHandler: GitHandler; private listReposHandler: ListReposHandler; private checkpointHandler: CheckpointHandler; private sessionHandler: SessionHandler; constructor() { // Initialize core services this.repositoryManager = new RepositoryManager(); this.gitExecutor = new GitExecutor(); this.sessionClient = new SessionClient(); // Initialize handlers this.gitHandler = new GitHandler(this.repositoryManager, this.gitExecutor); this.listReposHandler = new ListReposHandler(this.repositoryManager); this.checkpointHandler = new CheckpointHandler( this.repositoryManager, this.gitExecutor ); this.sessionHandler = new SessionHandler( this.repositoryManager, this.sessionClient ); // Initialize MCP server this.server = new Server( { name: 'shadowgit-mcp-server', version: VERSION, }, { capabilities: { tools: {}, }, } ); this.setupHandlers(); } private setupHandlers(): void { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'list_repos', description: 'List all available ShadowGit repositories. Use this first to discover which repositories you can work with.', inputSchema: { type: 'object', properties: {}, }, }, { name: 'git_command', description: 'Execute a read-only git command on a ShadowGit repository. Only safe, read-only commands are allowed.', inputSchema: { type: 'object', properties: { repo: { type: 'string', description: 'Repository name (use list_repos to see available repositories)', }, command: { type: 'string', description: 'Git command to execute (e.g., "log -10", "diff HEAD~1", "status")', }, }, required: ['repo', 'command'], }, }, { name: 'start_session', description: 'Start a work session. MUST be called BEFORE making any changes. Without this, ShadowGit will create fragmented auto-commits during your work!', inputSchema: { type: 'object', properties: { repo: { type: 'string', description: 'Repository name', }, description: { type: 'string', description: 'What you plan to do in this session', }, }, required: ['repo', 'description'], }, }, { name: 'checkpoint', description: 'Create a git commit with your changes. Call this AFTER completing your work but BEFORE end_session. Creates a clean commit for the user to review.', inputSchema: { type: 'object', properties: { repo: { type: 'string', description: 'Repository name', }, title: { type: 'string', description: 'Commit title (max 50 chars) - REQUIRED. Be specific about what was changed.', }, message: { type: 'string', description: 'Detailed commit message (optional, max 1000 chars)', }, author: { type: 'string', description: 'Author name (e.g., "Claude", "GPT-4"). Defaults to "AI Assistant"', }, }, required: ['repo', 'title'], }, }, { name: 'end_session', description: 'End your work session to resume ShadowGit auto-commits. MUST be called AFTER checkpoint to properly close your work session.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session ID from start_session', }, commitHash: { type: 'string', description: 'Commit hash from checkpoint (optional)', }, }, required: ['sessionId'], }, } ], })); // Handle tool execution this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; log('info', `Tool called: ${name}`); try { switch (name) { case 'list_repos': return await this.listReposHandler.handle(); case 'git_command': return await this.gitHandler.handle(args); case 'start_session': return await this.sessionHandler.startSession(args); case 'checkpoint': return await this.checkpointHandler.handle(args); case 'end_session': return await this.sessionHandler.endSession(args); default: return { content: [ { type: 'text', text: `Unknown tool: ${name}. Available tools: list_repos, git_command, start_session, checkpoint, end_session`, }, ], }; } } catch (error) { log('error', `Tool execution error: ${error}`); return { content: [ { type: 'text', text: `Error executing ${name}: ${error}`, }, ], }; } }); } async start(): Promise<void> { log('info', `Starting ShadowGit MCP Server v${VERSION}`); // Check Session API health const isSessionApiHealthy = await this.sessionClient.isHealthy(); if (isSessionApiHealthy) { log('info', 'Session API is available - session tracking enabled'); } else { log('warn', 'Session API is not available - proceeding without session tracking'); } const transport = new StdioServerTransport(); await this.server.connect(transport); log('info', 'ShadowGit MCP Server is running'); } shutdown(signal: string): void { log('info', `Received ${signal}, shutting down gracefully...`); process.exit(0); } } // Main entry point async function main(): Promise<void> { // Handle CLI arguments if (process.argv.includes('--version')) { console.log(VERSION); process.exit(0); } try { const server = new ShadowGitMCPServer(); // Handle shutdown signals process.on('SIGINT', () => server.shutdown('SIGINT')); process.on('SIGTERM', () => server.shutdown('SIGTERM')); await server.start(); } catch (error) { log('error', `Failed to start server: ${error}`); process.exit(1); } } // Start the server main().catch((error) => { log('error', `Unhandled error: ${error}`); process.exit(1); });

Implementation Reference

Latest Blog Posts

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/blade47/shadowgit-mcp'

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