mcp-server-git
Git operations MCP server
mcp-server-git is an MCP (Model Context Protocol) server implementation packaged as a kadi-package. It initializes the application DI container, logger, telemetry, high-resolution timers, and the TransportManager that accepts MCP JSON-RPC requests over STDIO or HTTP. It includes graceful shutdown handling and enforces MCP-compatible stdout behavior (plain JSON, no ANSI color) when running in STDIO mode or when launched without a TTY.
Architecture
Section titled “Architecture”- Startup flow
- composeContainer() builds the tsyringe DI container and registers app services.
- AppConfig is resolved from the container to obtain runtime configuration (notably logLevel and mcpTransportType).
- initializePerformance_Hrt() boots a high-resolution timer used by request context/perf traces.
- logger.initialize(…) sets up the Pino logger (with pino-pretty in dev or STDIO-safe JSON).
- TransportManager is resolved from the container and started (transport start/registration occurs inside its implementation).
- Runtime components
- TransportManager: abstracts MCP transport implementations (STDIO vs HTTP). The server uses it to receive and terminate connections.
- requestContextService: creates operation-scoped request contexts used throughout startup/shutdown logging.
- shutdownOpenTelemetry: ensures tracing/metrics are flushed when terminating.
- Logger: pino-based logger exposing initialize(…) and close() to manage lifecycle.
- Shutdown
- The shutdown(signal) function stops the TransportManager, flushes telemetry, closes the logger, and exits the process.
- How it fits in AGENTS ecosystem
- This package acts as an MCP host process exposing Git operations and any registered MCP tools (tools/abilities are wired into the container/TransportManager elsewhere). Agents (MCP clients) connect to this server over the configured transport to invoke tools. The server enforces MCP stdout constraints (JSON-only) when run as an MCP child process.
Data flow (high level)
- MCP client -> Transport (STDIO or HTTP) -> TransportManager -> registered MCP handlers / tools -> business logic (Git ops, etc.) -> response back through TransportManager -> MCP client.
Tools / API
Section titled “Tools / API”This package’s surface for embedding and operational control (functions visible or invoked in src/index.ts and imports):
| API / Tool | Source | Description | Key params |
|---|---|---|---|
| start() | src/index.ts | Main entry point that composes the container, initializes subsystems, and starts the server runtime. | None (async) |
| shutdown(signal: string) | src/index.ts | Graceful shutdown sequence: stops TransportManager, flushes telemetry, closes logger, exits process. | signal: process signal name |
| composeContainer() | container/index.js (import) | Composes DI container with application services and tokens. Called at startup. | None |
| AppConfig (token) | container/index.js (import) | DI token used to resolve the runtime configuration object (contains logLevel, mcpTransportType, etc.). | Resolved via container.resolve(AppConfig) |
| TransportManager (class/token) | mcp-server/transports/manager.js (import) | Manager for MCP transports; exposes stop(signal) which is called on shutdown. | stop(signal: string): Promise |
| requestContextService.createRequestContext() | utils/index.js (import) | Creates structured context objects used in logs (operation, triggerEvent). | { operation: string, triggerEvent?: string } |
| logger.initialize(level, transportType) | utils/internal/logger.js (import) | Initializes the Pino logger with MCP-safe settings. | (level: McpLogLevel, transportType?: string) |
| logger.close() | utils/internal/logger.js (import) | Flushes and closes logger streams. | None |
| shutdownOpenTelemetry() | utils/telemetry/instrumentation.js (import) | Ensures OpenTelemetry SDK is shutdown and exporters are flushed. | None |
| initializePerformance_Hrt() | utils/index.js (import) | Initialize high-resolution timer instrumentation used by request contexts. | None |
Notes:
- If you need to add new MCP tools (Git subcommands, repository operations), register them into the DI container during composeContainer() so the TransportManager picks them up.
Configuration
Section titled “Configuration”This module reads its runtime configuration from the DI-resolved AppConfig object. The following fields are used explicitly in src/index.ts:
-
config.logLevel (string)
- Description: Effective MCP log level. Valid values enforced at startup: debug, info, notice, warning, error, crit, alert, emerg.
- Typical env mapping: MCP_LOG_LEVEL
- Default behavior: If invalid, the server warns on TTY and defaults to “info”.
-
config.mcpTransportType (string)
- Description: Desired transport type the server should use (e.g., “stdio” or “http”). It is passed to the logger so STDIO path can use JSON-only output.
- Typical env mapping: MCP_TRANSPORT_TYPE
Environment variables honored or manipulated at startup:
- MCP_TRANSPORT_TYPE
- Used to determine if the process should run in “stdio” or “http” transport mode. If unset or “stdio”, STDIO mode is assumed.
- MCP_LOG_LEVEL
- Referenced in startup logs and used to populate config.logLevel (via AppConfig). The code expects this name in logs and config.
- NO_COLOR
- This process sets NO_COLOR=1 when running in STDIO or when HTTP without TTY to comply with MCP JSON output requirements.
- FORCE_COLOR
- This process sets FORCE_COLOR=0 to disable forced colors.
- NODE_ENV
- Set in the build process to “production” for the default build in agent.json.
Secrets / Vault
- This package does not directly manage secret storage. Secrets required by any subsystems (e.g., Git credentials, external APIs) should be provided via AppConfig injected by the container. Implement secret resolution (Vault, environment variables, or other secret providers) in the config module that populates AppConfig.
Code Examples
Section titled “Code Examples”Key excerpts from src/index.ts showing startup, coloring rules, and graceful shutdown:
#!/usr/bin/env node/** * @fileoverview Main entry point for the MCP TypeScript Template application. * This script initializes the configuration, sets up the logger, starts the * MCP server (either via STDIO or HTTP transport), and handles graceful * shutdown on process signals or unhandled errors. * @module src/index */
// CRITICAL: Disable ANSI color codes BEFORE any imports when running via MCP clients.// The MCP specification requires clean output. Even in HTTP mode, if launched via// bunx/npx by an MCP client, colored output pollutes the client's process streams.// This must be set before pino-pretty or any other library loads.//// We disable colors in these scenarios:// 1. STDIO mode (always - MCP JSON-RPC on stdout)// 2. HTTP mode when NOT in TTY (likely launched by MCP client via bunx/npx)// 3. When explicitly disabled via existing NO_COLOR env varconst transportType = process.env.MCP_TRANSPORT_TYPE?.toLowerCase();const isStdioMode = !transportType || transportType === 'stdio';const isHttpModeWithoutTty = transportType === 'http' && !process.stdout.isTTY;
if (isStdioMode || isHttpModeWithoutTty) { process.env.NO_COLOR = '1'; // Standard env var that most libraries respect process.env.FORCE_COLOR = '0'; // Disable forced coloring}const shutdown = async (signal: string): Promise<void> => { if (isShuttingDown) { return; } isShuttingDown = true;
const shutdownContext = requestContextService.createRequestContext({ operation: 'ServerShutdown', triggerEvent: signal, });
logger.info( `Received ${signal}. Initiating graceful shutdown...`, shutdownContext, );
try { if (transportManager) { await transportManager.stop(signal); }
logger.info( 'Graceful shutdown completed successfully. Exiting.', shutdownContext, );
// Shutdown OpenTelemetry and logger last to ensure all telemetry and logs are sent. await shutdownOpenTelemetry(); await logger.close();
process.exit(0); } catch (error) { logger.error( 'Critical error during shutdown process.', error as Error, shutdownContext, ); try { await logger.close(); } catch (_e) { // Ignore errors during final logger close attempt } process.exit(1); }};const start = async (): Promise<void> => { try { // Initialize DI container first composeContainer(); // Now it's safe to resolve dependencies config = container.resolve<typeof appConfigType>(AppConfig); } catch (_error) { // This will catch the McpError from parseConfig if (process.stdout.isTTY) { // The config module already logged the details. We just provide a final message. console.error('Halting due to critical configuration error.'); } // Ensure OpenTelemetry is shut down if it was started before the error await shutdownOpenTelemetry(); process.exit(1); }
// Initialize the high-resolution timer await initializePerformance_Hrt();
const validMcpLogLevels: McpLogLevel[] = [ 'debug', 'info', 'notice', 'warning', 'error', 'crit', 'alert', 'emerg', ]; const initialLogLevelConfig = config.logLevel;
let validatedMcpLogLevel: McpLogLevel = 'info'; if (validMcpLogLevels.includes(initialLogLevelConfig as McpLogLevel)) { validatedMcpLogLevel = initialLogLevelConfig as McpLogLevel; } else { if (process.stdout.isTTY) { console.warn( `[Startup Warning] Invalid MCP_LOG_LEVEL "${initialLogLevelConfig}". Defaulting to "info".`, ); } }
// Pass transport type to logger to ensure STDIO mode uses plain JSON (no ANSI colors) await logger.initialize(validatedMcpLogLevel, config.mcpTransportType);
logger.info( `Logger initialized. Effective MCP logging level: ${validatedMcpLogLevel}.`, requestContextService.createRequestContext({ operation: 'LoggerInit' }), );When adding or modifying handlers that perform Git operations, ensure they are registered into the DI container so TransportManager exposes them to MCP callers.
Dependencies
Section titled “Dependencies”Runtime dependencies (selected):
- pino, pino-pretty — logging
- reflect-metadata — tsyringe / decorator metadata
- tsyringe — dependency injection (listed in devDependencies but used at runtime via container)
- @hono/mcp, @hono/node-server — MCP / HTTP server helpers (devDependencies include @hono/mcp)
- OpenTelemetry libs — tracing/metrics instrumentation (multiple @opentelemetry/* packages)
- axios, repomix, execa, etc. — utilities likely used by Git/tool implementations
Full package lists are present in the agent manifest; key entries include:
- dependencies: pino, pino-pretty, reflect-metadata
- devDependencies: @hono/mcp, @modelcontextprotocol/sdk, @opentelemetry/*, tsyringe, typescript, bun-types, etc.
Abilities / exposed capabilities
- This package acts as an MCP host exposing tooling (Git ops) over MCP transports. The primary abilities are the MCP handler surface (registered in the container) and transport lifecycle management (TransportManager).
- Exposed utility APIs used by tools include logger, requestContextService, and telemetry helpers.
Who depends on this package
- External MCP clients/agents connect to this process as an MCP server to invoke Git-related abilities.
- Other internal packages that implement concrete Git tools (not shown here) will be wired into this server via the DI container.
Notes for contributors
- All color-suppression logic must run before importing logging/instrumentation libraries. The initial transport detection block at the top of src/index.ts is required to comply with MCP output requirements.
- When adding configuration fields to AppConfig, ensure the parse/config module logs helpful messages and throws McpError (the startup flow expects parse errors to be reported and the process to exit).
- Any new tools should register into the DI container during composeContainer() so TransportManager can expose them through MCP transports.