Upgrade to Pro — share decks privately, control downloads, hide ads and more …

実践AIチャットボットUI実装入門

Avatar for syumai syumai
September 21, 2025

 実践AIチャットボットUI実装入門

フロントエンドカンファレンス東京 2025の発表資料です
https://fec-tokyo.connpass.com/event/352581/

Avatar for syumai

syumai

September 21, 2025
Tweet

More Decks by syumai

Other Decks in Programming

Transcript

  1. 自己紹介 syumai ECMAScript 仕様輪読会 / Asakusa.go 主催 株式会社ベースマキナで管理画面のSaaS を開発中 Go

    でGraphQL サーバー (gqlgen) や TypeScript でフロン トエンドを書いています Software Design 2023 年12 月号から2025 年2 月号まで Cloudflare Workers の連載をしました Twitter ( 現𝕏): @__syumai Website: https://syum.ai
  2. 2024/5/15-16 Evan Bacon さんのReact Conf 2024 での発表 2025/4/10 Kent C.

    Dodds さんの「New Content Type for "UI" 」Proposal 2025/5/3 Kent C. Dodds さんの記事「The future of AI interaction: Beyond just text 」 2025/5/12 AG-UI リリースのアナウンス 2025/5/17 MCP UI リリースのアナウンス (MCP 公式ではない)
  3. 2024/5/15-16 Evan Bacon さんのReact Conf 2024 での発表 Expo Router のRSC

    対応についての発表の一環で、AI チャットボットがUI を返すデモを行った https://www.youtube.com/watch?v=djhEgxQf3Kw&t=677s
  4. 2025/4/10 Kent C. Dodds さんの「New Content Type for "UI" 」Proposal

    MCP に生のHTML でUI を返す機能追加の提案を行った https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/1146
  5. 2025/5/3 Kent C. Dodds さんの記事「The future of AI interaction: Beyond

    just text 」 Evan Bacon さんの発表をベースに、AI チャットボットでUI を使う提案を行う記事 https://www.epicai.pro/the-future-of-ai-interaction-beyond-just-text-w22ps
  6. AG-UI のプロトコルが行わないこと エージェントからのUI そのものの返却 MCP UI ( 後述) のように、ツールの呼び出し結果自体が生のHTML にはなったり

    しない あくまで、ユーザー(ブラウザ)とエージェントの間では、メッセージのやり取 りと、状態の同期をするだけ UI の表示方法は完全にフロントエンドに委ねられている →AI チャットボットのフロントエンドが、対応するエージェント向けの 専用の実装を持つ必要がある
  7. UI はただのMCP のResource UI は、独自の ui:// scheme のURL で始まるMCP のResource

    として表現され、 Tool の呼び出し結果として返される 例: ui://my-custom-form/instance-01 Resource の mimeType に応じて、 レンダリング方法が変わる mimeType: 'text/html' → HTML の中身をそのままiframe に表示 mimeType: 'text/uri-list' → URL の示す先をiframe に表示 MCP のResource は、元々Tool の結果として返せるので、仕様に反する部分がなくシ ンプル MCP のHost が、 ui:// Resource のレンダリング方法を知ってさえいればいい
  8. UI はiframe にレンダリングされる UI は、iframe 内にレンダリングされるため、直接AI チャットボット (MCP Host) のア

    プリケーションのWindow object に触れられないので安全 通信はpostMessage で行う iframe 内にレンダリングされるコンポーネントと、MCP UI のホストとの postMessage ベースの通信プロトコルが定義されている ツール呼び出し以外に、プロンプトを入力したり、URL を渡してリンクを開くよ うHost に依頼したりもできる
  9. UI 側からのツール呼び出しの例 window.parent.postMessage( { type: "tool", payload: { toolName: "get-weather",

    params: { city: "Tokyo", }, }, }, "*" ); https://mcpui.dev/guide/embeddable-ui#tool
  10. AG-UI とMCP UI の比較 汎用性 基本的にMCP UI の方が上。 MCP UI

    のResource をレンダリングできるクライアントならどこでも使える AG-UI は、専用のフロントエンド実装が必要 MCP 非依存という観点ではAG-UI の方が上。 エージェントの使用するツールが、MCP のTool として実装されるとは限らな い
  11. AG-UI とMCP UI の比較 ベンダー依存度 AG-UI の方が、ベンダー依存度が高く見える。 AG-UI のプロトコル自体がCopilotKit 発で、他に主要な実装が特に無さそう

    プロトコルの複雑性もこちらの方が高いので、この状況は続きそう 一方、MCP UI は、Postman など対応するクライアント実装が数多く存在し ている
  12. 「天気情報取得ツール」のUI のレンダリング エージェント側 結果のスキーマを定義 export type WeatherToolResult = z.infer<typeof WeatherToolResultSchema>;

    const WeatherToolResultSchema = z.object({ temperature: z.number(), feelsLike: z.number(), humidity: z.number(), windSpeed: z.number(), windGust: z.number(), conditions: z.string(), location: z.string(), }); https://github.com/CopilotKit/with-mastra/blob/main/src/mastra/tools/index.ts
  13. 「天気情報取得ツール」のUI のレンダリング エージェント側 先ほどのスキーマをoutputSchema に設定して、tool を宣言 export const weatherTool =

    createTool({ id: 'get-weather', description: 'Get current weather for a location', inputSchema: z.object({ location: z.string().describe('City name'), }), outputSchema: WeatherToolResultSchema, execute: async ({ context }) => { // ツールの内容は省略 return await getWeather(context.location); }, }); https://github.com/CopilotKit/with-mastra/blob/main/src/mastra/tools/index.ts
  14. 「天気情報取得ツール」のUI のレンダリング エージェント側 tool をエージェントに設定して公開 ( 普通のMastra のtool となんら変わらない) export

    const weatherAgent = new Agent({ name: "Weather Agent", tools: { weatherTool }, model: openai("gpt-4o"), instructions: "You are a helpful assistant.", // ... }); https://github.com/CopilotKit/with-mastra/blob/main/src/mastra/agents/index.ts
  15. 「天気情報取得ツール」のUI のレンダリング クライアント側 React で、天気情報の表示コンポーネントを実装 function WeatherCard({ result, location, status

    }: { // toolのoutputSchemaの型がそのまま使える! result: WeatherToolResult, location?: string, status: "inProgress" | "executing" | "complete" }) { // ... https://github.com/CopilotKit/with-mastra/blob/main/src/app/page.tsx
  16. 「天気情報取得ツール」のUI のレンダリング クライアント側 weatherTool の呼び出しに合わせて WeatherCard コンポーネントをレンダリングするこ とを useCopilotAction hook

    呼び出しで指定 import { useCopilotAction } from "@copilotkit/react-core"; // Pageのコンポーネント内 useCopilotAction({ name: "weatherTool", description: "Get the weather for a given location.", available: "frontend", parameters: [{ name: "location", type: "string", required: true }], // WeatherCardのコンポーネントを返す render: ({ args, result, status }) => <WeatherCard result={result} location={args.location} status={status} /> }); https://github.com/CopilotKit/with-mastra/blob/main/src/app/page.tsx
  17. 「天気情報取得ツール」のUI のレンダリング クライアント側 チャット内容は CopilotSidebar コンポーネントに表示される import { CopilotSidebar }

    from "@copilotkit/react-ui"; export default function CopilotKitPage() { return ( <main> <YourMainContent /> <CopilotSidebar // ... /> </main> ); } https://github.com/CopilotKit/with-mastra/blob/main/src/app/page.tsx
  18. MCP UI の実装 Tool の実装 (generateSyumai) 最後に呼ぶ、 generateSyumai tool を用意しておきます

    this.server.tool("generateSyumai", "Generate a syumai avatar image with the specified color code.", { colorCode: z.string().length(6) }, async ({ colorCode }) => ({ content: [{ type: "text", text: `{ "imageUrl": "https://syum.ai/image?code=${colorCode}"}` }] }));
  19. MCP UI の実装 コンポーネントの実装 カラーピッカーのHTML を実装 (Claude に書いてもらいました) <div class="color-selector">

    <h2>色を選択してください</h2> <div class="button-container"> <button class="color-button red" data-color="red" data-color-name="赤"> <span class="color-name">赤</span> </button> <!-- ... --> </div> <div class="selected-color" id="selectedColor" style="display: none;"> <div class="color-display" id="colorDisplay"></div> <span id="colorText">選択された色: </span> </div> </div>
  20. MCP UI の実装 コンポーネントの実装 onClick でMCP Host にpostMessage して、 generateSyumai

    を呼ぶようにする document.querySelectorAll('.color-button').forEach(button => { button.addEventListener('click', () => { // ... const message = { type: 'tool', payload: { toolName: 'generateSyumai', params: { colorCode: colorData.hex, } } }; window.parent.postMessage(message, '*');
  21. MCP UI の実装 Tool の実装 (showSyumaiColorPicker) Tool から、コンポーネントのResource を返すようにする //

    生のHTMLを文字列でexportしている import { colorpicker } from "./colorpicker"; import { createUIResource } from "@mcp-ui/server"; this.server.tool( "showSyumaiColorPicker", {}, () => { // `createUIResource` でMCP UIのリソースを生成 const resourceBlock = createUIResource({ uri: "ui://server-generated/syumaiColorPicker", content: { type: "rawHtml", htmlString: colorpicker }, encoding: "text", }) return { content: [resourceBlock] } },
  22. まとめ AI チャットボットでは、テキストではなく、専用のUI をレンダリングする方が適切な ことがある AG-UI (CopilotKit) / MCP UI

    は、それぞれ大きく出来ることが異なる AG-UI アプリケーション全体を制御したいならこちら MCP UI ツール呼び出しの結果の表示だけ制御したいならこちら MCP Host の対応も増えていて、より広く使える可能性がある