Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@skilljack/mcp-server-manager

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@skilljack/mcp-server-manager

MCP server lifecycle manager with health checks, auto-restart, and graceful shutdown

latest
Source
npmnpm
Version
0.1.0
Version published
Maintainers
1
Created
Source

@skilljack/mcp-server-manager

A loosely coupled lifecycle manager for MCP (Model Context Protocol) servers with health checks, auto-restart, and graceful shutdown capabilities.

Features

  • Lifecycle Management - Start, stop, restart servers with proper state tracking
  • Health Monitoring - Periodic ping-based health checks with configurable thresholds
  • Auto-Restart - Automatic recovery from crashes with exponential backoff
  • Graceful Shutdown - Clean shutdown with configurable timeouts and force-kill fallback
  • Two Transport Types - Support for stdio (child processes) and HTTP connections
  • Event System - Comprehensive events for monitoring server states
  • Dynamic Management - Add/remove servers at runtime

Installation

npm install @skilljack/mcp-server-manager

Peer Dependency: Requires @modelcontextprotocol/sdk ^1.0.0

Quick Start

import {
  ServerManager,
  createServerConfig,
  createStdioConfig,
} from '@skilljack/mcp-server-manager';

// Create a manager with server configurations
const manager = ServerManager.fromConfig({
  servers: [
    createServerConfig('my-server', createStdioConfig('npx', ['-y', '@modelcontextprotocol/server-everything']))
  ]
});

// Listen for events
manager.on('server:connected', (event) => {
  console.log(`Server ${event.serverName} connected`);
});

// Start all servers
await manager.start();

// Use the MCP client
const client = manager.getClient('my-server');
if (client) {
  const tools = await client.listTools();
}

// Graceful shutdown
await manager.shutdown();

Configuration

Server Configuration

interface ServerConfig {
  name: string;                        // Unique server identifier
  connection: ServerConnectionConfig;  // Stdio or HTTP config
  lifecycle?: LifecycleConfig;         // Optional lifecycle overrides
  autoStart?: boolean;                 // Auto-start with manager (default: true)
}

Stdio Connection (Child Process)

Spawns a child process and communicates via stdin/stdout pipes.

import { createStdioConfig } from '@skilljack/mcp-server-manager';

const config = createStdioConfig('npx', ['-y', '@modelcontextprotocol/server-everything'], {
  env: { DEBUG: 'true' },  // Optional environment variables
  cwd: '/path/to/dir',     // Optional working directory
});

HTTP Connection

Connects to an existing HTTP-based MCP server.

import { createHttpConfig } from '@skilljack/mcp-server-manager';

const config = createHttpConfig('http://localhost:3000', {
  headers: { 'Authorization': 'Bearer token' },  // Optional headers
});

Lifecycle Configuration

Override default lifecycle behavior per-server or globally:

interface LifecycleConfig {
  healthCheckEnabled?: boolean;       // Enable health checks (default: true)
  healthCheckIntervalMs?: number;     // Check interval (default: 30000)
  healthCheckTimeoutMs?: number;      // Check timeout (default: 5000)
  unhealthyThreshold?: number;        // Failures before unhealthy (default: 3)
  autoRestartEnabled?: boolean;       // Enable auto-restart (default: true)
  maxRestartAttempts?: number;        // Max restart tries (default: 5)
  restartBackoffBaseMs?: number;      // Backoff base delay (default: 1000)
  restartBackoffMaxMs?: number;       // Max backoff delay (default: 30000)
  shutdownTimeoutMs?: number;         // Graceful shutdown timeout (default: 10000)
}

Full Configuration Example

const manager = ServerManager.fromConfig({
  // Global defaults (optional)
  defaults: {
    healthCheckIntervalMs: 60000,
    maxRestartAttempts: 3,
  },
  servers: [
    {
      name: 'primary',
      connection: { type: 'stdio', command: 'node', args: ['server.js'] },
      autoStart: true,
    },
    {
      name: 'secondary',
      connection: { type: 'http', url: 'http://localhost:8080' },
      autoStart: false,
      lifecycle: {
        healthCheckEnabled: false,  // Override for this server
      },
    },
  ],
});

Server Lifecycle States

disconnected ──start()──▶ connecting ──success──▶ connected
                              │                       │
                              │                       │ health check failures
                              ▼                       ▼
                           failed ◀────────────── unhealthy
                              ▲                       │
                              │                       │ auto-restart
                              │                       ▼
                              └──max attempts──── restarting
                                                      │
                                                      │ success
                                                      ▼
                                                  connecting

Any state ──stop()──▶ stopped
StatusDescription
disconnectedInitial state, not yet started
connectingConnection in progress
connectedSuccessfully connected and healthy
unhealthyHealth checks failing
restartingAuto-restart in progress
failedMax restart attempts exceeded
stoppedManually stopped

