AWS DevOps AgentをプライベートMCPサーバへ接続する方法(ZabbixのMCPサーバ化)

記事タイトルとURLをコピーする

はじめに

前回の記事では、Zabbix × Zendesk × AWS DevOps Agentを連携させ、アラート発生からRCA結果のチケット反映までを自動化する仕組みを構築しました。

しかし、前回の構成ではDevOps AgentがRCA(根本原因分析)を行う際、AWS側のデータ(CloudWatch、CloudTrail等)のみを参照しており、Zabbix側の詳細な監視データには直接アクセスできないという課題がありました。例えば、Zabbixが検知したCPU高負荷アラートに対して、DevOps AgentはCloudWatchメトリクスからCPU使用率を確認できますが、Zabbixが持つプロセスレベルの詳細情報やイベント履歴には到達できません。

本記事では、この課題を解決するために以下の3つのエンハンスを実施します。

  1. Zabbix MCPサーバーの実装 — ZabbixのAPIをMCP(Model Context Protocol)サーバーとしてラッピングし、DevOps Agentから直接Zabbixデータを取得可能にする
  2. プライベート接続の設定 — VPC内のMCPサーバーにDevOps Agentから安全にアクセスするためのPrivate Connectionを構成する
  3. エージェントスキルによる誘導 — Zabbix起因のインシデントでMCPツールを優先的に使用するようDevOps Agentを誘導する

前回からの変更点

前回の構成に加え、以下が追加されます。

追加コンポーネント:

  • Zabbix MCPサーバー(EC2 / VPC内) — Zabbix APIをMCPプロトコルでラッピング
  • Private Connection(VPC Lattice) — DevOps AgentからVPC内のMCPサーバーへの安全な接続
  • エージェントスキル — Zabbix起因のRCA調査でMCPツールを優先使用するよう誘導

データフロー:

前提条件

  • 前回の記事の構成が完了していること
  • Zabbixサーバーが稼働中で、APIトークンが発行済みであること
  • MCPサーバーをホストするEC2インスタンスがVPC内に存在すること(Zabbixサーバーと同一でも可)

1. Zabbix MCPサーバーの実装

1-1. MCPサーバーとは

MCP(Model Context Protocol)は、AIエージェントが外部ツールやデータソースにアクセスするためのオープンプロトコルです。AWS DevOps Agentは、MCPサーバーを通じてZabbixのようなサードパーティ監視ツールのデータを調査に活用できます。

参考: Connecting MCP Servers(AWS公式ドキュメント)

1-2. 必要なパッケージのインストール

MCPサーバーをホストするEC2インスタンスで以下を実行します。

# Python仮想環境の作成
sudo mkdir -p /opt/zabbix-mcp-server
cd /opt/zabbix-mcp-server
sudo python3 -m venv venv

# 必要パッケージのインストール
sudo /opt/zabbix-mcp-server/venv/bin/pip install mcp httpx uvicorn

1-3. MCPサーバーのコード

/opt/zabbix-mcp-server/server.py を作成します。

# server.py
import os
import httpx
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("zabbix-mcp-server", host="0.0.0.0", port=8080)

ZABBIX_URL = os.environ["ZABBIX_API_URL"]
ZABBIX_TOKEN = os.environ["ZABBIX_API_TOKEN"]


async def _zabbix_call(method: str, params: dict) -> dict:
    """Zabbix JSON-RPC APIを呼び出す"""
    async with httpx.AsyncClient() as client:
        resp = await client.post(
            ZABBIX_URL,
            json={
                "jsonrpc": "2.0",
                "method": method,
                "params": params,
                "auth": ZABBIX_TOKEN,
                "id": 1,
            },
        )
        data = resp.json()
        if "error" in data:
            raise Exception(f"Zabbix API error: {data['error']}")
        return data.get("result", {})


