はじめに
AIエージェントに「ユーザーを無効にして」と依頼すると、画面を開き、対象を検索し、ボタンを押して完了メッセージを読む操作になりがちです。
人間には自然な手順です。しかし、AIに同じ仕事を任せる経路として、画面操作が最も効率的とは限りません。AIは画面の読み取り、待機、クリック位置、表示文言、モーダルの変化を扱う必要があります。途中で失敗すると、何が更新済みかを画面だけから判断しにくくなります。
一方で、対象の状態を取得・変更するAPIがあり、必要な操作を安全な単位で呼べるなら、AIは画面を経由せずに仕事を進められます。
この記事では、AIが外部システムを扱うときの画面操作、API、MCP Tool、Skillの役割とコストを整理します。あわせて、実行経路と検証経路を分け、E2Eを画面操作と同列の実行境界として扱わず、テストの分類として位置付けます。
画面操作やE2Eをなくすことがこの記事の主張ではありません。画面でしか確認できないことはE2Eテストで検証します。データの取得・変更は、できるだけ画面より内側の境界で扱う方が、AIにも人間にも効率がよくなります。
画面操作はAIにとって高コストな境界である
画面操作には、人間にとっては暗黙に補っている情報が多く含まれます。AIがブラウザを操作すると、その暗黙の部分も毎回扱う必要があります。
例えば、ユーザーの無効化を管理画面で行うとします。
1. ログイン画面を開く
2. 認証情報を入力する
3. ユーザー一覧へ遷移する
4. 検索条件を入力する
5. 対象の行を見つける
6. 詳細画面を開く
7. 無効化ボタンを押す
8. 確認モーダルで実行する
9. 成功表示と一覧の表示内容を確認する
この経路は、画面の品質を確かめるためには必要です。しかし状態変更だけが目的なら、画面の読み込みと非同期処理を待つことになります。表示文言、DOM構造、ボタン配置が変わると操作に失敗します。検索結果の並び順や同名データを解釈し、クリック後に本当に更新されたかも確認しなければなりません。失敗時には、UI、通信、業務処理、DBのどこで止まったかを切り分けます。
これはE2Eが悪いという意味ではありません。E2Eは、ユーザーが実際に辿る導線、入力制御、権限に応じた表示、画面遷移、描画を確認するためのテストです。
ただし、AIが内部の状態を反復して調査・修正するたびにE2Eを主経路にすると、目的に対して確認範囲が広くなります。画面を経由しているために、変更したいデータより多くの不確実性を抱えることになります。
同じ仕事でも操作する境界を分ける
「ユーザーを無効にする」仕事は、次のように複数の境界から実行できます。
| 対象となる層 | 例 | 得意なこと | 主なコスト |
|---|---|---|---|
| UI・ブラウザ操作 | PlaywrightやComputer Useで管理画面を操作する | 画面上の導線、表示、入力、権限表示を扱う | 遅い。画面変更に影響されやすい |
| API | RESTやGraphQLのAPIを呼ぶ | 状態を直接取得・変更する | AI向けの意図や安全制約を別途設計する必要がある |
| MCP Tool |
disable_user を呼ぶ |
AIが呼べる操作単位と結果を整える | Toolの粒度、認可、監査を設計する必要がある |
| Skill | 「退職者アカウントを停止する」手順 | 複数操作の順序、確認条件、出力をそろえる | 手順だけでは操作の認可や制御を強制できない |
API、MCP Tool、Skill、E2Eは、同じ階層の代替物ではありません。
APIはシステムの機能です。MCP Toolは、AIに公開する操作を整える境界です。Skillは、その操作を使って仕事を完了するための手順です。一方、E2Eは画面を含むユーザー導線を検証するテストの分類です。
Playwrightはブラウザを操作する手段であり、UIを含むユーザー導線全体を検証する代表例がE2Eテストです。AIにブラウザを操作させること自体が、必ずしもE2Eテストになるわけではありません。
上段はAIが状態を取得・変更する実行経路です。下段はユーザーがUIを使う経路であり、E2Eテストは画面という別の契約を確認します。実行経路と検証経路を分けることで、状態変更の失敗と画面上の不具合を別々に扱えます。
なぜAPIだけでなくMCPが必要なのか
AIが外部システムを操作する方法は、MCPが登場する前からありました。GitHubならGitHub API、SlackならSlack API、社内システムならそのシステムのAPIを、AIアプリケーションから個別に呼び出せます。
接続先ごとに専用の統合を作る方法では、AIアプリケーションと外部システムの組み合わせが増えるたびに、接続や呼び出し方を実装・保守することになります。
AIアプリA ─ GitHub専用実装 ─ GitHub API
├ Slack専用実装 ─── Slack API
└ 社内専用実装 ──── 社内API
AIアプリB ─ GitHub専用実装 ─ GitHub API
├ Slack専用実装 ─── Slack API
└ 社内専用実装 ──── 社内API
MCPは、Anthropicが2024年11月に公開した、AIアプリケーションと外部のデータや機能をつなぐ共通プロトコルです。MCPに対応したアプリケーションは共通の方法でMCPサーバーに接続し、サーバーが公開するToolやResourceを利用できます。AnthropicによるMCPの発表では、接続先ごとに個別実装が必要だった状況を、MCPが解決しようとする課題として挙げています。
AIアプリA ─ MCP Client ─ MCP ─ GitHub用MCP Server ─ GitHub API
├ MCP ─ Slack用MCP Server ─── Slack API
└ MCP ─ 社内MCP Server ────── 社内API
AIアプリB ─ MCP Client ─ MCP ─ GitHub用MCP Server ─ GitHub API
├ MCP ─ Slack用MCP Server ─── Slack API
└ MCP ─ 社内MCP Server ────── 社内API
共通化によって接続ごとの重複は減らせます。しかし、統合の作業がなくなるわけではありません。接続先ごとのMCPサーバー実装に加えて、認証、権限、サービス固有の意味や操作単位は引き続き扱う必要があります。
つまり、MCPは既存APIを置き換えるものではありません。APIが各システムの機能を定義するのに対し、MCPはAIアプリケーションが外部の機能やデータを発見し、共通の方法で利用するための接続を標準化します。MCP Toolの内部でREST APIやSDKを呼ぶ構成は、その役割分担に沿っています。
APIは状態と機能を直接扱う入口である
APIはAI専用の仕組みではありません。Web画面、バッチ、モバイルアプリ、外部連携、AIのどれからでも利用できる、システムの機能とデータの入口です。
GET /users?email=example@example.com
PATCH /users/usr_123
{
"status": "disabled"
}
このAPIが認可、入力検証、監査ログ、冪等性を適切に持っていれば、画面を経由するより少ない手順で目的を達成できます。結果もHTTPステータス、更新後の状態、監査IDのように構造化して受け取れます。
ただし、既存APIをそのままAIへ渡せばよいわけではありません。内部APIには、AIに公開したくないフィールド、低い粒度の更新、複数呼び出しが前提の操作が含まれることがあります。
例えば、次のAPIだけをAIに見せるとします。
GET /users/{id}
PUT /users/{id}
POST /audit-logs
AIはユーザーを取得し、更新用の大きなJSONを組み立て、無関係な項目を壊さないように送信し、監査ログも忘れず記録する必要があります。技術的には可能でも、業務操作としては境界が低すぎます。
APIはまず、人間のアプリケーションも含めたシステム境界として設計します。AIにどこまで何をさせるかは、その一段上で考えます。
MCP ToolはAIに公開する操作の境界である
MCPは、AIアプリケーションと外部のツール・データを接続する共通プロトコルです。MCPサーバーは、実行可能なTool、文脈となるResource、定型的なPromptなどを公開できます。MCPの仕様では、Toolをモデルが呼ぶ関数として位置付けています。
MCP Toolの内部でREST API、GraphQL、SDKを利用する構成は自然です。MCPはAPIと競合するものではありません。
実装上、MCP Toolが既存APIのラッパーでなければならないわけではありません。Tool自身がバックエンド処理を実装することもあります。ただし状態変更では、認可、入力検証、監査、業務ルールを集約したApplication APIやApplication Serviceを経由する方が、UI、バッチ、AIで同じ制約を守りやすくなります。この記事では、AIへ公開する操作境界としてMCP Toolを整理します。
先ほどの低い粒度のAPIに対し、AIへは次のようなToolを公開できます。
find_user_by_email(email)
disable_user(user_id, reason)
get_user_status(user_id)
disable_user の内部で、対象の現在状態を確認し、無効化できる遷移だけを許可し、理由と実行者を監査ログへ残せます。呼び出し側のAIは「どのフィールドを残すか」ではなく、「誰を、なぜ無効化するか」を渡せばよくなります。
この形にすると、AIに見せる操作の名前、入力、出力、認可、監査を業務上の単位でそろえられます。
APIを1対1でTool化しない方がよい場合
既存APIの全エンドポイントを、そのままMCP Toolにする必要はありません。複数APIを正しい順序で呼ぶ場合や、更新前の状態確認と競合確認が必須の場合は、AI向けのToolとしてまとめる価値があります。操作理由やチケット番号を監査に残す場合、AIに触らせない内部フィールドがある場合、画面文言ではなく構造化した結果を返したい場合も同様です。
一方で、既存APIが既にこの境界を満たし、認可と監査も揃っているなら、薄いラッパーを増やす必要はありません。MCP Toolにする目的は、HTTPを隠すことではなく、AIが間違えにくい操作境界を作ることです。
Skillの中心的な役割は仕事の進め方を定義すること
Skillは、AIに再利用可能な手順、判断基準、参照資料、出力形式を与えるものです。OpenAIのSkillsの説明でも、MCPサーバーがライブデータと制御された操作を担い、Skillはそれらをどの順番で使い、どの結果を返すかというワークフローを担うものとして説明されています。
Skillは指示文だけで構成されるとは限りません。SKILL.mdに加えて、scripts、references、assetsなどの補助ファイルを含められます。Skillの作成ガイドでは、スクリプトも同梱できると説明されています。そのため、「Skillは実行能力を持たない」と一律に言うより、仕事の進め方を定義する役割が中心だと捉える方が正確です。
例えば、退職者アカウントの停止という仕事には、単なるdisable_userより多くの判断があります。
1. 依頼にあるメールアドレスで対象を特定する
2. 雇用状態と停止予定日を確認する
3. 既に停止済みなら変更せず、現在状態を報告する
4. 停止理由とチケット番号を付けて無効化する
5. 更新後の状態と監査IDを確認する
6. 実行内容と未対応事項を決まった形式で報告する
これはToolではなく、仕事の手順です。Skillには、この手順を使う条件、Toolを使う順番、情報が不足したときの確認事項、実行を止める条件を記述できます。最終報告に含める項目や、チーム固有の規約、テンプレートもSkillに置けます。
Skillだけで、外部システムへの認可や状態変更の制御まで保証できるわけではありません。状態変更の安全性はAPIやMCP Toolなど、操作を実行する側でも強制します。一方、複数手順や判断が不要な単発照会なら、Skillを作らずToolを直接呼ぶ方が簡単です。
MCP経由でSkillを配布しても、安全制約の置き場所は変わらない
MCPにはSkillをResourceとして配布するためのSkills Extensionがあります。Skills Extensionの仕様では、SKILL.mdを含むSkillを発見・取得できます。
これはSkillを届ける経路の話です。Skillが表す手順と判断基準、Toolが担う実行能力、APIやApplication Serviceで強制する認可・監査という役割分担は変わりません。配布方式よりも、状態を変える制約を文章だけに置かないことが重要です。
E2Eテストとブラウザ操作を使い分ける
AIが画面を操作することが妥当な場面もあります。判断は「UIがあるか」ではなく、「画面そのものを確かめたいか」で行います。UIを含むユーザー導線をテストするならE2Eを選びます。AIがブラウザを使って調査や操作をする場合は、テストを実行しているのか、単に画面を操作しているのかを分けて考えます。
| やりたいこと | まず選ぶ境界 | 理由 |
|---|---|---|
| 画面で権限に応じて無効化ボタンが見えないことを確認する | E2E | 表示と導線が要件そのものだから |
| フォームの入力エラーや確認モーダルを確認する | E2E | ブラウザ上の体験を検証する必要があるから |
| 100件のアカウントを条件付きで停止する | APIまたはMCP Tool | 画面を100回辿る理由がないから |
| 障害時に対象データの状態と処理履歴を調べる | 読み取り専用APIまたはMCP Tool | 構造化した結果で比較・絞り込みできるから |
| 退職手続きを規約どおりに完了し、報告を残す | Skill + MCP Tool | 複数の確認・変更・報告を一つの仕事としてそろえるから |
実務では、APIやToolで状態を作り、E2Eテストで画面に正しく反映されるかを確認する組み合わせが扱いやすいです。
例えば、テストデータはAPIで作成し、ログイン後の表示・操作だけをブラウザで検証できます。AIが調査するときも、読み取りはToolで絞り込み、必要な画面だけを最後に確認する方が、失敗した箇所を切り分けやすくなります。
最初に必要なのはSkillやMCPではなく、変更できる境界である
AIエージェントを導入すると、最初にMCPサーバーやSkillを作りたくなることがあります。しかし、画面の奥にしか状態変更の入口がないなら、先に考えるべきはAPIやアプリケーションサービスの境界です。
次の順に考えると、追加するものを増やしすぎずに済みます。
- 状態を安全に取得・変更できるAPIまたは内部サービスがあるか
- AIへ公開する操作を、業務上の単位と認可の単位で切る必要があるか
- 複数の操作、停止条件、チーム固有の判断を再利用するか
- 最終的に画面の導線や表示まで確認する必要があるか
1だけが必要なら、APIや既存CLIで足ります。2が必要ならMCP Toolを検討します。3まで必要ならSkillを追加します。4を確認するなら、画面を含むユーザー導線をE2Eテストで検証します。
この順番にすると、「MCPを入れたからすべてTool化する」「Skillを作ったから安全になる」「AIに任せるから画面を自動化する」といった目的と手段の逆転を避けられます。
まとめ
AIにブラウザを操作させることはできます。しかし、ブラウザ操作とE2Eテストは同じものではありません。画面は人間の利用体験を確認する境界であり、内部状態を繰り返し取得・変更する主経路にすると、待機・表示変更・曖昧な失敗判定のコストを抱えます。
APIは、システムの機能と状態を直接扱う入口です。MCP Toolは、AIに公開する操作を安全で意味のある単位に整えます。Skillは、複数のToolを使って仕事を進める手順と判断基準です。E2Eテストは、画面の導線、表示、入力、権限を確認するために使います。AIのブラウザ操作は、それ自体ではE2Eテストではありません。
まずは目的の状態をどの境界で取得・変更すべきかを決めます。その上で、AI向けの操作境界が必要ならMCP Toolを作り、繰り返す業務手順があるならSkillにします。画面操作は画面でなければ確かめられないことに絞り、E2Eテストはユーザー導線を検証するために使うと、AIの作業もテストも追いやすくなります。