关于 mcp-visual-output
面向开发者的技能包,用于为新建或现有 MCP 服务添加由 JSON 规范驱动的交互式视觉输出。内容涵盖配置、安全沙箱、渐进式渲染和仪表板模式。
主要功能
- 01为新服务配置视觉输出
- 02为现有服务添加渲染工具
- 03配置 iframe 沙箱与 CSP
- 04渐进式流式传输规范
- 05应用仪表板布局模式
适用场景
- 01构建多指标仪表板
- 02呈现五行以上的数据表
- 03展示多个系统的状态
MCP 相关
指导开发者通过 MCP 工具和资源提供 JSON 渲染界面,并使用 `@json-render/mcp`。涵盖 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 | 高 | createMcpApp() 和 registerJsonRenderTool() |
| 安全性 | sandbox-csp.md | 高 | CSP 声明、iframe 沙盒化 |
| 渲染 | streaming-output.md | 中 | 通过 JSON Patch 渐进式渲染 |
| 模式 | dashboard-patterns.md | 中 | 统计网格、状态徽标、数据表 |
共计: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 网格 | 否 |
| 单个数值答案 | 否 | 是 |
| 错误消息 | 否 | 是 |
| 文件内容 / 代码 | 否 | 是 |
常见错误
- MCP 工具返回原始 HTML 字符串,而不是 json-render 规范(会破坏类型安全,且无法流式传输)
- 组件树嵌套过深,无法逐步流式传输(保持扁平)
- 在 CSP 声明中使用
script-src 'unsafe-inline'(存在安全风险,而且没有必要) - 等待完整规范生成后再渲染(违背渐进式渲染的初衷)
- 在单个目录中定义 20 多种组件类型(会增加提示词 Token 开销)
- 在
createMcpApp()配置中缺少htmlbundle(iframe 没有可渲染的内容)
相关技能
ork:mcp-patterns-- MCP 服务构建、传输与安全ork:json-render-catalog-- 完整的组件目录和组合模式ork:multi-surface-render-- 在 Claude、Cursor、ChatGPT 和 Web 中渲染ork:ai-ui-generation-- AI 生成界面的 GenUI 模式