0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Chatから指示出すとサイトが変更されるWebサイト作った

0
Posted at

「この文言を変えて」みたいな要望を、チャットで送るだけでWebサイトに反映される仕組みを作りました。

今回は、実際に作った prompt-to-app の構成と、どこを工夫したかをまとめます。

何を作ったのか

以下の体験を目指したコンセプトサイトです。

  • ユーザーが自然文で変更要望を送る
  • サーバー側で要望を安全なUI操作に変換する
  • 画面プレビューへ反映する
  • 必要に応じて public/index.html に永続化し、git commit && git push まで実行する

「会話がそのまま仕様になる」流れを、できるだけ短い導線で再現しています。

デモ画面のイメージ

フロント側にはランディングページとチャットUIを置いています。

  • public/index.html: ランディング + チャットUI
  • public/app.js: チャット送信、レスポンス反映、操作ガード
  • public/styles.css: UIデザイン

たとえば以下のような依頼を送る想定です。

  • 「ヒーロータイトルをもっと刺さる表現に変えて」
  • 「CTAを Start Free Pilot に変更して」
  • 「テーマを sunrise にして」

全体アーキテクチャ

今回の構成は大きく4つです。

  1. Firebase Hosting
  2. Firebase Functions(/api/chat
  3. APIサーバー(servers/api
  4. MCPサーバー(servers/mcp

1. Functionsで自然文を受ける

functions でチャットリクエストを受け、LLM(Groq)に問い合わせます。

ここで重要なのは、レスポンスを自由テキストではなく、JSON契約で受けることです。

  • 許可する操作を限定(例: setText, setCta, setStatus, setTheme
  • フロントで適用前にバリデーション
  • 想定外のDOM変更を防ぐ

この設計にしておくと、「AIが何を返すかわからない問題」をかなり抑えられます。

2. フロントは安全な操作だけ適用

public/app.js 側では、受け取ったJSON操作をそのまま実行せず、許可済みコマンドだけを反映します。

つまり「チャットで何でも変更できる」のではなく、変更可能な範囲を明示的に狭める構成です。

3. API + MCPでファイル更新とGit連携

プレビューだけでなく実ファイルへ反映したい場合、MCP経由でAPIサーバーを呼びます。

  • update_index_html: public/index.html の対象箇所を更新
  • git_commit_push_index_html: public/index.html をコミットして origin/main へpush

Gitフローは固定で、次の順序です。

  1. git add public/index.html
  2. git commit -m <message>
  3. git push origin main

変更がない場合はpushをスキップするようにしています。

MCPサーバーがやっていること(重要)

この構成でMCPサーバーは、AI(Functions)からの実行要求を、安全にAPIサーバーへ橋渡しするツールゲートウェイです。

言い換えると、Functionsが直接gitやファイル編集を触るのではなく、MCPが「使ってよい操作だけ」を公開します。

MCPサーバーの主な責務

  1. ツール定義の公開
  • update_index_html
    • 許可されたtargetだけ更新
    • 値の文字数制限あり
  • git_commit_push_index_html
    • コミットメッセージ長を制限
    • public/index.html対象の固定フローのみ実行
  1. 入力スキーマによる検証
  • toolごとにJSON Schemaを定義
  • additionalProperties: false で余計な引数を拒否
  • targetは列挙型で制限(任意DOM操作を防ぐ)
  1. APIサーバーへの中継
  • MCPは自分でHTML編集/Git操作を持たない
  • 実務処理はAPIサーバーの /edit-index-html/git-commit-push-index-html に委譲
  • MCPは「正規化された引数で呼び出す」役割に集中
  1. 認証ヘッダの付与
  • API向けに x-api-key を必ず付与
  • Cloud Run構成ではID Tokenを取得して Authorization: Bearer ... を付与可能
  • HTTPモード時、MCP自身にもBearerトークン保護を付けられる
  1. エラー整形
  • API応答をJSONとして扱い、失敗時はMCPエラーとして呼び出し元へ返却
  • Functions側はその結果をユーザー向けメッセージへ反映しやすい

なんでMCPを挟むのか

MCPを入れるメリットは、操作境界を明確にできることです。

  • Functionsの責務: 自然文を解釈して「何をしたいか」を決める
  • MCPの責務: 実行可能な操作を定義し、安全に中継する
  • APIの責務: 実際のファイル編集とGit実行を行う

この分離により、将来的にツールを増やす場合も「MCPに新しい安全なツールを足す」だけで拡張しやすくなります。

実際のリクエストフロー

  1. ユーザーがチャットで「文言変更して、コミットしてpushして」と入力
  2. FunctionsがLLM応答をJSON化し、必要なら tools/call を発行
  3. MCPがツール名と引数を検証
  4. MCPがAPIサーバーへ認証付きPOST
  5. APIサーバーがHTML更新/Git操作を実行
  6. 結果がMCP→Functions→フロントへ返る

セキュリティ上のポイント

  • MCPが公開するツールを最小にする(今回は2つ)
  • ツール引数を厳密にスキーマ制約する
  • APIキーとBearerトークンを分離し、漏れても影響範囲を限定する
  • 「自由なコマンド実行」を作らない

この構成だと、AIに権限を丸投げせず、操作を宣言的に制御したまま自動化できます。

ディレクトリ構成(抜粋)

public/
  index.html
  app.js
  styles.css
functions/
  index.js
servers/
  api/
    src/
      server.js
      indexHtmlService.js
      gitService.js
  mcp/
    src/
      server.js

役割分離のポイントは以下です。

  • functions: LLM呼び出しとチャットAPI
  • servers/api: HTML編集・Git操作の実務
  • servers/mcp: ツール公開レイヤー

ローカル起動手順

1. 依存をインストール

npm install -g firebase-tools
npm --prefix functions install
npm --prefix servers/api install
npm --prefix servers/mcp install

2. envファイルを作成

cp functions/.env.example functions/.env
cp servers/api/.env.example servers/api/.env
cp servers/mcp/.env.example servers/mcp/.env

最低限、functions/.env には GROQ_API_KEY を設定します。

3. エミュレータ起動

firebase emulators:start --only hosting,functions

必要なら別ターミナルでAPI/MCPサーバーも起動します。

npm run api:start
npm run mcp:start

実装して感じたハマりどころ

1. 「AIに自由にDOMを触らせない」設計が必須

最初は柔軟性を重視していましたが、すぐに危険だと分かりました。

  • 変更対象をIDベースで限定
  • 操作種別をホワイトリスト化
  • レスポンスをJSON Schemaで検証

この3つを入れるだけで安定性が大きく変わります。

2. Git実行環境の差分

実行環境によっては git バイナリが存在せず、spawn git ENOENT になることがあります。

APIサーバーを動かすランタイムに git を含める(Dockerfile側で担保)設計にすると解決しやすいです。

3. push失敗時の扱い

non-fast-forward などでpushが失敗するケースは必ず起きます。

  • エラーメッセージをUIに返す
  • どの段階で失敗したか(add/commit/push)を返す

この情報があると運用時の復旧が速くなります。

この構成の良かった点

  • 要望の入口を「自然文」に寄せられる
  • 変更を「安全な操作」に落とし込める
  • プレビューと永続化を分離できる
  • 既存のGit運用に接続しやすい

「チャットUIを付けただけ」で終わらず、実運用に必要なガードまで含めて組めたのが収穫でした。

まとめ

Chatからの指示でサイトが変わる体験は、見た目以上に設計が重要でした。

特に、

  • 自由入力をどう制約付き操作へ変換するか
  • どこまでをプレビューにし、どこからを本反映にするか
  • Git連携を失敗時含めてどう扱うか

この3点を押さえると、PoCから実運用に近づけやすいです。

同じように「会話を起点にUIを更新するプロダクト」を作る方の参考になればうれしいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?