@mcp.tool()
async def get_active_triggers(
    min_severity: int = 3,
    host_group: str | None = None,
) -> str:
    """現在発生中のトリガー(障害)一覧を取得する。
    min_severity: 最小深刻度 (0-5, デフォルト3=Average)
    host_group: ホストグループ名でフィルタ(省略時は全体)
    """
    params = {
        "output": ["triggerid", "description", "priority", "lastchange", "value"],
        "selectHosts": ["host", "name"],
        "filter": {"value": 1},
        "min_severity": min_severity,
        "sortfield": "priority",
        "sortorder": "DESC",
        "limit": 50,
    }
    if host_group:
        groups = await _zabbix_call("hostgroup.get", {
            "output": ["groupid"],
            "filter": {"name": host_group},
        })
        if groups:
            params["groupids"] = [g["groupid"] for g in groups]

    triggers = await _zabbix_call("trigger.get", params)
    if not triggers:
        return "アクティブなトリガーはありません"

    lines = []
    for t in triggers:
        host = t["hosts"][0]["name"] if t.get("hosts") else "unknown"
        lines.append(f"[severity:{t['priority']}] {host}: {t['description']}")
    return "\n".join(lines)


@mcp.tool()
async def get_host_items(host_name: str, search_key: str | None = None) -> str:
    """指定ホストの監視アイテム(メトリクス)の最新値を取得する。"""
    hosts = await _zabbix_call("host.get", {
        "output": ["hostid"],
        "filter": {"host": host_name},
    })
    if not hosts:
        return f"ホスト '{host_name}' が見つかりません"

    params = {
        "output": ["itemid", "name", "lastvalue", "units", "lastclock"],
        "hostids": hosts[0]["hostid"],
        "sortfield": "name",
        "limit": 100,
    }
    if search_key:
        params["search"] = {"key_": search_key}

    items = await _zabbix_call("item.get", params)
    lines = [f"{i['name']}: {i['lastvalue']} {i['units']}" for i in items]
    return "\n".join(lines) or "アイテムが見つかりません"


@mcp.tool()
async def get_events(
    host_name: str | None = None,
    time_from: str | None = None,
    limit: int = 30,
) -> str:
    """最近のイベント(障害発生・復旧)履歴を取得する。
    time_from: UNIX timestamp(省略時は直近)
    """
    params = {
        "output": ["eventid", "clock", "name", "severity", "r_eventid"],
        "selectHosts": ["name"],
        "sortfield": ["clock"],
        "sortorder": "DESC",
        "limit": limit,
        "source": 0,
        "object": 0,
    }
    if time_from:
        params["time_from"] = time_from
    if host_name:
        hosts = await _zabbix_call("host.get", {
            "output": ["hostid"],
            "filter": {"host": host_name},
        })
        if hosts:
            params["hostids"] = hosts[0]["hostid"]

    events = await _zabbix_call("event.get", params)
    lines = []
    for e in events:
        host = e["hosts"][0]["name"] if e.get("hosts") else "unknown"
        status = "RESOLVED" if e.get("r_eventid", "0") != "0" else "PROBLEM"
        lines.append(f"[{status}] {host}: {e['name']} (severity:{e['severity']})")
    return "\n".join(lines) or "イベントが見つかりません"


if __name__ == "__main__":
    mcp.run(transport="streamable-http")

