mcp-visual-output について
新規または既存の MCP サーバーに、JSON仕様を使ったインタラクティブなビジュアル出力を追加するスキルです。セットアップ、サンドボックスのセキュリティ、段階的なレンダリング、ダッシュボードのパターンを扱います。
主な機能
- 01新規サーバーのビジュアル出力設定
- 02既存サーバーへのレンダリングツール追加
- 03iframeサンドボックスとCSPの設定
- 04仕様の段階的なストリーミング
- 05ダッシュボードレイアウトの適用
活用シーン
- 01複数指標のダッシュボード作成
- 025行以上のデータテーブル表示
- 03複数システムの状態表示
MCP 対応
`@json-render/mcp`を使い、MCPツールとリソースを通じてJSONレンダリングのUIを提供する方法を案内します。stdioとStreamable HTTPのトランスポートを扱います。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ yonatangross/ orchestkit --skill mcp-visual-outputインストール後、Claude Code で/mcp-visual-outputを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
test-cases.jsonreferences/component-recipes.mdmcp-integration.mdupstream-mcp.mdrules/_sections.md_template.mddashboard-patterns.mdmcp-app-setup.mdsandbox-csp.mdstreaming-output.md詳細
上流バージョンの参照先:@json-render/mcp 0.21.0(2026-09-30)。
MCP ビジュアル出力
MCP ツールのプレーンな応答を、AI の会話内に表示されるインタラクティブなダッシュボードにアップグレードします。@json-render/mcp を基盤としており、json-render の仕様システムと MCP のツール/リソースモデルを橋渡しします。AI が型付き JSON 仕様を生成し、サンドボックス化された iframe がそれをインタラクティブな UI としてレンダリングします。
MCP サーバーをゼロから構築していますか? サーバーのセットアップ、トランスポート、セキュリティには
ork:mcp-patternsを使用してください。このスキルでは、サーバーの起動後のビジュアル出力レイヤーに焦点を当てます。コンポーネントカタログ全体が必要ですか? 利用できるすべてのコンポーネント、プロパティ、合成パターンについては、
ork:json-render-catalogを参照してください。
デシジョンツリー ― 読むファイルの選択
What are you doing?
|
+-- Setting up visual output for the first time
| +-- New MCP server -----------> rules/mcp-app-setup.md
| +-- Existing MCP server ------> rules/mcp-app-setup.md (registerJsonRenderTool section)
|
+-- Configuring security / sandbox
| +-- CSP declarations ----------> rules/sandbox-csp.md
| +-- Iframe permissions --------> rules/sandbox-csp.md
|
+-- Rendering strategy
| +-- Progressive streaming -----> rules/streaming-output.md
| +-- Dashboard layouts ----------> rules/dashboard-patterns.md
|
+-- API reference
| +-- Server-side API -----------> references/mcp-integration.md
| +-- Component recipes ----------> references/component-recipes.md
クイックリファレンス
| カテゴリー | ルール | 影響度 | 主要パターン |
|---|---|---|---|
| セットアップ | mcp-app-setup.md | HIGH | createMcpApp() と registerJsonRenderTool() |
| セキュリティ | sandbox-csp.md | HIGH | CSP 宣言、iframe のサンドボックス化 |
| レンダリング | streaming-output.md | MEDIUM | JSON Patch による段階的なレンダリング |
| パターン | dashboard-patterns.md | MEDIUM | 統計グリッド、ステータスバッジ、データテーブル |
合計:3 カテゴリーにわたる 4 つのルール
動作の仕組み
- カタログを定義する --
defineCatalog()と Zod を使って型付きコンポーネントスキーマを作成します - MCP に登録する -- 新しいサーバーでは
createMcpApp()、既存のサーバーではregisterJsonRenderTool()を使用します - AI が仕様を生成する -- モデルがカタログに準拠した JSON 仕様を生成します
- iframe がレンダリングする -- サンドボックス化された iframe 内のバンドル済み React アプリが、
useJsonRenderApp()と<Renderer />を使って仕様をレンダリングします
AI が HTML や CSS を書くことはありません。カタログのコンポーネントを型で参照する、構造化された JSON 仕様を生成します。iframe アプリは、事前に構築されたレジストリを使ってそれらのコンポーネントをレンダリングします。
クイックスタート ― 新しい MCP サーバー
import { createMcpApp } from '@json-render/mcp'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { buildAppHtml } from '@json-render/mcp/app'
import { catalog } from './catalog'
// Generate the iframe HTML from the bundled JS/CSS (docs-prescribed generator).
const bundledHtml = buildAppHtml({ entry: './app.tsx' })
// 1. Create the MCP app (async; returns an McpServer, no .start()/.close()).
// name + version are required; tool config nests under `tool`
// (default tool name is 'render-ui'). There is no top-level `csp`.
const server = await createMcpApp({
name: 'my-app',
version: '1.0.0',
catalog, // component schemas the AI can use
html: bundledHtml, // pre-built iframe app (single HTML file)
tool: {
name: 'render-dashboard',
description: 'Render an interactive dashboard from a json-render spec',
},
})
// 2. Connect a transport -- stdio, Streamable HTTP, or any MCP transport
await server.connect(new StdioServerTransport())
クイックスタート ― 既存のサーバーにビジュアル出力を追加する
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { registerJsonRenderTool, registerJsonRenderResource } from '@json-render/mcp'
import { buildAppHtml } from '@json-render/mcp/app'
import { catalog } from './catalog'
const server = new McpServer({ name: 'my-server', version: '1.0.0' })
// Generate the iframe HTML from the bundled JS/CSS (docs-prescribed generator).
const bundledHtml = buildAppHtml({ entry: './app.tsx' })
const resourceUri = 'ui://my-server/dashboard'
// Register the render tool (lets the model return specs).
// name, title, description, and resourceUri are all required.
registerJsonRenderTool(server, {
catalog,
name: 'render-dashboard',
title: 'Render Dashboard',
description: 'Render an interactive dashboard from a json-render spec',
resourceUri,
})
// Serve the bundled HTML iframe app as a resource (new in 0.15).
// resourceUri must match the tool's resourceUri.
registerJsonRenderResource(server, { resourceUri, html: bundledHtml })
registerJsonRenderResource() は 0.15 で追加され、ツールの登録とUI リソースの提供を分離できるようになりました。ホストがバンドル済み HTML をキャッシュする場合に便利です(クライアント:Claude、ChatGPT、Cursor、VS Code Copilot、Goose、Postman)。stdio と Streamable HTTP(Express)の両方のトランスポートに対応しています。このスキルは @json-render/mcp 0.20.0 に基づいて検証されています。このバージョンではコード変更は一切なく、公開されたすべてのファイルは、バージョンと固定された @json-render/core の依存関係を除き、0.19.0 とバイト単位で同一です。そのため、このリリースの新機能はこのパッケージではなく、core と react に属します。MCP がレンダリングする iframe に間接的に届くものとしては、名前付きスロットとネストされた繰り返しに加え、名前付きの onSuccess/onError 連鎖アクションが設定済みの params を実際に受け取るようになった修正があります。
クライアント側の iframe アプリ
iframe アプリは MCP ホストから仕様を受け取り、レンダリングします。
import { useJsonRenderApp } from '@json-render/mcp/app'
import { Renderer } from '@json-render/react'
import { registry } from './registry'
function App() {
const { spec, loading } = useJsonRenderApp()
if (loading) return <Skeleton />
return <Renderer spec={spec} registry={registry} />
}
カタログの定義
カタログでは、AI が使用できるコンポーネントを定義します。各コンポーネントには、Zod による型付きのプロパティがあります。
import { defineCatalog } from '@json-render/core'
import { schema } from '@json-render/react/schema'
import { z } from 'zod'
export const dashboardCatalog = defineCatalog(schema, {
components: {
StatGrid: {
props: z.object({
items: z.array(z.object({
label: z.string(),
value: z.string(),
trend: z.enum(['up', 'down', 'flat']).optional(),
color: z.enum(['green', 'red', 'yellow', 'blue']).optional(),
})),
}),
children: false,
},
StatusBadge: {
props: z.object({
label: z.string(),
status: z.enum(['success', 'warning', 'error', 'info', 'pending']),
}),
children: false,
},
DataTable: {
props: z.object({
columns: z.array(z.object({ key: z.string(), label: z.string() })),
rows: z.array(z.record(z.string())),
}),
children: false,
},
},
})
例:評価結果のダッシュボード
AI は次のような仕様を生成します。要素マップはフラットで、ネストは最大 2 階層です。
{
"root": "dashboard",
"elements": {
"dashboard": {
"type": "Card",
"props": { "title": "Eval Results -- v7.21.1" },
"children": ["stats", "table"]
},
"stats": {
"type": "StatGrid",
"props": {
"items": [
{ "label": "Skills Evaluated", "value": "94", "trend": "flat" },
{ "label": "Pass Rate", "value": "97.8%", "trend": "up", "color": "green" },
{ "label": "Avg Score", "value": "8.2/10", "trend": "up" }
]
}
},
"table": {
"type": "DataTable",
"props": {
"columns": [
{ "key": "skill", "label": "Skill" },
{ "key": "score", "label": "Score" },
{ "key": "status", "label": "Status" }
],
"rows": [
{ "skill": "implement", "score": "9.1", "status": "pass" },
{ "skill": "verify", "score": "8.7", "status": "pass" }
]
}
}
}
}
主な判断事項
| 判断事項 | 推奨 |
|---|---|
| 新規サーバーか既存サーバーか | 新規には createMcpApp()、既存への追加には registerJsonRenderTool() |
| CSP ポリシー | 最小限にし、実際に必要なドメインだけを宣言します |
| ストリーミング | 常に段階的なレンダリングを有効にします。仕様全体が揃うまで待たないでください |
| ダッシュボードの階層 | ストリーミングしやすいよう、要素ツリーはフラットに保ちます(最大 2~3 階層) |
| コンポーネント数 | ほとんどのダッシュボードでは、カタログあたり 3~5 種類のコンポーネントで十分です |
| ビジュアルかテキストか | 複数の指標を表示する場合はビジュアル出力を、単一の値にはプレーンテキストを使用します |
CC 2.1.113 で MCP の同時呼び出しのタイムアウト処理が修正されました。ハングしたツール呼び出しはキューをブロックせず、正常にエラーになります。ダッシュボードからのツールの並列呼び出しがより安全になり、回避策は不要です。
ビジュアル出力とプレーンテキストの使い分け
| シナリオ | ビジュアル出力を使用 | プレーンテキストを使用 |
|---|---|---|
| 複数の指標をひと目で確認する | はい -- StatGrid | いいえ |
| 表形式のデータ(5 行以上) | はい -- DataTable | いいえ |
| 複数のシステムのステータス | はい -- StatusBadge グリッド | いいえ |
| 単一の値を答える | いいえ | はい |
| エラーメッセージ | いいえ | はい |
| ファイルの内容/コード | いいえ | はい |
よくある間違い
- json-render の仕様ではなく、MCP ツールから生の HTML 文字列を返す(型安全性が損なわれ、ストリーミングできません)
- 段階的にストリーミングできないほど深くネストされたコンポーネントツリーを作成する(フラットに保ちます)
- CSP 宣言で
script-src 'unsafe-inline'を使用する(セキュリティリスクがあり、不要です) - レンダリング前に仕様全体が揃うのを待つ(段階的なレンダリングの利点が失われます)
- 1 つのカタログで 20 種類を超えるコンポーネントタイプを定義する(プロンプトのトークンコストが増加します)
createMcpApp()の設定にhtmlバンドルがない(iframe にレンダリングするものがありません)
関連するスキル
ork:mcp-patterns-- MCP サーバーの構築、トランスポート、セキュリティork:json-render-catalog-- コンポーネントカタログと合成パターンの全容ork:multi-surface-render-- Claude、Cursor、ChatGPT、ウェブにわたるレンダリングork:ai-ui-generation-- AI 生成インターフェースのための GenUI パターン