목차

Monithub가 Prometheus MCP 서버와 통신하는 방법

본 문서는 우리 Monithub 백엔드(Golang), Prometheus MCP 서버(Python), 그리고 LLM(Ollama/Gemini) 간의 통신 프로토콜과 메시지 포맷에 대해 설명하는 문서입니다.

/images/Monithub_MCP_Architecture.png

1. 시스템 아키텍처

  • 백엔드 (Client): 모델 컨텍스트 프로토콜(MCP) 클라이언트 역할을 수행합니다. Stdio 또는 SSE 전송 방식을 사용하여 MCP 서버에 연결합니다.

  • Prometheus MCP 서버: Prometheus의 기능(쿼리, 메타데이터, 메트릭 목록 조회)을 “도구(Tools)” 형태로 노출합니다.

  • LLM: 추론 엔진입니다. 백엔드가 준비한 컨텍스트 객체(메트릭, 값)를 수신하여 자연어 응답이나 JSON 설정을 생성합니다.

2. 통신 프로토콜: JSON-RPC 2.0 (MCP)

백엔드와 MCP 서버 간의 상호작용은 Model Context Protocol (MCP) 사양을 따르며, JSON-RPC 2.0 메시지를 사용합니다.

공통 메시지 구조

요청 (Client -> Server):

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "tool_name",
    "arguments": { ... }
  }
}

응답 (Server -> Client):

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
        {
            "type": "text",
            "text": "..."
        }
    ]
  }
}

3. 상세 통신 예시

시나리오 1: 사용자가 “내 서버의 현재 CPU 사용량은 얼마야?“라고 질문했을 때

1단계: 백엔드 초기화 및 도구 탐색 (Tool Discovery)

백엔드가 채팅 요청 처리를 시작할 때, 먼저 MCP 서버로부터 사용 가능한 도구들을 탐색합니다.

백엔드 -> MCP 서버 (tools/list):

{
  "jsonrpc": "2.0",
  "id": 101,
  "method": "tools/list"
}

MCP 서버 -> 백엔드:

{
  "jsonrpc": "2.0",
  "id": 101,
  "result": {
    "tools": [
      {
        "name": "list_metrics",
        "description": "List all available metrics in Prometheus...",
        "inputSchema": { ... }
      },
      {
        "name": "execute_query",
        "description": "Execute a PromQL instant query...",
        "inputSchema": {
          "type": "object",
          "properties": {
            "query": { "type": "string" }
          },
          "required": ["query"]
        }
      }
    ]
  }
}

2단계: 컨텍스트 수집 (메트릭 조회)

백엔드는 list_metrics를 호출하여 관련 메트릭 이름들을 LLM의 시스템 프롬프트에 주입할 준비를 합니다.

백엔드 -> MCP 서버 (call_tool: list_metrics):

{
  "jsonrpc": "2.0",
  "id": 102,
  "method": "tools/call",
  "params": {
    "name": "list_metrics",
    "arguments": {}
  }
}

MCP 서버 -> 백엔드:

{
  "jsonrpc": "2.0",
  "id": 102,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"metrics\": [\"node_cpu_seconds_total\", \"node_memory_MemTotal_bytes\", \"container_cpu_usage_seconds_total\", ...]}"
      }
    ]
  }
}

3단계: LLM 프롬프트 구성

백엔드는 MCP로부터 가져온 데이터를 통합하여 시스템 프롬프트를 구성합니다.

백엔드 -> LLM (프롬프트 전송):

SYSTEM:
You are Monithub AI, a specialized dashboard generator.

Current available metrics in Prometheus:
[
  "node_cpu_seconds_total",
  "node_memory_MemTotal_bytes"
]

[KNOWLEDGE BASE]
- Title: CPU Usage, Expr: 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100), Unit: percent

User Request: "What is the current CPU usage of my server?"

INSTRUCTIONS:
... (PromQL 문법, 집계 규칙 등에 대한 지침) ...

4단계: 데이터 검증 (옵션/동적)

사용자가 구체적인 값을 물었거나 대시보드에 현재 데이터를 보여줘야 하는 경우, 백엔드는 execute_query를 호출하여 실제 값을 가져와 컨텍스트에 포함시킬 수 있습니다.

백엔드 -> MCP 서버 (call_tool: execute_query):

{
  "jsonrpc": "2.0",
  "id": 103,
  "method": "tools/call",
  "params": {
    "name": "execute_query",
    "arguments": {
      "query": "100 - (avg(rate(node_cpu_seconds_total{mode='idle'}[5m])) * 100)"
    }
  }
}

MCP 서버 -> 백엔드:

{
  "jsonrpc": "2.0",
  "id": 103,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"status\":\"success\",\"data\":{\"resultType\":\"vector\",\"result\":[{\"value\":[1715660000,\"12.5\"]}]}}"
      }
    ]
  }
}

5단계: 최종 응답 생성

LLM은 제공된 컨텍스트를 사용하여 최종 응답을 생성합니다.

LLM -> 백엔드:

The current CPU usage of your server is approximately **12.5%**.

I used the following query to calculate this:
`100 - (avg(rate(node_cpu_seconds_total{mode='idle'}[5m])) * 100)`