Claude Media
mcp-grafanaでPromQLを実行し、p95・p99を出す手順

mcp-grafanaでPromQLを実行し、p95・p99を出す手順

mcp-grafanaのPrometheusツール群(query_prometheus・メタデータ系・query_prometheus_histogram)の使い分けと、p50〜p99を安全に出すための権限設計をまとめます。

mcp-grafanaには、Grafanaに登録済みのPrometheusデータソースへ問い合わせる専用ツールが6つあります。生のPromQLを投げるquery_prometheus、メトリクス名やラベルを探す4つのメタデータ系、そしてp50・p90・p95・p99を出すquery_prometheus_histogramです。使い分けの軸は「何を知りたいか」と「どのPromQLをモデルに書かせるか」の2点に絞れます。

Prometheus向けの6ツールは何ができるか

READMEのPrometheus Querying節は、機能を3系統に分けています。ツール名と必要権限はRBAC表に載っています。

系統ツール名できること
クエリ実行ツール名query_prometheusできることPromQLの実行。instant(瞬間値)とrange(期間)の両方
メタデータツール名list_prometheus_metric_namesできること使えるメトリクス名の一覧
メタデータツール名list_prometheus_metric_metadataできることメトリクスのメタデータの取得
メタデータツール名list_prometheus_label_namesできることセレクタに合致するラベル名の一覧
メタデータツール名list_prometheus_label_valuesできること特定ラベルの値の一覧
パーセンタイルツール名query_prometheus_histogramできることhistogram_quantileによるp50・p90・p95・p99の算出

6ツールとも、必要なRBAC権限はdatasources:queryとdatasources:readです。スコープはdatasources:uid:prometheus-uidのようにUID単位で絞れます。データソースのUIDは、同じくREADMEにあるlist_datasourcesやget_datasourceで調べます。

導入そのものはmcp-grafanaの導入とRBAC設計で扱っています。Prometheus自体にMCPサーバーを立てる構成はPrometheus連携の記事が対象です。ここでは、Grafana経由で既存のデータソースを使う前提で進めます。

手順:クエリ用の最小構成で起動する

パーセンタイルを出すだけなら、書き込み系のツールは要りません。起動引数の--disable-writeで止めておきます。不要なカテゴリは--disable-<category>で個別に止められます(Prometheus側のカテゴリ名はprometheusなので、これは止めずに残します)。

claude mcp add-json grafana \
  '{"command":"uvx","args":["mcp-grafana","--disable-write"],"env":{"GRAFANA_URL":"https://myinstance.grafana.net","GRAFANA_SERVICE_ACCOUNT_TOKEN":"<トークン>"}}'

サービスアカウントには、対象のPrometheusデータソースに限ったdatasources:readとdatasources:queryを付けます。READMEの例では、特定のPrometheusだけを許す場合のスコープはdatasources:uid:prometheus-prodのように書かれています。Editorなどの組み込みロールでも動きますが、READMEは最小権限から外れると明記しています。

query_prometheus_histogramでパーセンタイルを出す

ヒストグラムのパーセンタイルは、PromQLではhistogram_quantile()で計算します。READMEのquery_prometheus_histogramは、この関数で算出するp50・p90・p95・p99用のツールです。パラメータの細目はREADMEに載っていないため、依頼文でメトリクス名と出したいパーセンタイルを伝え、Claudeに引数を組み立てさせる形になります。

依頼文は、たとえば次のような形です。メトリクス名は仮のものです。

Grafanaのprometheusデータソースで、http_request_duration_seconds の
p95とp99を直近10分の窓で出して。まずメトリクス名とラベルが
実在するか確認してから計算して。

「実在確認から」と頼む理由は、メトリクス名の取り違えを避けるためです。list_prometheus_metric_namesとlist_prometheus_label_namesを先に呼ばせれば、存在しない名前で空の結果を受け取る事故を減らせます。

手書きPromQLで計算するときの式の形

query_prometheus_histogramで足りない切り口、たとえばジョブ別のp99を出したいときは、query_prometheusで式を直接実行します。式の形は次のとおりです。

