groundtruth-mcp
groundtruth-mcp
あなたのコーディングエージェントは、リポジトリ内のすべてのファイルを読めるにもかかわらず、まだ推測しているだけです。 これは、プロジェクト自身のチェック、リプレイ、シミュレーション、クエリをMCPツールに変換し、エージェントが編集の結果を予測するのではなく、観察できるようにします。
中国語ドキュメント · 導入ガイド · アーキテクチャ · 固定シードの理由
問題
構造化設定(ワークフローグラフ、ルールファイル、ステートマシン、パイプライン定義)を編集するエージェントは、誤った種類のコンテキストを扱っています。スキーマは読めますが、実際に実行されたときに何が起こるかを読むことはできません。
だから推測するのです。リトライ制限を変更し、その変更は安全だと伝えます。なぜなら「安全」というのが、もっともらしい差分に対して最も確からしい次のトークンだったからです。誰も実際に実行していません。違反した制約は、3ファイル先の不変条件や、ポリシーが最後に調整されて以来誰もサンプリングしていない分布の中にあります。
修正方法は、より優れたプロンプトではありません。エージェントに観察できるものを与えることです。
機能
flowchart LR
E[Agent edits a config] --> L[lint]
L -->|DANGLING_TRANSITION at states 1.transitions 0.to| E
E --> R[replay seed=7]
R -->|the 5 steps that actually ran| E
E --> S[simulate 2000 seeds]
S -->|88.3% success · p95 2566ms · PASS| E
S --> G["CI: groundtruth simulate --gate"]
G -->|same config, same thresholds| Sあなたが書く4つの小さな関数から構築された5つのツール:
ツール | 回答 | それを有用にする特性 |
| この設定は自己整合的ですか? | すべての問題が編集すべき正確なパスを伝えます |
| これを実行すると何が起こりますか? |
|
| 私の変更は全体的に良くなりますか、悪くなりますか? | シード付きバッチ、分布、閾値、合格/不合格 |
| データには実際に何が入っていますか? | 正規表現ではなくデータベースによって強制される読み取り専用 |
| どのテーブルがありますか? | スキーマを推測する必要がないように |
同じ機能はCLIとしても実行できるため、groundtruth simulate --gate は、エージェントが最適化するのと同じ閾値を読み取るマージゲートです。コピーが1つしかないので、それらが乖離することはありません。
60秒
pip install "groundtruth-mcp[mcp]"
git clone https://github.com/ZhenGtai123/groundtruth-mcp && cd groundtruth-mcp
groundtruth --config examples/checkout-flow/groundtruth.toml lint broken_checkout同梱の例は、設定駆動のチェックアウトです。4つのページ、不安定な決済ゲートウェイ、リトライポリシー、去っていく顧客。broken_checkout.json には、エージェントが実行できない設定を編集するとき実際に犯すミスが含まれています。
broken_checkout: BLOCKED errors=6 warnings=1 infos=0
source: flows\broken_checkout.json
-- ERRORS — these block (6) --
[DANGLING_TRANSITION] states[1].transitions[0].to 'payment_methd' does not name any states.id
fix: point it at an existing state id, or delete the transition
[DEAD_END] states[6] 'review_hold' has no outgoing edge and is not marked terminal — a run that arrives here stops with no result
fix: give it a transition, or mark it kind = "terminal" with an outcome
[DUPLICATE_STATE] states[2] duplicate id='shipping' (first declared at states[1])
fix: rename one of them; the engine silently uses the first and ignores the rest
[RATE_OUT_OF_RANGE] policy.gateway_failure_rate 1.4 is above the maximum 1.0
fix: this is a probability, not a percentage — 0.18, not 18
[RETRY_BUDGET_TOO_THIN] policy.max_retries 140% gateway failure with 1 retries leaves 196.0% of checkouts failing on payment alone (budget: 2.0%)
fix: raise max_retries, or lower gateway_failure_rate if the gateway improved
[UNKNOWN_STATE_KIND] states[3].kind 'stage' is not one of ['step', 'gateway', 'retry', 'terminal']
fix: the engine only knows these four kinds; anything else is treated as a plain step
-- WARNINGS (1) --
[UNREACHABLE_STATE] states[4] 'gift_wrap' cannot be reached from 'cart_review'
fix: no path from start reaches this state — delete it, or wire it inそのうち6つはルールファイルに由来します。RETRY_BUDGET_TOO_THIN は8行のPythonから来ています。「このリトライ予算は製品の障害目標を満たしているか」はスキーマではなく算術だからです。
それでは1回の実行を見てみましょう:
groundtruth --config examples/checkout-flow/groundtruth.toml replay standard_checkout --seed 3standard_checkout seed=3 outcome=success steps=7 fingerprint=52b66a2024a61b5d
metrics: latency_ms=2506 payment_attempts=2 steps=7
-- TRACE --
0. cart_review --always-->
1. shipping --always-->
2. payment_method --always-->
3. authorize --failure--> # attempt 1 declined
4. retry_decision --retries_left--> # 0 retry(s) used of 2
5. authorize --success--> # attempt 2 authorized
6. confirmed # terminal: successシード3は常にその7つのステップを生成します。あなたのマシンでも、CIでも、来年でも。それがこのツールを読む価値あるものにしています。
そしてその2000回分:
groundtruth --config examples/checkout-flow/groundtruth.toml \
simulate standard_checkout --runs 2000 --seed 0 --gate --check-determinismstandard_checkout: PASS runs=2000 base_seed=0 fingerprint=449e16b50c8184c0
-- OUTCOMES --
success: 1767 (88.3%)
abandoned: 227 (11.3%)
payment_failed: 6 (0.3%)
-- METRICS (mean / p50 / p95 / max) --
latency_ms: 1587.75 / 1553 / 2566 / 3626
payment_attempts: 1.06 / 1 / 2 / 3
steps: 5.12 / 5 / 7 / 10
-- THRESHOLDS --
PASS rate:success = 0.8835 expected >= 0.8 (below this, the flow is losing customers faster than the business case allows)
PASS rate:stuck = 0 expected <= 0 (a run with nowhere to go is always a config bug, never bad luck)
PASS p95:latency_ms = 2566 expected <= 4000 (95th-percentile checkout wall time, retries included)
PASS mean:payment_attempts = 1.0585 expected <= 1.6 (rising attempts mean the gateway is degrading or the retry policy is too eager)
note: determinism: 20 seeds re-ran identically真価を発揮する部分
1つの数値を上げます — shipping.abandon_chance を 0.05 から 0.28 へ。これは製品の微調整に見えてレビューを通過する類の編集です:
$ groundtruth lint standard_checkout
standard_checkout: OK errors=0 warnings=0 infos=0 # exit 0
$ groundtruth simulate standard_checkout --runs 2000 --seed 0 --gate
standard_checkout: FAIL runs=2000 base_seed=0 fingerprint=5a7c0d9feed5adca
-- OUTCOMES --
success: 1336 (66.8%)
abandoned: 660 (33.0%)
-- THRESHOLDS --
FAIL rate:success = 0.668 expected >= 0.8
PASS rate:stuck = 0 expected <= 0
PASS p95:latency_ms = 2549 expected <= 4000
PASS mean:payment_attempts = 0.795 expected <= 1.6
# exit 1構造的には完璧です。コンバージョンの21ポイントが失われています。スキーマも型システムもコードレビューもそれを検出できません。宣言された帯域を持つシード付きバッチは、人間が差分を読む前に、プルリクエスト上で4秒で検出します。
逆方向にも機能します。express_checkout は標準フローよりも高い成功率(91.0%)を報告しますが、より悪い設定です。その決済失敗率は0.3%に対して3.9%で、問題なさそうな主要な数値の中に隠れています。集計値はそれを見逃します。手書きのバリデータはそれを明確に指摘します:
[RETRY_BUDGET_TOO_THIN] policy.max_retries 18% gateway failure with 1 retries
leaves 3.2% of checkouts failing on payment alone (budget: 2.0%)どちらの層も他方を包含しません。だから2つあるのです。
導入方法
1つのモジュールと1つの設定ファイル。examples/checkout-flow/groundtruth_app.py が全体のテンプレートです — コメントを含めて約100行。
from groundtruth_mcp import Context, Issue, Loaded, Toolkit, Trace
kit = Toolkit(name="my-project", subject_noun="pipeline")
@kit.loader
def load(name: str):
path = CONFIG_DIR / f"{name}.yaml"
if not path.is_file():
return None # → "no pipeline named X; available: ..."
return Loaded(subject=parse(path), source=str(path))
@kit.validator
def check(pipeline, ctx: Context) -> list[Issue]:
... # the checks a rule file can't express
@kit.runner
def run_once(pipeline, seed: int, ctx: Context) -> Trace:
... # one run, pure in (pipeline, seed)@kit.runner だけで replay と simulate の両方が得られます — ライブラリはシードごとにそれを1回実行し、結果を保持します。その他すべて(シードのバッチ処理、集計、パーセンタイル、閾値ゲーティング、出力予算、エラーメッセージの表現、MCPサーフェス)はパッケージから提供されます。
# groundtruth.toml
[project]
toolkit = "groundtruth_app:kit"
[lint]
rules = "rules.toml"
[[thresholds]]
metric = "rate:success"
min = 0.80
note = "why this number, for whoever has to change it"次に groundtruth doctor が何が配線されているかを教え、groundtruth serve がツールをエージェントに渡し、groundtruth simulate --gate がマージをブロックします。ドメイン別の例による完全なチュートリアル: docs/ADOPTION.md。
自動的に得られるルール
構造チェックは記述するのではなく宣言します。構造化設定が実際に劣化する方法をそれぞれカバーする12のタイプがあります:
タイプ | 検出するもの | 主要フィールド |
| 中途半端に書かれたエントリ |
|
| エンジンが静かに隠す重複ID |
|
| エンジンが処理しない値 |
|
| 数値が入る場所に文字列 |
|
| 確率であるフィールドに入った |
|
| 命名規則を破るID |
|
| 1件必要だが空のリスト |
|
| 名前が変更されたものへの参照 |
|
| 開始点からのパスが存在しないノード |
|
| 出口のない非終端ノード |
|
| 自分自身に遷移するノード |
|
| 出口のないリング(意図的なもののための |
|
セレクタは意図的に小さなパス言語です — states[].transitions[].to — そしてすべての一致は、それが見つかった具体的なパスを報告します。これにより、「遷移が無効です」ではなく states[3].transitions[1].to と報告できるのです。
各ルールはオプションの code、severity、hint を受け取ります。ヒントはエージェントが行動するための文なので、命令形で書いてください。
読み取り専用は読み取り専用
query は1つの SELECT を実行します。それを強制する2つの層がありますが、それらは同等ではありません。
キーワードスキャンはユーザー体験です。DELETE FROM … を、モデルが解読しなければならないデータベースエラーではなく、その旨を伝える文で拒否します。これは境界ではありません — テキストに対するブロックリストは常に1つのケースで間違う可能性があり、その典型例は SELECT * INTO audit_copy FROM users です。これは SELECT で始まり、拒否された動詞を含まず、テーブルを作成します。
境界はデータストアです。SQLiteでは mode=ro と PRAGMA query_only、PostgreSQLでは READ ONLY トランザクション、両方にステートメントタイムアウト。テストはガードを完全に迂回し、接続が依然として拒否することを確認します。
カラムの秘匿化は、強制である唯一のテキストレベル制御です。deny_columns 内の値は、フェッチ後かつ結果文字列が存在する前に削除されるため、SELECT * でもそれらを漏らすことはできません。返されるすべてのものは <untrusted> タグでラップされます。命令のような形をしたものを含む notes カラムはデータであり、データとしてラベル付けされて届く必要があるからです。
CLI
groundtruth [--config PATH] <command>
doctor what is wired up, what is missing
targets the configs this project exposes
lint TARGET exit 1 on errors
replay TARGET --seed N one deterministic run, full trace
simulate TARGET --runs N --seed N --gate --check-determinism
query "SELECT ..." one read-only statement
schema readable tables and columns
serve the MCP server, over stdio終了コード: 0 はクリーン、1 は検出あり(lintエラー、帯域外の閾値、非決定性)、2 は実行不可(設定不良、能力不足、拒否されたクエリ)。機械可読な出力が必要な場合は lint、replay、simulate に --json を追加してください。
インストール
pip install groundtruth-mcp # core: rules, simulation, gating, CLI
pip install "groundtruth-mcp[mcp]" # + the MCP server
pip install "groundtruth-mcp[postgres]" # + the PostgreSQL data sourcePython 3.11以上。コアにはサードパーティの依存関係がありません — これは意図的で、CIゲートがエージェントスタックに依存しないようにしています。ベアランナーはSDKをインストールせずにあなたの閾値を強制できます。
配線を検証する
python scripts/mcp_smoke.py [path/to/groundtruth.toml]サーバーを実際のサブプロセスとして起動し、stdioで初期化し、ツールを一覧表示し、そのうち2つを呼び出し、返ってきた内容を出力します — クライアントが実行するのと同じシーケンスです。エージェントがツールを認識しないと非難する前に、これを実行してください。
CIがすべてのプルリクエストで強制すること
「テストが実行された」という意味のバッジではありません — 6つの項目 で、それぞれが何かをブロックしてきました:
チェック | なぜ提案ではなくゲートなのか |
|
|
| パッケージは |
| 69テスト、カバレッジ下限75%(現在はブランチカバレッジ込みで78%) |
| 実際のサブプロセス、実際のstdio、実際の |
| プロジェクト自身の引数を自分自身に適用 |
| 失敗できないlintは装飾にすぎない |
明確に述べた制限事項
SQLテーブルの許可リストはテキストベースです。
FROMとJOINの後の識別子をスキャンします。実際のテーブル単位の強制はデータベースの権限です。これは優れたエラーメッセージを備えたガードレールであり、実際に効くのは読み取り専用トランザクションです。キーワードブロックリストは文字列リテラル内にも一致します。
grantを含む値でフィルタリングするクエリは拒否されます。修正するには実際のSQLパーサーが必要ですが、パーサーが境界ではないため、構築する価値はありません。自動
LIMITはヒューリスティックです。 サブクエリ内のLIMITはトップレベルの追加を抑制します。max_rowsはレンダリングされる内容の上限を依然として設定します。セレクタはフィルタリングしません。
states[].transitions[]はすべてを走査します。states[kind=terminal]はありません。述語言語は、誰も求めていない3番目の機能になるでしょう。代わりに@kit.validatorを書いてください。閾値はプロジェクト全体で、ターゲットごとではありません。 プロジェクト内のすべてのターゲットは同じ帯域で判断されます。設定に本当に異なる帯域が必要なプロジェクトは、別々の
groundtruth.tomlファイルにすべきです。PostgreSQLソースは実装されていますが、軽くしか試されていません。 テストスイートは、サービスコンテナなしでどこでも実行できるSQLiteに対して境界を証明しています。
このプロジェクトの由来
パターンが定着した非公開コードベースから抽出されたものです。それは、コントリビューターたちが、スキーマ検証を通過するものの実行時に壊れる設定を出し続けたオーサリングパイプラインです。ドメイン固有の部分は残されました。一般化されたのは、その形——チェック、リプレイ、シミュレート、クエリ——と、機能リスト以上に重要であることが判明した一連の決定事項です:
エージェントとCIの両方が読む単一のしきい値リスト。2つのコピーがずれてしまい、ツールはCIが拒否する数値をしばらくPASSと報告していたからです。
有効な代替案をインラインで挙げるエラー。何を渡せるのかを知るために2回目の呼び出しをしなければならないエージェントは、代わりに推測してしまうからです。
ライブ設定から構成されるツールの説明。古い説明は、エージェントが誤って、しかも自信を持って使うツールになるからです。
すべての経路で出力に上限を設定すること。1つの過剰なクエリが会話の残りを追い出してしまうからです。
docs/ARCHITECTURE.md には、モジュールマップと完全な理由が記載されています。
ライセンス
MIT。
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
A paid remote MCP for OpenAI Codex agent coordination MCP, built to return verdicts, receipts, usage
Free public MCP for AI agents — 193 tools, 44 workflows. No API key.
Agent Replay Debugger MCP — record every agent step + deterministic replay. Step-debugger for
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ZhenGtai123/groundtruth-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server