AI Audit Event Mcp について
AI Audit Event Mcp はエージェントの監査イベントを検証可能な形で記録し、GDPR/AI Act のコンプライアンス監査スキルを提供します。承認フローやデータ主体の記録出力に対応し、Merkle 署名による公証も利用できます。
主な機能
- 01SHA-256 ハッシュチェーンでイベントを記録
- 02イベントチェーンの完全性を検証
- 03イベント記録の絞り込みと出力
- 04人による承認と状態確認
- 05GDPR/AI Act 監査スキルを同梱
- 06Merkle ルートと Ed25519 公証に対応
活用シーン
- 01エージェントのツール呼び出しと判断を記録
- 02監査ログの改ざんを確認
- 03データ主体の記録を NDJSON で出力
- 04イベントストアのコンプライアンスを確認
MCP 対応
このリモート MCP サーバーは HTTPS 経由で、イベントの記録、検証、検索、出力、承認のツールを提供します。クライアントは Cloudflare Access または OAuth で認証して接続できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
@kajaril/audit-event-mcp
エージェントの運用を支えるインフラストラクチャです。ハッシュチェーンによる監査ログ、Merkle による公証、GDPR/AI Act 対応スキルを備えています。
概要
- エージェントのイベント(ツール呼び出し、判断、人間によるターン)を、クライアントごとの SQLite ログに SHA-256 ハッシュチェーンで記録します。各レコードは暗号学的に前のレコードとリンクされます。
- オプションで、バッチを Merkle ルートと Ed25519 署名で公証します(有料プラン)。外部監査担当者は、kajaril に問い合わせることなく検証できます。
- データ主体のすべてのイベントを、必要に応じて NDJSON としてエクスポートします(GDPR 第20条のデータポータビリティ)。
- あらゆるイベントストアに対して8つの GDPR/AI Act の観点で評価する Claude Code スキルが付属します。
MCP エンドポイント
https://audit-event.kajaril.com/mcp
HTTPS 上の JSON-RPC 2.0 で、Cloudflare Access(サービス・トークン)または OAuth クライアントクレデンシャルのアクセストークンで認証します。詳しくは認証をご覧ください。利用開始については [email protected]までお問い合わせください。
ツール
| ツール | 説明 |
|---|---|
record_event | 監査イベントを1件書き込みます。{ id, chain_hash }を返します。 |
verify_chain | イベント範囲のchain_hashを再計算します。検証済み件数と破損したエントリを返します。 |
query_events | セッション、エージェント、イベントタイプ、または日付範囲で絞り込みます。input_hashは返されません。 |
export_dossier | subjectIdのすべてのイベントをNDJSONとしてエクスポートします(GDPR 第20条)。1時間有効のダウンロードURLを返します。 |
request_approval | アクションの承認を人間に依頼します。approvalId、承認ページのapprovalUrl、およびwebhookSecretを返します。チェーンにはapproval.requestedとして記録されます。 |
check_approval | 承認状態を確認します。pending | approved | denied | timeoutと、決定後は理由および回答者を返します。 |
クイックスタート
イベントを記録します。
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "record_event",
"arguments": {
"agentId": "travel-assistant",
"eventType": "tool.call",
"purpose": "User requested flight search via travel assistant",
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"input": { "tool": "search_flights", "origin": "LHR", "dest": "JFK" },
"lawfulBasis": "contract",
"subjectId": "user-8821"
}
}
}
チェーンを検証します。
{ "jsonrpc": "2.0", "id": 2, "method": "tools/call",
"params": { "name": "verify_chain", "arguments": { "limit": 100 } } }
データ主体のレコードをエクスポートします。
{ "jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": { "name": "export_dossier", "arguments": { "subjectId": "user-8821" } } }
認証
認証方法は3種類あります。いずれも、テナントを選択する署名検証済みのclient_idに紐づきます。ユーザーが指定した値によってテナントが選択されることはありません。
Cloudflare Access サービス・トークン(手動での利用開始):トークンヘッダーを送信すると、CF Access が検証済み JWT を挿入します。すべての機能を利用できます。
OAuth ブラウザーフロー(MCP クライアント向け、コピー&ペースト不要):クライアントでサーバーを指定し、残りの情報を自動検出させます。
claude mcp add --transport http audit-event https://audit-event.kajaril.com/mcp
RFC 8414 メタデータでは、動的クライアント登録(/oauth/register)、PKCE S256 による認可(/oauth/authorize)、および共通のトークンエンドポイントが公開されます。サインイン済みのテナント運用者がブラウザーで同意を承認します。付与されたスコープ(agentまたはadmin)は発行されたトークンに紐づけられます。
OAuth クライアントクレデンシャル(M2M):POST /oauth/tokenでクライアントシークレットを1時間有効の Bearer トークンに交換します(application/x-www-form-urlencoded、HTTP Basic または本文のclient_id/client_secretパラメーター)。
curl -s https://audit-event.kajaril.com/oauth/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d grant_type=client_credentials -d scope=agent
スコープは2種類あり、それぞれ個別に発行・ローテーションされます。
| スコープ | 呼び出し可能なツール |
|---|---|
agent | record_event、request_approval、check_approval |
admin | すべてのツール、およびPOST /credentials/rotate |
シークレットは発行時またはローテーション時(POST /credentials/rotate、本文{"scope":"agent"})に一度だけ表示され、テナントの Durable Object にはハッシュのみが保存されます。スコープをローテーションすると、古いシークレットは直ちに無効になります。発行済みのアクセストークンは1時間以内に期限切れとなります。
承認ツールは、本番バックエンド向けの通常の REST API としても利用できます。POST /approvals(request_approvalと同じ本文)とGET /approvals/:idを、Authorization: Bearer <access token>とともに呼び出します。
仕組み
ハッシュチェーン
各イベントは、それ以前のすべてのイベントをコミットします。このチェーンは、第一原理から再計算できます。
input_hash_slot = input_hash ?? input_hash_omitted_reason
chain_hash = SHA-256(id + "|" + event_type + "|" + input_hash_slot + "|" + prev_hash)
呼び出し元が input の代わりに inputHashOmittedReason を指定すると、その理由文字列がチェーンに含まれます。つまり、省略自体が改ざん検知可能になります。
Merkle 公証(有料プラン)
15 分ごと(または保留中のイベントが 1,000 件に達したとき)に、公証 Worker は次の処理を行います。
- 保留中のレコードから
{ id, chain_hash }のペアを収集します - id でソートし、SHA-256 のバイナリ Merkle ツリーを構築します
- Ed25519 でルートに署名します
merkle_rootとnotary_sigを各レコードに書き戻します
公証の公開鍵は /.well-known/notary-pubkey で公開されています(検証ページでは go.kajaril.com 上で同一オリジンにプロキシされています)。監査者は kajaril に接続せずに、オフラインで署名を検証できます。公証側が受け取るのは input_hash、payload_ref、またはペイロードの内容ではありません。
証跡の検証
export_dossier は、go.kajaril.com 上の人が読める証跡へのリンクと、添付された生の JSONL 証拠ファイルを返します。誰でもそのファイルを https://go.kajaril.com/verify にドロップできます。ブラウザーは、エクスポートされたプリイメージ(id | event_type | input_hash ?? omitted_reason | prev_hash)から各レコードのチェーンフィンガープリントを再計算し、公開鍵を使って各公証 Ed25519 署名を確認します。何もアップロードされず、判定はクライアント側で計算されます。
プライバシー設計
inputはローカルでハッシュ化されます。R2 バケットが明示的にバインドされていない限り、生の値は保存されませんinput_hashはquery_eventsのレスポンスから除外されます。証跡では、独立した検証を可能にするチェーンのプリイメージとして(prev_hashとともに)エクスポートされます。これらはダイジェストであり、内容ではありませんpayload_refは呼び出し元に返されません。すべてのハンドラー境界で適用されていますexport_dossierの結果が空(eventCount: 0)であることは、対象者に関するデータが存在しないことを示す有効な GDPR 証拠です
イベントタイプ
tool.call | tool.result | decision.made |
human.turn | memory.read | memory.write | error.raised |
approval.requested | approval.decided
approval.* タイプは予約済みです。人間による承認が要求され、決定されると、witness が自らこれらを記録します。record_event はこれらを拒否します。エージェントが人間の意思決定に関する証拠を捏造できてはなりません。(approval.deferred と approval.escalated は後日使用するために予約されています。)
意思決定 Webhook
承認に callback_url が含まれている場合、人間が決定した時点で、その決定(approve/deny)がそこへ POST されます。これにより、中断したエージェントはポーリングではなく処理を再開できます。タイムアウト時に Webhook は呼び出されず、ポーリングによって解決されます。
すべての配信には署名が付与されます。本文は JSON です。
{
"type": "approval.decided",
"approval": { "id": "…", "status": "approved", "reason": null, "responderId": "…",
"agentId": "…", "sessionId": "…", "actionSummary": "…",
"actionPayloadHash": "…", "createdAt": "…", "decidedAt": "…", "expiresAt": "…" },
"chainEvent": { "id": "…", "chainHash": "…" }
}
chainEvent はハッシュチェーン内の approval.decided エントリーを指しています。証拠として引用してください。
署名の検証。 Webhook シークレット(whsec_…)は、すべての request_approval レスポンスで webhookSecret として返されます。ダッシュボードは不要です。各配信には次の情報が含まれます。
X-Kajaril-Signature: t=<unix seconds>,v1=<hex>
検証手順:
- ヘッダーから
tとv1を読み取ります。|now − t|が 300 秒を超える場合は拒否します。 - 次の値で
HMAC-SHA256を計算します。キーは秘密文字列そのもの(UTF-8、whsec_プレフィックスを含む)、メッセージは"{t}." + raw request bodyです。 - 16 進数にエンコードし、定数時間比較で
v1と比較します。
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
リファレンス実装は src/lib/webhook.ts の verifyWebhookSignature です。テストでも同じコードパスを実行します。
セルフホストに関する注意:Webhook 署名では、WEBHOOK_SIGNING_SECRET Workers Secret からテナントごとのシークレットを導出します。設定されていない場合、Webhook は一切送信されず(署名なしで送信されることはありません)、request_approval は webhookSecret: null を返します。ポーリングは引き続き機能します。
通知チャネル
request_approval は channels: ["telegram", "email"] を受け付け、承認者に優先順位に沿って通知します。まず即時に通知し、その後フォールバックとしてメールを送信します。
Telegram(即時)。 一度接続すれば利用できます。POST /channels/telegram/connect(admin スコープ)は、有効期限が15分のワンタイム t.me ディープリンクを返します。リンクを開いて「Start」を押すと、そのチャットにインラインの Approve/Deny/Deny with reason ボタン付き承認カードが届きます。「Deny with reason」を選ぶと短い返信の入力が求められ、その内容は決定とともに記録されます。これは二値の記録よりも強力な Art. 14 の証拠になります。再接続すると、紐付けられたチャットが置き換わります。
Email(フォールバック)。 承認者のメールアドレスを一度設定します。POST /channels/email(admin スコープ)に {"address": "…"} を指定します。メールは必要な場合にのみ送信されます。
- 即時チャネルで通知できなかった場合(未接続、送信失敗、またはリクエストされていない場合)は、すぐに送信されます。
- 即時通知カードが届いたものの、承認が未決定の場合は、10分後に送信されます。
- メールが役立つ前に承認の有効期限が切れる場合は、送信されません。
メールは [email protected] から決定リンク付きで送信されます。返信は [email protected] を通じて担当者に届きます。
通知レポート。 すべての request_approval の応答には、実際に行われた処理が含まれます。
"notifications": { "telegram": "sent", "email": "scheduled" }
(telegram:sent | failed | not_connected | unconfigured | not_requested、email:immediate | scheduled | expires_first | no_address | unconfigured | arm_failed | not_requested。)
TTL のデフォルト値はチャネルに応じて決まります。即時チャネルを使用する場合は30分、メールのみのリクエストでは4時間です。ttlSeconds が明示されている場合は、常にその値が優先されます。
セルフホストに関する注意:チャネルは任意です。TELEGRAM_BOT_TOKEN/RESEND_API_KEY/CHANNELS_KV がない場合、通知レポートは unconfigured となりますが、approvalUrl とポーリングを使って承認機能を利用できます。バインディングについては wrangler.jsonc と wrangler.go.jsonc に記載されています。
適法な根拠(GDPR Art. 6)
legitimate_interest | contract | legal_obligation |
vital_interest | public_task | consent
個人データを処理するイベントには lawfulBasis を指定してください。処理しないイベントでは省略してください。
プラン
| 機能 | Free | Paid |
|---|---|---|
| ハッシュチェーン付きイベント書き込み | はい | はい |
verify_chain | はい | はい |
export_dossier(GDPR Art. 20) | はい | はい |
| R2 ペイロードストレージ | 任意 | 任意 |
| Merkle ルート + Ed25519 公証 | — | はい |
| compliance-audit の軸6(公証カバレッジ) | スキップ | 評価 |
compliance-audit スキル
skills/compliance-audit/SKILL.md は、任意のイベントストアを対象に GDPR/AI Act のコンプライアンスを8つの軸で検査する Claude Code スキルです。ワークスペースにコピーしてください。
cp -r node_modules/@kajaril/audit-event-mcp/skills/compliance-audit .claude/skills/
軸:
- 適法な根拠の有無 — GDPR Art. 5–6
- 目的の具体性 — GDPR Art. 5(1)(b)
human.turnイベントにおける対象者との紐付け- 保存期間の上限(≤ 730日)
- チェーンの完全性 — 10% のサンプルを再計算
- 公証カバレッジ ≥ 95%(有料プランのみ)
- 高リスクイベントの完全性 — AI Act Art. 12–13
- データ最小化の指標 —
payload_refの割合
各軸は、証拠の抜粋とともに pass | fail | warn を出力します。出力は JSON と Markdown の要約ブロックです。
セルフホストでのデプロイ
前提条件
- Workers と Durable Objects が有効な Cloudflare アカウント
- 認証済みの
wranglerCLI
手順
# 1. Create R2 bucket
wrangler r2 bucket create audit-payloads
# 2. Set notary signing key (paid tier)
wrangler secret put NOTARY_PRIVATE_KEY --config wrangler.notary.jsonc
# Value: hex-encoded Ed25519 private key — never committed to source
# 3. Deploy Workers
wrangler deploy
wrangler deploy --config wrangler.notary.jsonc
# 4. Add audit-event.kajaril.com as a CF Access Self-hosted Application
# Issue one service token per client with custom.client_id claim
# 5. Onboard a client
npx tsx src/scripts/onboard-client.ts --client-id acme-crm --tier free --region eu
# 6. Verify
curl https://audit-event.kajaril.com/health
作業ツリーに未コミットの変更がある状態で wrangler deploy を実行しないでください。デプロイするコードは git HEAD と一致している必要があります。
開発
npm install
npm test # 81 tests (node:sqlite adapter, no cloudflare/vitest-pool-workers)
npm run typecheck
npm run lint
ライセンス
MIT。Copyright © 2026 Kajaril Ltd.
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。