対象式
クラシックヒストグラム(全体のp90)式histogram_quantile(0.9, sum by (le) (rate(http_request_duration_seconds_bucket[10m])))
クラシックヒストグラム(ジョブ別)式histogram_quantile(0.9, sum by (job, le) (rate(http_request_duration_seconds_bucket[10m])))
ネイティブヒストグラム(全体)式histogram_quantile(0.9, sum(rate(http_request_duration_seconds[10m])))

クラシックヒストグラムではleラベルが必須で、sum byにleを含めないと計算が成立しません。leのないサンプルは黙って無視されます。ClaudeがPromQLを組むときに最も落としやすい箇所なので、依頼文かCLAUDE.mdに書いておく価値があります。

## PromQLの書き方(Grafana MCP経由)
 
- パーセンタイルは histogram_quantile(rate(..._bucket[窓])) で計算する
- クラシックヒストグラムの sum by には必ず le を含める
- サマリー型の quantile ラベルを avg() で平均しない
- 実行前に list_prometheus_metric_names でメトリクス名を確認する

3項目目の理由は、サマリーが事前計算したパーセンタイルを平均しても、統計的に意味を持たない値になるためです。

計測側がヒストグラムかサマリーかを先に確かめる

histogram_quantileが使えるのは、ヒストグラム型のメトリクスだけです。quantileラベルが付いたサマリー型は、パーセンタイルが計測側で事前計算されています。両者の違いは次のとおりです。

比較軸ネイティブヒストグラムクラシックヒストグラムサマリー
パーセンタイルの指定ネイティブヒストグラムPromQLで後から自由に指定クラシックヒストグラムPromQLで後から自由に指定サマリー計測時に固定
集計(複数インスタンスの合算)ネイティブヒストグラム可能クラシックヒストグラム可能(バケット境界が揃っていれば)サマリー不可
誤差を決めるものネイティブヒストグラム設定した解像度クラシックヒストグラム該当バケットの幅サマリー設定したφ方向の誤差

メタデータ系ツールで_bucketサフィックスの有無やquantileラベルを確認させれば、どの式が使えるかを実行前に判断できます。複数レプリカをまたぐ全体のp99が欲しいのにサマリー型だった場合は、サマリーのパーセンタイルを平均しても意味のある値にならないため、計測側をヒストグラムにする選択肢を検討します。

ダッシュボードのように同じ式を何度も評価する場面では、計算が重くなることがあります。そうした場面では記録ルール(recording rule)で事前計算しておきます。

結果を読むときの注意:パーセンタイルは推定値

パーセンタイルは、サーバー側で計算したものも含めてすべて推定値です。ヒストグラムでは、値が入っているバケットの幅が誤差の上限になります。

たとえば、実際は220ms付近に集中しているリクエストがle="0.3"(200〜300msのバケット)に入ると、推定値は295msになります。SLOが300msなら「ぎりぎり」に見えますが、実態は余裕がある状況です。実測の220msと推定の295msの差は75msで、200〜300msという100ms幅のバケットの内側に収まっています。Claudeが返したp95が閾値に近いときは、バケット境界の設定を確認する前提で読むと誤読を避けられます。

もう1つ、バケット数が単調増加でない異常データでは、histogram_quantileは補正した上で情報レベルの注釈を付けます。注釈が出たら、入力データ側の問題を調べます。

依頼文の型:窓・集計軸・時間範囲を明示する

パーセンタイルの値は、rateの窓と集計軸で変わります。時間窓はrate()の角括弧で指定します。式の形が決まるのは、依頼文に次の3点が入っているときです。

伝える項目依頼文の例式に効く場所
窓依頼文の例「直近10分」「5分窓」式に効く場所rate(...[10m])の角括弧
集計軸依頼文の例「ジョブ別」「全体で1本」式に効く場所sum by (job, le)かsum by (le)
時間範囲依頼文の例「今の値」「過去6時間の推移」式に効く場所instant(今)かrange(推移)

query_prometheusはinstantとrangeの両方に対応するので、「今の値」と「推移」で使い分けを依頼文に書いておくと迷いません。障害の切り分けでは、まず直近の窓でp99を見て、悪化していれば推移を取る流れが自然です。

窓を短くすると、直近の変化には敏感になりますが、リクエスト数が少ないサービスでは推定が不安定になりやすくなります。この点はPrometheusの仕様上の記述ではなく、一般的な統計の性質からの見立てです。