ポイント:

  • _zabbix_call でZabbix JSON-RPC APIをラッピングし、エラーハンドリングを実装。APIエラーが発生した場合は例外を投げ、DevOps Agentに原因を伝達する
  • 3つのツールを提供:
    • get_active_triggers — 現在発生中の障害一覧
    • get_host_items — ホストの監視メトリクス最新値
    • get_events — イベント(障害/復旧)履歴
  • DevOps AgentはStreamable HTTP transportをサポートしており、transport="streamable-http" を指定する
  • 3つのツールはすべて読み取り専用であり、Zabbixの状態を変更する操作は含まれない。AWS公式ドキュメントでは、プロンプトインジェクションのリスクを軽減するため、MCPツールと認証情報は読み取り専用アクセスのみを許可することが推奨されている(参考: Connecting MCP Servers - Security considerations

1-4. 環境変数の設定

/opt/zabbix-mcp-server/.env を作成します。

ZABBIX_API_URL=http://localhost/api_jsonrpc.php
ZABBIX_API_TOKEN=<ZabbixのAPIトークン>

ZabbixのAPIトークン発行方法: Zabbix Web UI → ユーザー設定 → APIトークン → トークンの作成。Zabbix 6.4以降で利用可能です。

1-5. systemdサービスの登録

/etc/systemd/system/zabbix-mcp-server.service を作成します。

[Unit]
Description=Zabbix MCP Server for AWS DevOps Agent
After=network.target httpd.service

[Service]
Type=simple
WorkingDirectory=/opt/zabbix-mcp-server
EnvironmentFile=/opt/zabbix-mcp-server/.env
ExecStart=/opt/zabbix-mcp-server/venv/bin/python server.py
Restart=always
RestartSec=5
User=nobody
Group=nobody
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now zabbix-mcp-server
sudo systemctl status zabbix-mcp-server

1-6. TLS終端の設定(Apache リバースプロキシ)

DevOps AgentのMCPサーバー接続はHTTPS必須です。Apacheをリバースプロキシとして配置し、TLS終端を行います。

自己署名証明書の作成:

DevOps AgentがTLS接続を検証するため、SAN(Subject Alternative Name)にIPアドレスを含める必要があります。

PRIVATE_IP=$(hostname -I | awk '{print $1}')

sudo openssl req -x509 -nodes -days 3650 \
  -newkey rsa:2048 \
  -keyout /etc/pki/tls/private/mcp-server.key \
  -out /etc/pki/tls/certs/mcp-server.crt \
  -subj "/CN=${PRIVATE_IP}" \
  -addext "subjectAltName=IP:${PRIVATE_IP}"

後述のPrivate Connection作成時に証明書の公開鍵が必要になるため、控えておきます。

sudo cat /etc/pki/tls/certs/mcp-server.crt

Apacheの設定 (/etc/httpd/conf.d/mcp-proxy.conf):

Listen 8443 https
<VirtualHost *:8443>
    ServerName <プライベートIP>
    SSLEngine on
    SSLCertificateFile /etc/pki/tls/certs/mcp-server.crt
    SSLCertificateKeyFile /etc/pki/tls/private/mcp-server.key

    ProxyPreserveHost On
    ProxyPass / http://127.0.0.1:8080/
    ProxyPassReverse / http://127.0.0.1:8080/

    # SSE対応
    SetEnv proxy-sendchunked 1
    ProxyTimeout 300
</VirtualHost>
sudo systemctl restart httpd

注意: SetEnv proxy-sendchunked 1ProxyTimeout 300 はMCPのStreamable HTTP通信に必要な設定です。これがないとSSE(Server-Sent Events)が正しく中継されません。

2. プライベート接続の設定

MCPサーバーはVPC内のプライベートサブネットで稼働しているため、DevOps Agentから直接アクセスできません。Private Connectionを作成して、VPC Lattice経由で安全に接続します。

参考: Connecting to privately hosted tools(AWS公式ドキュメント)

2-1. Private Connectionの作成

自己署名証明書を使用しているため、serviceManagedcertificate フィールドに証明書のPEM内容を指定します。これがないとDevOps AgentがTLSハンドシェイクに失敗します。

# 証明書の内容を変数に格納(改行を\nに変換)
CERT_PEM=$(sudo cat /etc/pki/tls/certs/mcp-server.crt | awk '{printf "%s\\n", $0}')

aws devops-agent create-private-connection \
  --name zabbix-mcp-connection \
  --mode "{
    \"serviceManaged\": {
      \"hostAddress\": \"<MCPサーバーのプライベートIP>\",
      \"vpcId\": \"<VPC ID>\",
      \"subnetIds\": [\"<サブネットID>\"],
      \"securityGroupIds\": [\"<セキュリティグループID>\"],
      \"portRanges\": [\"8443\"],
      \"certificate\": \"${CERT_PEM}\"
    }
  }" \
  --region ap-northeast-1

