Prometheus MCP 서버 구축하기: AI 에이전트를 위한 안전한 읽기 전용 PromQL
요약
AI 에이전트가 Prometheus 데이터를 안전하게 조회할 수 있도록 Model Context Protocol(MCP)을 활용한 읽기 전용 서버 구축 방법을 설명합니다. 에이전트에게 직접적인 API 접근 대신 가드레일이 적용된 구조화된 도구 세트만 제공하여 시스템 부하와 보안 위협을 방지하는 것이 핵심입니다.
핵심 포인트
- 에이전트에게 직접적인 API 노출 대신 MCP를 통한 제한된 도구 제공 권장
- 비용이 많이 드는 쿼리 및 컨텍스트 폭발 방지를 위한 가드레일 설계
- 읽기 전용 원칙을 통해 데이터 변경 및 시스템 과부하 위험 차단
- FastMCP를 활용한 즉시 쿼리, 범위 쿼리, 메트릭 검색 도구 구현
💡 원문은 devtocash.com에 게시되었습니다 — 이 가이드의 최신 업데이트가 이루어지는 곳입니다. 저는 그곳에서 매주 실무 중심의 DevOps/SRE 심층 분석 글을 작성합니다.
에이전트에게 스크레이프(scrape) 엔드포인트가 아닌 쿼리 레이어가 필요한 이유
온콜(on-call) AI 에이전트가 "결제 지연 시간이 왜 높아졌나요?"라는 질문에 답하려고 할 때, 당신이 할 수 있는 최악의 행동은 에이전트에게 셸(shell)과 Prometheus URL을 통째로 넘겨주는 것입니다. 에이전트는 가공되지 않은 HTTP API를 curl로 호출하고, 레이블(label) 이름을 추측하며, 카디널리티(high-cardinality)가 높은 시계열 데이터 2주 치에 대해 제한 없는 범위 쿼리(range query)를 실행할 것입니다. 그 결과 타임아웃이 발생하거나, 장애 상황에서 다른 모든 사람이 쿼리 중인 인스턴스를 다운시켜 버릴 수 있습니다. 에이전트에게 필요한 것은 Prometheus 서버 그 자체가 아니라, 가드레일(guardrails)이 내장된 _제한적이고 구조화된 PromQL 인터페이스(surface)_입니다.
그 인터페이스를 제공하는 것이 바로 Model Context Protocol (MCP)의 목적입니다. MCP 서버는 소수의 타입화된 도구(typed tools) 세트를 노출하며, 에이전트는 검증된 인자(arguments)를 사용하여 이를 호출하고 구조화된 결과를 돌려받습니다. 이는 safe kubectl MCP server 뒤에 숨겨진 읽기 전용 원칙과 동일합니다. 설계 원칙은 같습니다. 에이전트에게 건물 전체를 주는 것이 아니라, 좁은 문 하나를 제공하는 것입니다. 여기서는 Prometheus 버전의 대응물을 구축합니다. 에이전트는 메트릭(metrics)에 대해 질문을 던질 수 있지만, 구조적으로 그 어떤 것도 변경, 삭제 또는 과부하를 일으킬 수 없습니다.
한 문장으로 요약한 위협 모델
읽기 전용이라고 해서 무해하다는 뜻은 아닙니다. PromQL 쿼리는 모니터링 서버에서 실행되는 코드입니다. 쓰기 경로(write path)가 없더라도 세 가지 문제가 발생할 수 있습니다: 실제 사용자를 위한 Prometheus 성능을 저하시킬 정도로 비용이 많이 드는 쿼리, 수백만 개의 샘플을 반환하여 에이전트의 컨텍스트(context)를 폭발시키고 토큰 비용을 발생시키는 범위(range) + 스텝(step) 조합, 그리고 에이전트가 요약해서는 안 되는 데이터를 유출하는 레이블 값입니다. MCP 서버는 이 세 가지를 모두 강제하기에 적합한 장소입니다. 모든 쿼리는 TSDB에 도달하기 전에 반드시 당신의 도구 코드(tool code)를 통과해야 하기 때문입니다.
도구 인터페이스: 딱 세 가지 도구만 사용
모든 것을 노출하고 싶은 유혹을 뿌리치세요. 신뢰성(reliability) 질문에 답하는 에이전트에게 필요한 것은 즉시 쿼리(instant query)를 실행하고, 범위 쿼리(range query)를 실행하며, 어떤 메트릭(metrics)이 존재하는지 찾아내는 것뿐입니다. 그게 전부입니다.
# server.py — FastMCP를 기반으로 구축된 읽기 전용 Prometheus MCP 서버
import os
import time
...
에이전트가 할 수 있는 모든 일은 아래 세 가지 함수 중 하나입니다. 파일 어디에도 /api/v1/admin 호출, 원격 쓰기(remote-write), 또는 delete-series 도구가 없기 때문에, "읽기 전용(read-only)"은 단순히 지켜지기를 바라는 정책이 아니라 코드 자체의 속성이 됩니다.
도구 1: 쿼리 형태 가드(query-shape guard)를 갖춘 즉시 쿼리(instant query)
BANNED = ("/api/v1/admin", "delete_series", "clean_tombstones")
def _reject_if_dangerous(promql: str) -> None:
...
도구 2: 실제 가드레일(guardrails)이 존재하는 범위 쿼리(range query)
이 부분은 제한이 없는 에이전트가 가장 큰 피해를 줄 수 있는 지점입니다. 요청된 시간 창(window)으로부터 step을 계산하여 포인트(point) 개수가 MAX_POINTS를 초 exceed할 수 없도록 하고, 상한선보다 긴 시간 창은 거부해야 합니다. 에이전트는 일반 초(seconds) 단위로 시간 범위를 요청하지만, 해상도(resolution)는 당신의 코드가 결정합니다.
@mcp.tool()
def range_query(promql: str, lookback_seconds: int) -> dict:
"""지난 N초 동안의 범위 쿼리(range query)를 실행합니다. Step은 호출자가 제어하는 것이 아니라 계산됩니다."""
...
호출자가 설정할 수 없는 항목에 주목하세요: 바로 step입니다. 흔한 실패 사례는 에이전트가 1초 단위의 step으로 6시간의 시간 창을 요청하는 것입니다. 이는 시리즈(series)당 21,600개의 포인트를 생성하며, 셀렉터(selector)가 매칭되는 시리즈의 수만큼 배가됩니다. 시간 창으로부터 step을 유도하고 내림(floor) 처리를 함으로써, 모델이 무엇을 요청하든 최악의 경우를 제한할 수 있습니다.
도구 3: 에이전트의 추측을 방지하는 메트릭 검색(metric discovery)
에이전트가 잘못된 쿼리를 던지는 원인의 절반은 메트릭 이름을 임의로 만들어내기 때문입니다. 에이전트에게 메트릭을 조회할 수 있는 저렴한 방법을 제공하면, 에이전트는 실제 메트릭이 http_server_request_duration_seconds인데도 http_request_duration_seconds라고 환각(hallucination)을 일으키는 대신, 현실에 기반한 PromQL을 작성하게 될 것입니다.
@mcp.tool()
def list_metrics(prefix: str = "") -> list[str]:
"""선택적으로 접두사(prefix)로 필터링된 메트릭 이름들을 반환합니다. 비용이 적게 드는 메타데이터 호출입니다."""
...
결과 요약 — 컨텍스트에 가공되지 않은 샘플을 쏟아붓지 마세요
가장 큰 비용 절감 방법은 가공되지 않은(raw) JSON을 반환하지 않는 것입니다. 40개의 시리즈(series)에 걸쳐 700개의 포인트를 가진 범위 결과(range result)는 모델에게도 도움이 되지 않고 토큰 비용만 높이는 숫자의 벽일 뿐입니다. 각 시리즈를 실제 장애 상황(incident)에 필요한 형태, 즉 처음(first), 마지막(last), 최소(min), 최대(max), 그리고 개수(count)로 요약하세요.
def _summarize(payload: dict, computed_step: int | None = None) -> dict:
result = payload.get("data", {}).get("result", [])
out = []
...
메트릭 선택기(metric selectors) 자체는 일반적인 PromQL을 유지하세요. 예를 들어 rate(http_requests_total{code=~"5.."}[5m])와 같은 쿼리는 수정 없이 그대로 전달됩니다. 서버는 쿼리를 절대 재작성하지 않습니다. 단지 쿼리가 실행되는 범위와 정밀도, 그리고 반환되는 양만을 제한할 뿐입니다.
Prometheus 측면도 강화하세요
MCP 서버는 애플리케이션 계층의 울타리 역할을 하지만, 심층 방어(defense in depth)를 의미하려면 TSDB(Time Series Database)가 MCP 서버를 맹목적으로 신뢰해서는 안 됩니다. 도구 코드의 버그가 권한 상승(escalate)으로 이어지지 않도록, Prometheus 자체를 실행할 때 쓰기(write) 및 관리(admin) 인터페이스를 비활성화하세요.
prometheus \
--web.enable-lifecycle=false \
--web.enable-admin-api=false \
...
여기서 중요한 것은 --query.max-samples와 --query.timeout입니다. 잘못된 형식의 쿼리가 포인트 제한(point cap)을 통과하더라도, Prometheus는 터무니없는 수의 샘플을 로드하는 것을 거부하고 너무 오래 실행되는 작업은 강제로 종료할 것입니다. 이것이 장애 발생 시 동일한 인스턴스에 쿼리를 날리는 다른 작업자(humans)를 보호하는 최후의 보루(backstop)입니다.
평가(eval)를 생략하지 마세요
쿼리 접근 권한을 가진 에이전트는 그 쿼리가 정확할(right) 때만 유용하며, 가드레일(guardrails)이 실제로 작동할 때만 안전합니다. 이것을 실제 장애 상황에 적용하기 전에, "가장 높은 에러율을 보이는 서비스를 찾으세요", "결제 Pod의 메모리 사용량이 증가 추세인가요?"와 같은 고정된 시나리오 세트에 대해 실행해 보고, 답변과 생성된 쿼리를 모두 확인하십시오. 이것이 DevOps AI 에이전트를 위한 평가(evals for DevOps AI agents)에서 주장하는 핵심입니다. 즉, 모델뿐만 아니라 도구 사용 동작(tool-using behavior)을 테스트해야 한다는 것입니다. 이를 인프라로서의 에이전트 하네스(the agent harness as infrastructure)에서 강조하는 최소 권한 원칙(least-privilege thinking)과 결합하고, MCP 서버를 다른 구성 요소와 마찬가지로 버전 관리 및 모니터링해야 하는 컴포넌트로 취급하십시오.
적용 위치
읽기 전용 PromQL MCP 서버는 온콜(on-call) 에이전트의 감각 중 메트릭(metrics) 측면을 담당합니다. 트레이싱(tracing) 측면은 DevOps AI 에이전트를 위한 관측성(observability for DevOps AI agents)에서 다루며, 이 서버가 보완하는 인간용 대시보드는 운영 환경의 Prometheus + Grafana 설정(production Prometheus + Grafana setup)에서 제공하는 것들입니다. 이 패턴은 일반화될 수 있습니다. 질문에 답할 수 있는 가장 작은 도구 표면(tool surface)을 선택하고, 호출자를 신뢰하는 대신 비용이 많이 드는 파라미터(parameters)를 직접 계산하며, 반환하기 전에 요약하고, 쓰기 경로(write path)를 한 곳이 아닌 두 곳에서 비활성화하십시오. 그렇게 한다면, 에이전트는 메트릭에 위험을 초래하지 않으면서도 장애 발생 시 메트릭을 읽는 데 도움을 줄 수 있습니다.
📌 이 가이드의 최신 버전과 DevOps, SRE, Kubernetes, 관측성(observability) 및 클라우드 비용 가이드 전체 라이브러리를 devtocash.com에서 확인하세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기