AIに“安全に”書かせるCMS ― エージェントにスキーマとコンテンツを任せる制御層
平原 典彦 — Tesseraを開発しているエンジニア。ヘッドレスCMSとAI連携に関心があります。
Claude CodeやCursorにコードを書かせるのは、もう当たり前になりました。差分をレビューし、テストを通し、気に入らなければgitで戻す——コードには「任せても大丈夫」と言える仕組みが揃っているからです。
ところが、同じエージェントにCMSのスキーマやコンテンツを書き換えさせるとなると、急に手が止まる人が多いのではないでしょうか。その怖さの正体を分解すると、だいたい次の4つに行き着きます。
- 壊れ: AIが良かれと思ってフィールドを必須化したら、値が入っていない既存エントリが壊れる
- 衝突: 予約語や既存スキーマとぶつかる変更を、AIが気づかず通してしまう
- 追跡不能: どのエージェントがいつ何を変えたのか、後から追えない
- 戻せない: 気づいたときには上書きされていて、元に戻す手段がない
多くのMCP対応CMSは、エージェントの操作を「直接patch=即時反映」する形をとっています。手軽な反面、上の4つの怖さがそのまま残ります。Tesseraは「AIに任せる」ことと「勝手に変わる」ことを分離する設計にしました。以下、4つの怖さに一つずつ答えていきます。
1. スキーマ変更は「提案」まで。反映は人間が承認する
MCP経由でエージェントが送れるのは、スキーマ変更の提案だけです。propose_content_type_changeを呼んでも、コンテンツタイプ本体に即座に反映されることはありません。
提案はまず自動検証を通ります。予約済みフィールド名との衝突、reference型の整合性、既存スキーマとの矛盾——ここで問題が見つかれば提案は成立しません。検証を通過した提案はpending_approvalとしてステージングされ、管理画面に差分として並びます。人間がその差分を確認して承認するまで、既存のスキーマにもコンテンツにも一切影響しません。
意図的な設計として、承認・却下の操作自体はMCPツールとして提供していません。エージェントは提案はできても、自分の提案を自分で通すことはできない。ここが「任せる」と「勝手に変わる」を分ける最初の一線です。
2. 書き込む前に、何が起きるかを見る(dry-run)
コードで言えば--dry-runにあたるものが、コンテンツ書き込みにもあります。preview_entry_writeは、エントリの作成・更新をコミットせずに検証し、「実行したら何が起きるか」だけを返す読み取り系ツールです。
エージェントは書き込む前に、たとえば次のような違反を先に受け取れます。
- unique重複:
slugが既存エントリと重複している - 必須未入力:
requiredなフィールドに値がない - 参照切れ: reference先に指定したエントリが存在しない
- 自己参照の循環・深さ超過: 参照が自分自身をたどってループする、あるいは深すぎる
- 単体型・ワークスペース上限: 1件しか持てない単体型に2件目を作ろうとしている、上限を超える
- 公開予約の妥当性: 予約日時の指定が不正
更新の場合は、これらに加えてbefore/afterのdiffを返します。エージェントは「この更新で、どのフィールドがどう変わるか」を確定前に把握できます。人間がレビューでdiffを見るのと同じことを、AIが書き込みの前段でできるわけです。
3. どのエージェントが何を変えたか、すべて記録する
複数のエージェント、複数のAPIキーが同じワークスペースを触るようになると、「誰がこれを変えたのか」が分からなくなりがちです。
Tesseraは、どのAPIキー(=どのエージェント)が、どのエントリを、いつ変更したかをリビジョン履歴に記録します。MCP経由でもGraphQL経由でも、さらにロールバック操作そのものも、すべて履歴に残ります。list_entry_revisionsで、あるエントリがたどってきた変更の履歴を追えます。
APIキー単位で記録されるので、「このエージェントの一連の変更を確認したい」といった追跡が後からできます。追跡不能という怖さに対する答えは、地味ですが、記録を欠かさないことに尽きます。
4. ワンコマンドで、任意の時点へ巻き戻す
それでも間違いは起きます。大事なのは、起きたあとに確実に戻せることです。
rollback_entryは、エントリを任意の過去リビジョンへ復元します。ポイントは、履歴を消さないことです。巻き戻しは過去の状態を「上書きで復活」させるのではなく、新しいリビジョンとして記録されます。つまり「戻した」という操作自体も履歴に残り、さらにその前後へまた移動できます。破壊的なundoではなく、常に前に進みながら任意の状態を再現する——git revertに近い考え方です。
制御層があると、何が変わるか
一般的な「エージェントが直接patch」型では、AIの判断がそのまま本番に届きます。速い代わりに、壊れ・衝突・追跡不能・戻せない、の4つがそのままリスクとして残ります。
Tesseraは、エージェントと本番データの間に制御層を1枚挟みました。提案は人間が承認し、書き込みは事前にdry-runで確かめ、変更はすべて記録し、間違えても巻き戻せる。この層があるからこそ、「AIに任せる」と踏み込めるようになります。制御層は自由を奪うためではなく、安心して任せるためにあります。
まとめ
- AIにCMSを書き換えさせる怖さは「壊れ・衝突・追跡不能・戻せない」の4つに分解できる
- 提案→人間承認: スキーマ変更は
pending_approvalでステージングされ、承認するまで反映されない。承認操作はエージェントに渡していない - 書き込み前のdry-run:
preview_entry_writeが、unique重複・必須未入力・参照切れ・循環・上限・公開予約の妥当性をコミットせず検証し、更新時はbefore/afterのdiffを返す - エージェント監査: どのAPIキーがどのエントリをいつ変えたかをMCP/GraphQL両経路で記録し、
list_entry_revisionsで追跡できる - ワンコマンド巻き戻し:
rollback_entryで任意のリビジョンへ復元。履歴は消さず、巻き戻し自体も新しいリビジョンとして残る - 「AIに任せる」と「勝手に変わる」を分離する制御層こそ、エージェントにCMSを任せられる前提になる
「AIがCMSの構造を理解する」——Tesseraのコンセプトは、AIにただ操作を開放することではなく、AIが安全に操作できる土台をCMS側に用意することにあります。制御層はその中核です。