コンソールから作成する場合は、Certificate public key フィールドに証明書のPEM内容(-----BEGIN CERTIFICATE----- から -----END CERTIFICATE----- まで)を貼り付けます。

ステータスが ACTIVE になるまで待ちます(最大10分)。

aws devops-agent describe-private-connection \
  --name zabbix-mcp-connection \
  --region ap-northeast-1

サポートされないAZ: apne1-az3 はVPC Latticeで非サポートです。サブネットがこのAZに属していないことを確認してください。

セキュリティグループの設定: Private Connectionは、指定したサブネット内にENI(VPC Latticeのサービスマネージドリソースゲートウェイ)をプロビジョニングします。MCPサーバー(EC2)にアタッチされているセキュリティグループで、指定したサブネットのCIDR範囲からのTCP 8443ポートへのインバウンドを許可する必要があります。

2-2. MCPサーバーの登録

DevOps Agentコンソールで、MCPサーバーをCapability Providerとして登録します。

  1. Capability ProvidersMCP ServerRegister
  2. 以下を入力:
項目
Name zabbix-mcp-server
Endpoint URL https://<MCPサーバーのプライベートIP>:8443
Description Zabbix monitoring MCP server for trigger, item, and event data
Private Connection zabbix-mcp-connection を選択
  1. 認証方式を選択し、設定を完了
  2. Submit で登録

認証方式について: DevOps AgentのMCPサーバー登録では認証方式の選択が必須です。MCPサーバー側で認証を実装していない場合でも、いずれかの方式を選択する必要があります。本構成ではPrivate Connectionによるネットワークレベルの制限とセキュリティグループで保護しています。

CloudTrailへの記録: 登録したMCPサーバーのエンドポイントURLは、AWS CloudTrailのログにプレーンテキストで記録されます。エンドポイントURLに社内IPアドレスや内部DNS名が含まれる場合は、CloudTrailログへのアクセス制御を適切に設定してください。

自己署名証明書の場合: Private Connection作成時に serviceManagedcertificate フィールドで証明書のPEM内容を指定する必要があります。コンソールの場合は「Certificate public key」フィールドにPEM形式で貼り付けます。証明書にはSAN(Subject Alternative Name)としてMCPサーバーのIPアドレスを含めてください。SANがないとTLS検証に失敗する場合があります。

2-3. Agent SpaceへのMCPツール関連付け

  1. DevOps Agentコンソール → 対象のAgent Spaceを選択
  2. Capabilities タブ → MCP ServersAdd
  3. zabbix-mcp-server を選択
  4. ツールを選択:
    • get_active_triggers
    • get_host_items
    • get_events
  5. Add をクリック

CLIの場合:

aws devops-agent create-association \
  --agent-space-id <AgentSpaceId> \
  --association-configuration '{
    "mcpServers": [{
      "name": "zabbix-mcp-server",
      "endpoint": "https://<MCPサーバーのプライベートIP>:8443",
      "tools": ["get_active_triggers", "get_host_items", "get_events"]
    }]
  }' \
  --region ap-northeast-1

2-4. 疎通確認

Agent SpaceのOperator Web Appでチャットセッションを開始し、以下のように質問します。

Zabbixで現在発生中のアラートを教えてください

DevOps Agentが get_active_triggers ツールを呼び出し、Zabbixのトリガー情報を返せば疎通成功です。

3. エージェントスキルによるMCPツール活用の誘導

MCPサーバーを登録しただけでは、DevOps Agentが調査時にZabbixツールを積極的に使うとは限りません。エージェントスキルを設定することで、Zabbix起因のインシデントではMCPツールを優先的に使用するよう誘導できます。