Events

Lifecycle Events

EventDescriptionKey Properties
server:connectingConnection startingserverName
server:connectedSuccessfully connectedserverName, pid?
server:connection-failedConnection failedserverName, error
server:healthyHealth check passedserverName, healthCheck
server:unhealthyHealth checks failingserverName, consecutiveFailures
server:crashedProcess crashedserverName, exitCode, signal, willRestart
server:restartingRestart initiatedserverName, attempt, maxAttempts, reason
server:restart-succeededRestart successfulserverName, attempts, pid?
server:restart-failedAll restart attempts failedserverName, attempts, error
server:status-changedAny status changeserverName, previousStatus, newStatus
server:stoppedServer stoppedserverName, graceful

Manager Events

EventDescriptionKey Properties
manager:readyAll auto-start servers startedserverCount
manager:shutdownShutdown completegraceful
manager:state-snapshotState snapshot emittedservers (array of summaries)

Event Usage

// Specific event
manager.on('server:connected', (event) => {
  console.log(`${event.serverName} connected with PID ${event.pid}`);
});

// All lifecycle events
manager.on('*', (event) => {
  console.log(`Event: ${event.type}`, event);
});

// All manager events
manager.on('manager:*', (event) => {
  console.log(`Manager event: ${event.type}`);
});

// Typed event helpers
manager.onLifecycleEvent('server:unhealthy', (event) => {
  console.log(`${event.serverName} unhealthy after ${event.consecutiveFailures} failures`);
});

manager.onManagerEvent('manager:ready', (event) => {
  console.log(`Manager ready with ${event.serverCount} servers`);
});

API Reference

ServerManager

Static Methods

// Create from config object
ServerManager.fromConfig(config: ManagerConfig, options?: ServerManagerOptions): ServerManager

// Create from config file
ServerManager.fromConfigFile(filePath: string, options?: ServerManagerOptions): Promise<ServerManager>

Instance Methods

// Lifecycle
start(): Promise<void>              // Start all auto-start servers
shutdown(): Promise<void>           // Stop all servers gracefully
startServer(name: string): Promise<void>
stopServer(name: string): Promise<void>
restartServer(name: string): Promise<void>

// State
getServerStatus(name: string): ServerStatus | undefined
getServerState(name: string): ServerStateSummary | undefined
getAllServerStates(): ServerStateSummary[]
isServerConnected(name: string): boolean
areAllServersConnected(): boolean

// Clients
getClient(name: string): Client | null
getConnectedClients(): Map<string, Client>

// Management
getServerNames(): string[]
getServerCount(): number
addServer(config: ServerConfig): void
removeServer(name: string): Promise<void>

// Events
emitStateSnapshot(): void

ServerStateSummary

interface ServerStateSummary {
  name: string;
  status: ServerStatus;
  healthy: boolean;
  timeInStatus: number;      // milliseconds
  pid?: number;
  lastLatencyMs?: number;    // last health check latency
  restartAttempts: number;
  error?: string;
}

Advanced Usage

Custom Logger

import { ServerManager, ConsoleLoggerFactory } from '@skilljack/mcp-server-manager';

const manager = ServerManager.fromConfig(config, {
  loggerFactory: new ConsoleLoggerFactory('debug'),
});

Using Core Components Directly

For advanced use cases, you can use the underlying components:

import {
  ServerLifecycle,
  ProcessManager,
  HealthMonitor,
  HttpConnection,
} from '@skilljack/mcp-server-manager';

// Create a single server lifecycle
const lifecycle = new ServerLifecycle(serverConfig, lifecycleDefaults);
lifecycle.on('*', (event) => console.log(event));
await lifecycle.start();

Retry Utilities

import { retry, withTimeout, calculateBackoff } from '@skilljack/mcp-server-manager';

// Retry an operation
const result = await retry(
  async () => fetchData(),
  { maxAttempts: 3, backoff: { baseMs: 1000, maxMs: 10000 } }
);

// Add timeout to a promise
const data = await withTimeout(fetchData(), 5000);

Architecture

ServerManager
    │
    ├── ServerLifecycle (one per server)
    │   ├── ProcessManager (stdio transport)
    │   │   └── Child Process (stdin/stdout pipes)
    │   │
    │   ├── HttpConnection (http transport)
    │   │
    │   ├── MCP Client
    │   │   └── Transport (StdioClientTransport or StreamableHTTPClientTransport)
    │   │
    │   └── HealthMonitor
    │       └── Periodic ping checks
    │
    └── Event Emitter
        └── Forwards all lifecycle events

License

MIT

Keywords

mcp

FAQs

Package last updated on 24 Jan 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts