How it works · 日本語
カードをどう調べ、
何を返すのか。
Agent Cardは、エージェントの名前、接続先、認証方式、スキルなどを公開するJSONです。Scannerはこの文書を読み、宣言の問題点、署名の検証結果、複数カードに共通する手がかりを、根拠つきのレポートにします。

1. 入力するのは、調べたいカード
1件の公開URL、または手元のJSONと公開元URLを指定します。必要なら公開鍵の集合であるJWKSや「署名を必須にする」などの判定条件を加えます。一括調査では、利用者が用意した公開ホスト・カードURLの一覧をCLIに渡します。
ホスト指定では /.well-known/agent-card.json、続いて互換用の /.well-known/agent.json を探します。単体検査の明示URLはそのURLを取得します。一括調査では、.json で終わる独自パスを標準パスに続く候補に加えます。調査対象そのものをインターネット全体から自動発見する機能ではありません。
2. 取得し、読めるJSONかを確認する
公開URLはDNSの回答を確認し、許可した公開IPに接続先を固定してHTTPSで取得します。リダイレクト先も再確認します。取得できなければ、署名不正ではなく取得失敗として記録します。JSONを直接渡した場合、カード本文の取得は省略します。
文書は512 KiB、入れ子は64段までです。不正なUTF-8、重複したJSONキー、不正な数値などを拒否します。その後、対応する仕様世代のフィールドを共通の表現へまとめ、検査・比較に使います。署名検証には、受け取ったカードから別途再構成する署名対象を使います。
3. 宣言を、明示したルールと照合する
| 読む情報 | 照合する条件 | 返す指摘の例 |
|---|---|---|
| 名前・バージョン・スキル等 | 対応する主要フィールドの存在・型 | 必須文字列がない、型が異なる |
| 接続先URL | HTTPSか、公開元と別サイトか | AC-TLS-001:接続先の宣言がHTTP |
| 認証方式の宣言 | 認証の記載、APIキーの渡し方、OAuthフロー等 | APIキーをクエリに入れる宣言がある |
ここで読むのはカード内の設定です。ログインを試したり、エージェントにタスクを実行させたりはしません。「認証の宣言がない」と「実際に認証なしで使える」は別の結果です。
4. 署名は、本文・公開鍵・署名値を暗号的に照合する
- 署名ヘッダーを読む。 方式を示す
alg、鍵の識別子kid、公開鍵URLのjkuを解析します。未対応方式や曖昧なヘッダーは受け入れません。 - 署名されたバイト列を再構成する。 カードの
signaturesを除外し、対応するv1.0.1プロファイルでは所定の既定値・フィールド存在ルールを適用します。JCSでJSONのキー順や空白の表現を揃え、署名ヘッダーと組み合わせます。 - 公開鍵を選ぶ。 利用者が指定したJWKSを優先します。ネットワーク取得を使う場合は、カードと同じHTTPSオリジンの
jkuだけを許可します。kidがあれば一致する鍵に絞り、鍵の種類・曲線・用途と署名方式の組み合わせも確認します。 - 暗号ライブラリで照合する。 再構成したバイト列、公開鍵、カード内の署名値をECDSA・Ed25519・RSA系の対応方式で検証します。照合に成功した鍵は、その公開パラメータからSHA-256の指紋も計算します。
検証対象 = protectedヘッダーのbase64url
+ "."
+ base64url(JCS(署名対象の本文))
結果 = Verify(公開鍵, 検証対象, 署名値)
署名の結果は valid(照合成功)、invalid(照合失敗)、rejected(方式・形式・取得先等が方針外)、unresolved(使える鍵が得られない)、unsigned(署名なし)を区別します。署名の照合成功が示すのは、選んだ鍵と本文の整合性です。
5. 1枚ごとの検査レポートを返す
レポートには署名状態、指摘のルールID・重要度・根拠・修正案、適用した判定条件、カードのハッシュを含めます。公開URLを取得した場合は取得日時も残ります。
以下は、署名も認証宣言もない架空カードを検査した実出力の抜粋です。
{
"decision": "pass",
"signatures": [{ "status": "unsigned" }],
"findings": [
{ "id": "AC-AUTH-001", "severity": "medium", "category": "advisory" },
{ "id": "AC-SIG-000", "severity": "info", "category": "advisory" }
]
}
pass は、利用者が選んだ判定条件に対する結果です。この例では助言的な指摘のみなので既定条件を通ります。同じカードでも署名必須にすると fail になります。根拠のない「安全度スコア」にまとめず、指摘と署名状態を個別に返します。
6. 複数カードの共通点を、希少性と組み合わせで比較する
一括調査では各カードから、署名検証に成功した公開鍵の指紋、宣言された認証先ホスト、提供者サイト・名称、接続先サイト、取得時のIPv4範囲、値を除いたJSON構造を取り出します。
- 同じ信号を持つサイトを集める。 比較単位はサイトです。公開鍵の指紋は検証済みの鍵から、認証先や提供者はカードの宣言から得ます。
- 広く共有される値を除く。 2サイト以上で一致し、調査したサイトの5%を超えない値を、既定の比較対象にします。一般的なテンプレートや共用基盤だけで関連づけるのを抑えます。
- ペアごとに条件を判定する。 希少な公開鍵・一部の認証先・提供者サイトの一致は単独でも候補になります。名称・IP範囲・構造などの弱い信号は2種類以上を要求し、種類ごとの
ln(全サイト数 / 一致サイト数)の合計が2.5以上のペアを候補にします。共用IdPのホストは弱い信号です。 - 成立したペアをつないで候補群にする。 AとB、BとCが結ばれれば同じ群に入ります。その場合も、AとCが直接一致したとは限りません。レポートには、実際に条件を満たしたペアとその根拠を残します。
提供者URLなどの宣言は第三者が書ける情報です。一致は追加確認の手がかりであり、運営者の本人確認や共謀の証明にはなりません。
7. 集計と候補群を、再確認できる形で出す
架空の50サイトを実装に通した例では、2サイトだけが同じ提供者URLを宣言しました。共有率は4%で、候補条件を満たします。全50サイトで共通するJSON構造は除外されました。出力された候補群の抜粋は次のとおりです。
{
"sites": ["agent00.test", "agent01.test"],
"evidence": [{
"pair": "agent00.test|agent01.test",
"signals": ["provider-site|shared-provider.test"],
"score": "strong"
}]
}
strong はこの比較ルールでの扱いを示すラベルです。確率や、運営者の同一性を検証した評価ではありません。
| 出力 | 中身 | 次にできること |
|---|---|---|
| JSONL | 対象ごとの取得状態・検査結果・共通信号 | 記録を追う、途中再開する、再集計する |
| JSON | 統計、候補群、ペアごとの一致根拠 | 候補を確認する、他の分析処理へ渡す |
| Markdown | 重複を除いた集計表と候補群の件数 | 調査報告の下書きにする |
統計は、署名欄を除いた本文のハッシュで同じカードをまとめて数えます。候補群は各サイトで観測した信号から作ります。JSONLにはカード本文全体ではなく、抽出した観測項目を保存します。
利用者の作業は、どう変わるか
1枚を確認する場合:JSONの項目や署名を自分で照合する作業から、具体的な指摘を受け取り、同じ条件で再検査する作業へ変わります。
多数を調べる場合:1件ずつ取得して表で照合する作業から、観測記録・統計・根拠つきの候補を受け取り、候補を詳しく確認する作業へ変わります。一括調査はCLIで利用でき、Webは1枚ずつの検査に対応しています。
カードの検査・比較に使うルールは明示的です。LLMによる判定や実行時の行動試験は含みません。工数削減率や候補の検知精度はまだ測定していないため、その効果を数値で約束する段階ではありません。