エージェントスキルの詳細な説明(作成方法、Agent Typeの選択、ベストプラクティス等)については、こちらの記事を参照してください。本記事ではZabbix MCPサーバー向けのスキル設定に絞って解説します。

参考: DevOps Agent Skills(AWS公式ドキュメント)

3-1. スキルの作成

Operator Web Appの Skills ページから Add skillCreate skill で以下を入力します。

項目
Name zabbix-incident-investigation
Status Active
Agent Type Incident RCA

Description:

Investigation procedures for incidents originating from Zabbix monitoring.
Use this skill when the incident source is Zabbix, when the alert mentions
Zabbix host names, or when investigating infrastructure issues detected by
Zabbix agents. This skill guides the agent to use Zabbix MCP server tools
to retrieve triggers, host metrics, and event history for root cause analysis.

Instructions:

# Zabbix Incident Investigation

Use this skill when investigating incidents that originate from Zabbix monitoring alerts.
Zabbix alerts are forwarded via Zendesk and contain Zabbix host names or trigger descriptions.

## Identifying Zabbix-originated incidents

An incident is Zabbix-originated when:
- The alert source mentions "Zabbix" or contains Zabbix host naming patterns
  (e.g., `ip-*.compute.internal`)
- The incident was created from a Zendesk ticket forwarded by the
  convertZendeskDevOps integration
- The alert description contains Zabbix trigger terminology
  (severity levels, trigger IDs)

## Step 1: Get active triggers from Zabbix

Use the `get_active_triggers` tool with `min_severity: 0` to retrieve ALL
active triggers. Do not use the default min_severity of 3, as the relevant
trigger may be lower severity.

## Step 2: Get host metrics

Use the `get_host_items` tool with the affected host name to retrieve current
metric values. The host name format in Zabbix is the EC2 private DNS name
(e.g., `ip-10-0-1-243.ap-northeast-1.compute.internal`).

Check key metrics: CPU utilization, memory usage, disk I/O and space,
network connectivity, process status.

## Step 3: Get event history

Use the `get_events` tool with the affected host name to retrieve recent
event history. Set `limit` to 50 to get sufficient context.

Look for: when the problem first occurred, whether the issue is recurring,
related events on the same host, resolution patterns from past events.

## Step 4: Correlate with AWS data

After gathering Zabbix data, correlate findings with AWS observability data:
- Check CloudWatch metrics for the corresponding EC2 instance
- Review CloudWatch Logs for application-level errors
- Check EC2 instance status checks
- Review recent deployments or configuration changes

## Step 5: Root cause analysis

Synthesize findings from both Zabbix and AWS data sources:
1. Timeline of events from Zabbix event history
2. Current system state from Zabbix host metrics
3. AWS-side observations from CloudWatch
4. Identify the root cause and contributing factors
5. Recommend remediation steps

日本語訳(参考):

Description: Zabbix監視から発生したインシデントの調査手順。インシデントソースがZabbixである場合、アラートにZabbixホスト名が含まれる場合、またはZabbixエージェントが検出したインフラストラクチャの問題を調査する場合にこのスキルを使用する。このスキルは、根本原因分析のためにZabbix MCPサーバーツールを使用してトリガー、ホストメトリクス、イベント履歴を取得するようエージェントを誘導する。

Instructions: - Zabbix起因のインシデントの識別: アラートソースに「Zabbix」が含まれる、Zabbixホスト名パターン(ip-*.compute.internal)が含まれる、convertZendeskDevOps経由で作成されたチケットである、等 - Step 1: get_active_triggersmin_severity: 0 で実行し、全アクティブトリガーを取得 - Step 2: get_host_items で対象ホストのメトリクス(CPU、メモリ、ディスク等)を取得 - Step 3: get_eventslimit: 50 を指定し、イベント履歴を取得。初回発生時刻、再発パターン、関連イベントを確認 - Step 4: Zabbixデータ収集後、AWS側のデータ(CloudWatch、CloudTrail、EC2ステータス)と相関分析 - Step 5: ZabbixとAWS双方のデータから根本原因を特定し、修復手順を推奨