最大値と最小値の推定には、次の書き方もあります。histogram_quantile(1, ...)が推定最大値、histogram_quantile(0, ...)が推定最小値です。外れ値の上限を知りたいときに役立ちます。

既存ダッシュボードのPromQLを出発点にする

自前でPromQLを組む前に、チームがすでにGrafanaに置いている式を拾う手があります。READMEにはget_dashboard_panel_queriesというダッシュボード用のツールがあり、パネルのタイトル、クエリ、データソースのUIDと種別を取得できます。必要な権限はdashboards:readです。

p95のパネルがすでにあるなら、その式のrateの窓やby句をそのまま使えます。「このダッシュボードのレイテンシのパネルと同じ式で、p99を出して」と頼めば、チームの既存の定義とずれにくくなります。ダッシュボード全体のJSONを読ませると、READMEが警告するとおりコンテキストウィンドウを大きく消費します。パネルのクエリだけを取るこのツールか、get_dashboard_summaryのほうが軽く済みます。

結果を人の目で確かめたいときは、generate_deeplinkでGrafana上の画面へのリンクを作れます。READMEのNavigation節には、データソースを指定したExploreのリンクを生成できると書かれています。Claudeの出した数値を、Exploreで同じ式を流して照合する使い方です。

権限と運用の設計

クエリ実行ツールは、データの中身を読み出せます。READMEの--disable-queryは、データソースへクエリを投げるツールを登録から外すフラグです。対象にはquery_prometheusとquery_prometheus_histogramが含まれ、メタデータ系は残ります。「探索はさせるが数値は読ませない」という構成に使えます。

Claude Code側でも許可を絞れます。Claude CodeのMCPツールのルールはmcp__<サーバー名>__<ツール名>の形で書き、サーバー名の後にワイルドカードを置けます。サーバー名をgrafanaとした場合の許可設定の例は次のとおりです。

{
  "permissions": {
    "allow": [
      "mcp__grafana__list_prometheus_metric_names",
      "mcp__grafana__list_prometheus_label_names",
      "mcp__grafana__query_prometheus_histogram"
    ]
  }
}

この例では、探索系2つとパーセンタイル計算だけを確認なしで許可しています。手書きPromQLのquery_prometheusは許可リストに入れず、都度確認を挟む形です。mcp__ルールに括弧で引数条件を付けることはできません。引数単位の制御が必要なら、--disallowedToolsか、Grafana側のスコープで絞ります。

よくあるつまずき

空の結果が返る: メトリクス名かラベルの取り違えが大半です。メタデータ系ツールで実在を確認してから、計算に進みます。

ツールが見えない: --disable-prometheusや--disable-queryを付けていないか確認します。カテゴリ単位の無効化は、サーバー起動引数で決まります。

権限エラーになる: datasources:queryだけでなくdatasources:readも必要です。スコープのUIDがデータソースと一致しているかも見ます。

ネイティブ用の式をクラシックに当ててしまう: ネイティブヒストグラムの式は_bucketサフィックスを持たず、sum byにleも要りません。クラシック用の式をそのまま流すと、leのないサンプルは無視される仕様のため、期待した値になりません。メタデータ系ツールで、対象のメトリクス名に_bucketが実在するかを確かめます。

ジョブ別を頼んだのに全体の値が返る: 集計軸が依頼文になければ、式はsum by (le)の全体集計になりえます。「ジョブ別」「インスタンス別」と書いて、by句に入れる軸を指定します。

Lokiも同時に調べたい: ログ側のクエリはLogQL検索の記事にまとめています。

Claude Codeから繋ぐ構成を前提にしましたが、READMEのクイックスタートはClaude DesktopやCursorなど他のMCPクライアントも想定しています。

まとめ

mcp-grafanaのPrometheus向けツールは、探索(メタデータ4つ)、汎用クエリ(query_prometheus)、パーセンタイル(query_prometheus_histogram)の3層で考えると整理できます。p50〜p99の定型は専用ツール、ジョブ別などの切り口は手書きのhistogram_quantile、という分担です。

結果は推定値であり、バケット幅が誤差を決めます。権限はdatasources:queryをUID単位で絞り、--disable-writeと許可リストで運用を固めると、読み取りに専念させやすくなります。

この記事を共有:XはてブLinkedIn