SayDo について
SayDoは、ツールが宣言どおりに動作するかを検証し、各実行の検証可能なレシートを作成します。適合性の証拠を必要とするツール公開者や評価者向けに、失敗と何も立証できなかった実行を区別します。
主な機能
- 01署名付き宣言に基づいてツールをテスト
- 02ローカルまたはサンドボックスで実行
- 03結果を合格、失敗、未対象に分類
- 04ハッシュチェーン付き署名レシートを発行
- 05実行間の動作変化を検出
- 06単独で動作するブラウザページでレシートを検証
活用シーン
- 01ツール適合性をCIビルドの条件にする
- 02独自宣言の有無を問わずMCPサーバーを検査
- 03送信データがツール入力に依存するか評価
- 04発行者を信頼せずにレシートを確認
MCP 対応
SayDoは、npmやPyPIから見つけたものを含むMCPサーバーをテストできます。宣言に基づいてツールを実行し、実行で立証された内容を検証可能なレシートに記録します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
4掲載時のツール一覧 · 3 週間前に更新
このツールにパラメーターはありません。
詳細
╔════════════════════════════════════════════════════════════════════════════════════════════╗
║ ║
║ ███████╗ █████╗ ██╗ ██╗██████╗ ██████╗ ║
║ ██╔════╝██╔══██╗╚██╗ ██╔╝██╔══██╗██╔═══██╗ ║
║ ███████╗███████║ ╚████╔╝ ██║ ██║██║ ██║ ║
║ ╚════██║██╔══██║ ╚██╔╝ ██║ ██║██║ ██║ ║
║ ███████║██║ ██║ ██║ ██████╔╝╚██████╔╝ ║
║ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ║
║ ║
║ does the tool do what it says ║
║ ║
╚════════════════════════════════════════════════════════════════════════════════════════════╝
草稿 — オーナーによる確認待ちです。 以下の内容はすべて測定値または機械的な処理に基づいており、マーケティング上の主張は含みませんが、文言はまだ承認されていません。
公開者は、署名付きの機械可読な契約で、ツールが何をするのかを正確に宣言します。ハーネスはツールを実行し、その契約に照らしてチェックします。実行ごとにハッシュチェーンで連結されたレシートが生成され、アカウントを作成せず、発行者を信頼することなく、誰でもブラウザーで検証できます。
この仕組みが答える問いは、意図的に限定されています。このツールは、宣言どおりに動作するか? 安全かどうかでも、優れているかどうかでもありません。動作を拒否するツールは、安全であると示されたわけではありません。何も示されていないのです。SayDo は緑のチェックマークを返すのではなく、そのことをそのまま伝えます。
判定結果の種類
pass 実行中、宣言された動作が確認された
fail ツールが、宣言で禁止されている動作をした
not-covered 実行からはいずれの結論も得られなかった
not-covered が、ひそかに pass に格上げされることはありません。この領域で起きる興味深い失敗の多くは、沈黙を良好な動作と読み違えることから生じます。
実行全体の結果は、2 つではなく、次の 4 つのいずれかです。
CONFORMANT 宣言どおりに動作し、その動作が確認された
NOT CONFORMANT 宣言で禁止されている動作をした
INCONCLUSIVE 失敗はなく、何も確認されなかった
(revoked / expired, once a registry has spoken)
INCONCLUSIVE が最も重要な意味を持ちます。あらゆる呼び出しを拒否するサーバーは、公開スイープで最もよく見られる種類ですが、ネットワークリクエストを送信せず、ファイルも書き込まず、プロセスも開始しません。そのため、素朴なハーネスは 3 つのチェックすべてをパスと判定し、何もしなかったプログラムに認定証を発行してしまいます。SayDo では、いずれかのチェックをパスとする前に、実行によって 動作 が示されている必要があります。また、サーバーが自分自身について説明することは、動作とは見なされません。
CI で使う
- uses: vince-gonzalez/saydo@main
with:
command: python -m my_server
declaration: saydo.declaration.json
ツールが宣言に反した場合だけでなく、実行から何も確認できなかった場合もビルドは失敗します。何も証明しない緑のチェックは、実際には誰も行っていない適合性の主張となるため、チェックがないよりも悪いからです。require-coverage: false を設定すると、そのようなビルドも通過します。レシートには引き続き inconclusive と記録され、認定証として扱われることはありません。
このツールが最も役立つのはここです。カバレッジを得るには、ツールが実際に作業を行う必要があります。そのためにはツールが受け付ける認証情報と入力が必要ですが、それらが存在するのは公開者自身の CI であり、実質的にほかの場所にはありません。
あらゆるツールで実行する
saydo は 1 つのツールをテストし、レシートを書き込みます。テスト対象のツールは自分のものでなくても、F-Keys のものでもなくてもかまいません。
python cli/saydo.py verify --npm @modelcontextprotocol/server-memory --sandbox
python cli/saydo.py verify --pypi mcp-server-time --sandbox
python cli/saydo.py verify --command "python my_server.py" --declaration mine.json
--declaration を指定した場合、テスト対象となるのは作者自身の契約です。指定しない場合は、意図的に保守的な契約が推定され、ほとんどの不変条件は not-covered になります。認証情報を持たない他人がサーバーを調べた場合の、誠実な結果です。
--sandbox を指定すると、外部への唯一の経路が記録プロキシであるコンテナー内でサーバーを実行します(Linux と Docker が必要です。封じ込めは CI で実証されており、tools/SANDBOX.md には、何が対象で何が対象外なのかが明記されています)。指定しない場合、実行は強制されず 観測 されるだけで、レシートには observed と記録されます。そのため、結果を生み出した仕組みの範囲を超える主張はできません。
続いて、結果を自分で確認します。
python cli/saydo.py status certivl # エージェントが読み取る、一度限りの判定結果
python cli/saydo.py selfcheck # ハーネスが失敗できることを証明する
verifier/index.html を開き、レシートとアンカーを貼り付けると、ページがブラウザー内でチェーン全体と署名を再計算します。ページからリクエストが外部に送信されることはありません。
4 つのレイヤー
1 宣言 公開者が約束する内容。署名付き (spec/)
2 ハーネス ツールを動作させ、監視する (tools/harness.py)
3 レシート ハッシュチェーン化され、署名付きで検証可能 (tools/receipt.py)
4 レジストリ 現在も有効な内容と、その有効期限 (tools/registry.py)
レイヤー 4 があるのは、レシートがある時点の事実を示すものであり、そのままでは 知りたい問いに答えられないからです。ツールを選ぶ人が知りたいのは、8 月に どう動作したかではありません。そのため、クレームは読み取り時に期限切れとなり、 誰も再実行しなかったというだけで緑の状態が続くことはありません。また、取り消しは 固定されます。撤回済みのクレームに対して新しい合格レシートを公開しても、その試みは 記録されますが、取り消しは解除されません。
ここにある、標準的な慣行とは異なる 2 つの点
反実仮想。 ツールがネットワーク呼び出しを行うのを監視すれば、呼び出しを
行ったことはわかります。しかし、データが外部に送信されたかどうかはわかりません。
そこで、異なる入力でツールを 2 回実行し、受信した内容が入力に応じて変わったか
どうかで各宛先を分類します。input-dependent はペイロードに渡した内容が含まれて
いたことを意味し、input-independent は含まれていなかったことを意味します。
内容を確認できない本文は、問題なしではなく unexamined と報告されます。
入力を example.com に送信したという文は、リクエストを送信したという文とは
異なります。そして、判断を下す人にとって意味があるのは前者だけです。
これは seeded/leakserver.py で実証されています。これは、テスト前にここで
主張されていたために存在しています。2 つのツールは、呼び出しのたびに同じホストへ
接続します。submit は渡されたテキストを POST し、ping は固定の本文を POST します。
FAIL network.none egress: ping->example.com; submit->example.com
FAIL data.stays-put ツールが独自の入力データを外部に送信しました:
submit -> example.com。実行間で入力を変えることで確認:
example.com は入力依存です
network.none は両方を検出しますが、区別できません。トラフィックの監視で
わかるのはそこまでです。data.stays-put が示すのは submit だけです。
これを現実のものにした修正。 2026-08-31 までは、マーカーは環境変数
SAYDO_CANARY にのみ設定され、それを外部に送信する唯一のフィクスチャも
そこから値を読み取っていました。これは既存の先行例でも使われている仕組みであり、
別の方法ではありませんでした。ツールの引数にマーカーを入れるものはなかったため、
279 個のサードパーティ製サーバーを対象に、プロキシはどの入力にも一度も含まれて
いない文字列を検索し、279 個すべてが unexamined となりました。現在は、上の
段落で常に説明していたとおり、実行ごとに異なるマーカーを 1 つずつ、その実行に
渡す引数に含めています。
ドリフト。 変更されていないバージョン番号のまま再定義されたツールは、単一の
レシートだけを見ても、まったく通常どおりに見えます。欺瞞が明らかになるのは、
2 回の実行の差分においてのみです。そのため、レシートは直前のレシートに連鎖し、
バージョンを変更せずに再定義された場合は、単に記録するのではなく serious と
評価されます。
これは珍しいものではありません。現場をきちんと調べた結果、同様のことを
行っているプロジェクトが複数見つかるまでは、ここでは珍しいものとして記載して
いました。詳しくは下記の関連する取り組みをご覧ください。askalf/truecopy は
検証済みのツール定義をコンテンツハッシュで固定し、バイト列が変更されると CI の
実行を失敗させます。これは別の名前で呼ばれたドリフト検出であり、こちらより先に
提供されていました。独自の主張は当初考えていたより限定的です。つまり、上記の
反実仮想と、バイト列が検証済みのものと一致するかを確認するのではなく、作者が
記述した契約に照らして動作をテストすることです。
構成
spec/ 宣言スキーマとフィールドの意味
tools/harness.py 適合性ハーネス (tools/HARNESS.md)
tools/runner.py ローカル実行と隔離実行 (tools/SANDBOX.md)
tools/egress_proxy.py 記録プロキシ、許可リストの適用、TLS の検査
tools/canary.py マーカーの生成と本文の検査
tools/differential.py 2 回の実行を比較する反実仮想分類器
tools/drift.py 前回のレシートからの変更点
tools/registry.py 有効期限と取り消し状態の固定
tools/status.py レシート -> エージェントが読む簡潔なオブジェクト
tools/declare.py 観測した実行から宣言の草案を作成
tools/discover.py npm と PyPI から MCP サーバーを検索
tools/sweep_scale.py 多数のサーバーをバッチ処理で測定
action.yml GitHub Action としての SayDo
verifier/index.html ネットワーク不要の自己完結型ブラウザーベリファイア
seeded/malserver.py ハーネスをテストするために、意図的に嘘をつくサーバー
seeded/silentserver.py 何も受け付けないサーバー。無応答を問題なしと報告しないか
ハーネスをテストするためのもの
ベリファイアを検証する
selfcheck は、意図的に自らの約束を 6 つ破るシードサーバーを実行します。ハーネスが適合していると報告したり、誤った不変条件に問題を帰属させたりした場合、ハーネスは壊れており、これまでに生成したレシートには何の価値もありません。宣言バリデーターも、拒否すべき 5 つの変更を使って同じ方法で検証します。
もう 1 つ、正反対の動作をするフィクスチャもあり、こちらも同じくらい重要です。このフィクスチャは起動してツールを一覧表示しますが、すべての呼び出しを拒否します。ハーネスはこれを INCONCLUSIVE と報告しなければなりません。これを CONFORMANT と報告したとき(実際にそう報告され、レシートにも署名されました)、その判定には何の意味もありません。見知らぬ相手から呼び出されたとき、ほとんどの公開 MCP サーバーがそうするからです。
CI はライブラリと Action の両方でこの 2 つを検証します。嘘をつくツールを使ったビルドと、何も示さない実行では、ビルドが失敗しなければなりません。
気にかけている理由で失敗しないチェックは、チェックではありません。
このプロジェクトが基盤とする先行事例
- TBOM v1.0.2、Jason M. Lovell、2026 — 10.5281/zenodo.18459260
- CTMS 1.0、George Kanellopoulos、2026 — github.com/gkanellopoulos/ctms
どちらも来歴を示すもので、ツールのメタデータが発行者の公開したものと同じであることを確立します。また、どちらも、そのメタデータに対する動作の検証は対象外であると明記しています。このリポジトリは、その対象外とされた部分を担います。SayDo の宣言は、TBOM の既存の attestations[] を通じて関連付けられ、既存の ToolDigest 形式を再利用するため、どちらの仕様も分岐させません。
関連する取り組みと、その境界
このセクションは増え続けています。それがこのセクションの役立つところです。 ここにあるものが珍しいと説明された後で、これらがそれぞれ見つかりました。そのため、 この一覧には、範囲を狭める必要があった主張の記録という側面もあります。
- Pipelock、github.com/luckyPipewrench/pipelock — 実行中のエージェントのトラフィックを 仲介し、署名済みのレシートを生成するエージェントファイアウォールです。
- truecopy、github.com/askalf/truecopy — ツール定義を検証し、オプションの Ed25519 署名とともに コンテンツハッシュで固定して、バイト列が変わると CI を失敗させます。実行時の封じ込めには redstamp と組み合わせます。
- Proofpane、github.com/Proofpane/releases — すべてのツール呼び出しをハッシュチェーン監査ログに 記録するガバナンスプロキシです。ログは Ed25519 署名付きで、オフライン検証可能な エビデンスパックとしてエクスポートされます。クローズドソースで、このリポジトリは ダウンロードミラーです。
- dcl-webhook、github.com/Fronesis-Labs/dcl-webhook — 改ざん検知可能な SHA-256 ハッシュチェーンに ポリシー判定を書き込みます。
境界を決めるのは暗号技術ではありません。ハッシュチェーン化され、署名付きで、 オフライン検証可能な記録は、今では一般的な設計であり、このリポジトリも その点については独自性を主張していません。
境界となるのは、記録の対象です。Pipelock と Proofpane は、デプロイ済みのエージェントが 実行したアクションを証明します。truecopy が証明するのは、ツールが検証済みのものと 同じバイト列であることです。これは整合性を保証し、無断の更新を検出しますが、 もともと不適切な動作をしていたツールについては何も明らかにしません。SayDo のレシートが証明するのは、 あるツールのあるバージョンが、実行前に書かれた契約に照らしてテストされ、 その作者が述べたとおりに動作したことです。
整合性が問うのは、これは自分が承認したものか? ということです。適合性が問うのは、 これは主張どおりに動作するか? ということです。どちらも価値があり、片方で もう片方に答えることはできません。
これまでに集めた証拠によれば、まだ共有されていないように見えるのは、 データが外部に出たこととリクエストが発生したことを切り分ける2回実行の反実仮想と、 ツールが単に実行を拒否しただけなのに問題なしと判定することを避ける仕組みです。 どちらかに先行事例があると分かった場合は、この一覧に加えるべきであり、 上の主張は擁護するのではなく削除すべきです。
最初の主張は、ここで1週間にわたって誇張されていました。Pipelock との違いは、 相手のカナリアは環境変数だが、こちらはツール自身の入力であると説明されていました。 しかし、こちらも環境変数でした。2026-08-31時点ではツールの入力になっており、 その論拠を示すフィクスチャもあります。この文の正確さを担保しているのは、 この段落ではなく、そのフィクスチャです。
ステータス
公開作業リポジトリです。ここで生成されるレシートには、F-Keys Creative LLC が保有する 概念実証用の鍵で署名しています。本番環境での署名方式は未決定です。 コーパスの測定結果は所有者による確認待ちの草案であり、そこに記載された数値は すべて下限値です。サーバーは認証情報なしで実行されたため、認証情報があるサーバーでは 記録された内容を超える動作をする可能性があります。
ライセンス:オープンなレイヤーである宣言スキーマと仕様テキスト(spec/)、
リファレンスツール群(tools/)、ブラウザ検証ツール(verifier/)、シード済みフィクスチャ(seeded/)は
Apache-2.0 です(LICENSE、NOTICE を参照)。署名済みの公開成果物には、このリポジトリでは
いかなるライセンスも適用していません。
╔════════════════════════════════════════════════════════════╗
║ ║
║ ███████╗ ██╗ ██╗███████╗██╗ ██╗███████╗ ║
║ ██╔════╝ ██║ ██╔╝██╔════╝╚██╗ ██╔╝██╔════╝ ║
║ █████╗ █████╗█████╔╝ █████╗ ╚████╔╝ ███████╗ ║
║ ██╔══╝ ╚════╝██╔═██╗ ██╔══╝ ╚██╔╝ ╚════██║ ║
║ ██║ ██║ ██╗███████╗ ██║ ███████║ ║
║ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚══════╝ ║
║ ║
║ · C R E A T I V E · ║
║ ║
║ ──────────────────────────────────────── ║
║ ║
║ Vincent Gonzalez ║
║ f-keys.com ║
║ ORCID 0009-0005-3640-014X ║
║ ║
╚════════════════════════════════════════════════════════════╝
F-Keys の一部です — 独立系のハードウェア、ソフトウェア、 インターネット製品を提供しています。作業ログ およびライブステータスをご覧ください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。