注意: スキルのName、Description、Instructionsは英語で記載してください。DevOps Agentのスキル評価エンジンは英語のキーワードでマッチングを行うため、日本語で記載するとスキルが適切に選択されない場合があります。Agent Spaceの「Agent response language」を日本語に設定していれば、調査結果は日本語で出力されます。

ポイント:

  • Agent Type を Incident RCA に限定 — Triage や Mitigation フェーズでは不要なため、RCA調査時のみスキルが読み込まれるようにする。これによりコンテキスト消費を抑え、エージェントの集中度を向上させる
  • Description が重要 — DevOps Agentはこのフィールドを評価してスキルの適用可否を判断する。「Zabbix」「host names」「infrastructure issues」など、トリガーとなるキーワードを含める
  • min_severity: 0 の指示 — デフォルトの min_severity: 3 では低深刻度のトリガーが取得できないため、スキル内で明示的に指示する

4. 動作確認

4-1. Zabbixアラートの発生

監視対象のEC2インスタンスでCPU負荷を発生させます。

# stress-ngのインストールと実行(5分間CPU 100%)
sudo yum install -y stress-ng
stress-ng --cpu $(nproc) --timeout 300s

4-2. 期待される動作フロー

  1. Zabbixが system.cpu.util トリガーを検知
  2. Zabbix → Zendesk チケット自動作成(zabbix タグ付き)
  3. Zendesk → convertZendeskDevOps → DevOps Agent Webhook
  4. DevOps Agent が調査を開始
  5. エージェントスキルにより、Zabbix MCPツールを使用:
    • get_active_triggers でアクティブなトリガーを確認
    • get_host_items でCPU、メモリ等のメトリクスを取得
    • get_events でイベント履歴を確認
  6. AWS側のデータ(CloudWatch等)と相関分析
  7. RCA完了 → EventBridge → sendBackToZendesk → Zendeskチケットに結果反映

4-3. DevOps AgentのRCA調査結果

DevOps AgentがZabbix MCPサーバーのツールを使用してRCA調査を行った様子です。エージェントスキルの誘導により、get_active_triggersget_host_items が呼び出され、Zabbix側の詳細データがRCAに活用されていることがわかります。

ハマりどころ

Zabbix APIトークンの設定忘れ

.env ファイルのトークンがプレースホルダーのままだと、Zabbix APIへの認証が失敗します。しかし、MCPサーバーのレスポンスは「データが見つかりません」となり、認証エラーであることがわかりにくいです。_zabbix_call でエラーハンドリングを実装し、APIエラーを明示的に例外として投げることで、問題の切り分けが容易になります。

VPC Lattice非対応AZ

apne1-az3 はVPC Latticeで非サポートです。Private Connection作成時にこのAZのサブネットを指定すると失敗します。事前に aws ec2 describe-subnets でAZ IDを確認してください。

Apache ProxyのSSE対応

MCPのStreamable HTTP通信にはSSE(Server-Sent Events)が使われます。Apacheのデフォルト設定ではSSEが正しく中継されないため、SetEnv proxy-sendchunked 1ProxyTimeout 300 の設定が必要です。

まとめ

本記事では、前回の Zabbix × Zendesk × DevOps Agent 連携に対して、以下の3つのエンハンスを実施しました。

エンハンス 効果
Zabbix MCPサーバー DevOps AgentがZabbixのトリガー、メトリクス、イベント履歴に直接アクセス可能に
プライベート接続 VPC内のMCPサーバーにインターネットを経由せず安全に接続
エージェントスキル Zabbix起因のインシデントでMCPツールを優先的に使用するよう誘導

これにより、DevOps AgentはAWS側のデータだけでなく、Zabbixが持つ詳細な監視データも活用してRCAを実施できるようになりました。オンプレミスの監視基盤とクラウドネイティブなAI分析を橋渡しする構成として、ハイブリッド環境の運用自動化に活用できます。

参考リンク