🙋‍♂️

systemd で MCP サーバーを管理できる MCP Server Manager を作ってみた

に公開

はじめに

MCP が流行りはじめ、便利な MCP サーバが開発され続けている一方で、複数の MCP サーバを管理するのが面倒だと思ったことはありませんか?

そこで、設定ファイルにコマンドを記述するだけで複数のプロセスを管理できる「MCP Server Manager」を開発してみました。

https://github.com/ksawaray/systemd-mcp

特徴

MCP Server Manager の特徴を以下に記載します。

  • 📝 シンプルな設定ファイル: mcp_server.conf にコマンドを 1 行ずつ記述するだけ
  • 🎮 CLI 操作: mcpctl コマンドでサーバの起動・停止・再起動を個別に制御できる
  • 🔄 自動再起動: プロセスが異常終了した場合には自動で復旧される
  • 🛠️ systemd 統合: サービス化により信頼性の高い運用を実現できる

アーキテクチャ

システムは 3 つのコンポーネントで構成されています。

  1. mcp_manager.py: メインのデーモンプロセス
  2. mcpctl: ユーザー向け CLI ツール
  3. mcp_server.conf: 管理対象サーバの設定ファイル

基本的な使い方

1. インストール

git clone https://github.com/ksawaray/systemd-mcp.git
cd systemd-mcp
sudo ./install.sh

インストールスクリプトが以下を自動実行します:

  • 必要なディレクトリの作成
  • 実行ファイルのコピーとパーミッション設定
  • systemd サービスの登録
  • サービスの起動と自動起動設定

2. 設定ファイルの編集

sudo nano /etc/mcp/mcp_server.conf

実行したいコマンドを 1 行ずつ記述:

# 管理したいサーバのコマンドを 1 行ずつ記述
/usr/bin/python3 /path/to/my_mcp_server.py --port 8080
/usr/bin/node /path/to/web_server.js
/path/to/mcp_server.sh
/usr/bin/python3 /another/service.py --config prod.json

3. 設定の適用とサーバ操作

# 設定を読み込み、全サーバを起動
mcpctl apply

# サーバ状態の確認
mcpctl status

実行結果例:

ID       STATUS    PID     UPTIME          COMMAND
-------- --------- ------- --------------- ----------------------------------------
a1b2c3d  Running   12345   0:10:30         /usr/bin/python3 /path/to/my_server.py
e4f5g6h  Running   12346   0:10:25         /usr/bin/node /path/to/web_server.js
i7j8k9l  Stopped   N/A     N/A             ./mcp_server.sh
# 個別サーバの操作
mcpctl start i7j8k9l    # サーバ起動
mcpctl stop a1b2c3d     # サーバ停止
mcpctl restart e4f5g6h  # サーバ再起動

実装のポイント

1. ハッシュベースの ID 生成

各サーバコマンドから 7 文字のハッシュ ID を自動生成:

def get_id_from_command(command_list):
    """Generate hash-based ID from command list"""
    command_str = ' '.join(command_list)
    return hashlib.sha1(command_str.encode()).hexdigest()[:7]

これにより、コマンドが同じであれば常に同じ ID が生成されます。
また、この ID を利用した制御が可能になります。

2. Unix Socket による通信

CLI とデーモン間の通信には Unix Socket を使用:

# デーモン側
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
    s.bind(SOCKET_PATH)
    os.chmod(SOCKET_PATH, 0o666)  # 全ユーザーアクセス可能
    s.listen()

これにより低レイテンシで安全な通信を実現しています。

3. プロセス監視と自動再起動

メインループでプロセスの生死を監視:

while True:
    time.sleep(MONITOR_INTERVAL_SECONDS)
    with process_lock:
        # 終了したプロセスを検出
        dead_server_ids = [sid for sid, info in managed_processes.items() 
                          if info['proc'].poll() is not None]
        
        for server_id in dead_server_ids:
            # 意図的な停止でない場合は自動再起動
            if server_id not in stopped_processes:
                time.sleep(RESTART_DELAY_SECONDS)
                new_proc = start_server(info['command'])
                # ...

4. スレッドセーフな実装

複数のクライアント接続とプロセス監視を同時実行するため、適切な排他制御を実装:

process_lock = threading.Lock()

def handle_client_connection(conn):
    with process_lock:
        # プロセス情報の安全な操作
        # ...

systemd との統合

サービスファイル

[Unit]
Description=MCP Server Manager Daemon

[Service]
ExecStart=/usr/bin/python3 /usr/local/lib/mcp-manager/mcp_manager.py
WorkingDirectory=/usr/local/lib/mcp-manager
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
KillSignal=SIGTERM

[Install]
WantedBy=multi-user.target

シグナルハンドリング

def signal_handler(signum, frame):
    print(f"Received signal {signum}. Stopping all servers...")
    with process_lock:
        for server_id in list(managed_processes.keys()):
            proc_info = managed_processes.pop(server_id)
            if proc_info['proc'].poll() is None:
                proc_info['proc'].terminate()
    sys.exit(0)

signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGINT, signal_handler)

運用面での配慮

1. 設定ファイルのバックアップ

インストール時に既存の設定ファイルが存在する場合、自動でバックアップを作成:

# install.sh内の処理
cp "$MCP_CONFIG_DIR/mcp_server.conf" "$MCP_CONFIG_DIR/mcp_server.conf.backup.$(date +%Y%m%d_%H%M%S)"

2. ユーザビリティの向上

  • root 以外のユーザーでもmcpctlを実行可能
  • ソケットファイルを /tmp に配置し、権限を 666 に設定
  • カラフルな出力メッセージでユーザー体験を向上

3. ログ統合

systemd の journalctl と統合し、ログ管理を簡素化:

# サービスログの確認
sudo journalctl -u mcp-manager.service -f

# 特定期間のログ
sudo journalctl -u mcp-manager.service --since "1 hour ago"

まとめ

MCP Server Manager を使うことで:

シンプルな設定: コマンド 1 行の記述だけで複雑なプロセス管理が可能
高い可用性: systemd との統合による堅牢な運用
運用効率: CLI による直感的な操作性
拡張性: 新しいサーバの追加が容易

複数の MCP サーバを管理している方は、ぜひ試してみてください!
(MCP サーバ管理のために作ったものの、MCP サーバに限らず Web サーバなどのプロセス管理としても活用できると思います)

ご質問やフィードバックがあれば、お気軽に Issue やコメントでお知らせください 🙌

Discussion