Agent skill
mcp-visual-output
Interactive MCP visual output via @json-render/mcp. Upgrade plain JSON tool responses to interactive dashboards rendered in sandboxed iframes inside Claude, Cursor, and ChatGPT conversations. Covers createMcpApp(), registerJsonRenderTool(), CSP config, streaming, and dashboard component patterns. Use when building MCP servers that return visual output, upgrading existing MCP tools with interactive UI, or creating eval/monitoring dashboards.
Install this agent skill to your Project
npx add-skill https://github.com/yonatangross/orchestkit/tree/main/plugins/ork/skills/mcp-visual-output
Metadata
Additional technical details for this skill
- category
- mcp
- upstream package
- @json-render/mcp
- upstream version tested
- 0.13.0
SKILL.md
MCP Visual Output
Upgrade plain MCP tool responses to interactive dashboards rendered inside AI conversations. Built on @json-render/mcp, which bridges the json-render spec system with MCP's tool/resource model -- the AI generates a typed JSON spec, and a sandboxed iframe renders it as an interactive UI.
Building an MCP server from scratch? Use
ork:mcp-patternsfor server setup, transport, and security. This skill focuses on the visual output layer after your server is running.Need the full component catalog? See
ork:json-render-catalogfor all available components, props, and composition patterns.
Decision Tree -- Which File to Read
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
Quick Reference
| Category | Rule | Impact | Key Pattern |
|---|---|---|---|
| Setup | mcp-app-setup.md |
HIGH | createMcpApp() and registerJsonRenderTool() |
| Security | sandbox-csp.md |
HIGH | CSP declarations, iframe sandboxing |
| Rendering | streaming-output.md |
MEDIUM | Progressive rendering via JSON Patch |
| Patterns | dashboard-patterns.md |
MEDIUM | Stat grids, status badges, data tables |
Total: 4 rules across 3 categories
How It Works
- Define a catalog -- typed component schemas using
defineCatalog()+ Zod - Register with MCP --
createMcpApp()for new servers orregisterJsonRenderTool()for existing ones - AI generates specs -- the model produces a JSON spec conforming to the catalog
- Iframe renders it -- a bundled React app inside a sandboxed iframe renders the spec with
useJsonRenderApp()+<Renderer />
The AI never writes HTML or CSS. It produces a structured JSON spec that references catalog components by type. The iframe app renders those components using a pre-built registry.
Quick Start -- New MCP Server
import { createMcpApp } from '@json-render/mcp'
import { catalog } from './catalog'
import bundledHtml from './app.html'
// 1. Create the MCP app (wraps McpServer + registers the render tool)
const app = createMcpApp({
catalog, // component schemas the AI can use
html: bundledHtml, // pre-built iframe app (single HTML file)
})
// 2. Start -- works with stdio, Streamable HTTP, or any MCP transport
app.start()
Quick Start -- Enhance Existing Server with Visual Output
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { registerJsonRenderTool } from '@json-render/mcp'
import { catalog } from './catalog'
import bundledHtml from './app.html'
const server = new McpServer({ name: 'my-server', version: '1.0.0' })
// Add visual output capability alongside existing tools
registerJsonRenderTool(server, {
catalog,
html: bundledHtml,
})
Client-Side Iframe App
The iframe app receives specs from the MCP host and renders them:
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} />
}
Catalog Definition
Catalogs define what components the AI can use. Each component has typed props via Zod:
import { defineCatalog } from '@json-render/core'
import { z } from 'zod'
export const dashboardCatalog = defineCatalog({
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,
},
})
Example: Eval Results Dashboard
The AI generates a spec like this -- flat element map, no nesting beyond 2 levels:
{
"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" }
]
}
}
}
}
Key Decisions
| Decision | Recommendation |
|---|---|
| New vs existing server | createMcpApp() for new; registerJsonRenderTool() to add to existing |
| CSP policy | Minimal -- only declare domains you actually need |
| Streaming | Always enable progressive rendering; never wait for full spec |
| Dashboard depth | Keep element trees flat (2-3 levels max) for streamability |
| Component count | 3-5 component types per catalog covers most dashboards |
| Visual vs text | Use visual output for multi-metric views; plain text for single values |
When to Use Visual Output vs Plain Text
| Scenario | Use Visual Output | Use Plain Text |
|---|---|---|
| Multiple metrics at a glance | Yes -- StatGrid | No |
| Tabular data (5+ rows) | Yes -- DataTable | No |
| Status of multiple systems | Yes -- StatusBadge grid | No |
| Single value answer | No | Yes |
| Error message | No | Yes |
| File content / code | No | Yes |
Common Mistakes
- Returning raw HTML strings from MCP tools instead of json-render specs (breaks type safety, no streaming)
- Deeply nested component trees that cannot stream progressively (keep flat)
- Using
script-src 'unsafe-inline'in CSP declarations (security risk, unnecessary) - Waiting for the full spec before rendering (defeats progressive rendering)
- Defining 20+ component types in a single catalog (increases prompt token cost)
- Missing
htmlbundle increateMcpApp()config (iframe has nothing to render)
Related Skills
ork:mcp-patterns-- MCP server building, transport, securityork:json-render-catalog-- Full component catalog and composition patternsork:multi-surface-render-- Rendering across Claude, Cursor, ChatGPT, webork:ai-ui-generation-- GenUI patterns for AI-generated interfaces
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
expect
Diff-aware AI browser testing — analyzes git changes, generates targeted test plans, and executes them via agent-browser. Reads git diff to determine what changed, maps changes to affected pages via route map, generates a test plan scoped to the diff, and runs it with pass/fail reporting. Use when testing UI changes, verifying PRs before merge, running regression checks on changed components, or validating that recent code changes don't break the user-facing experience.
github-operations
GitHub CLI operations for issues, PRs, milestones, and Projects v2. Covers gh commands, REST API patterns, and automation scripts. Use when managing GitHub issues, PRs, milestones, or Projects with gh.
chain-patterns
Chain patterns for CC 2.1.71 pipelines — MCP detection, handoff files, checkpoint-resume, worktree agents, CronCreate monitoring. Use when building multi-phase pipeline skills. Loaded via skills: field by pipeline skills (fix-issue, implement, brainstorm, verify). Not user-invocable.
storybook-mcp-integration
Storybook MCP server integration for component-aware AI development. Covers 6 tools across 3 toolsets (dev, docs, testing): component discovery via list-all-documentation/get-documentation, story previews via preview-stories, and automated testing via run-story-tests. Use when generating components that should reuse existing Storybook components, running component tests via MCP, or previewing stories in chat.
component-search
Search 21st.dev component registry for production-ready React components. Finds components by natural language description, filters by framework and style system, returns ranked results with install instructions. Use when looking for UI components, finding alternatives to existing components, or sourcing design system building blocks.
ai-ui-generation
AI-assisted UI generation patterns for json-render, v0, Bolt, and Cursor workflows. Covers prompt engineering for component generation, review checklists for AI-generated code, design token injection, refactoring for design system conformance, and CI gates for quality assurance. Use when generating UI components with AI tools, rendering multi-surface MCP visual output, reviewing AI-generated code, or integrating AI output into design systems.
Didn't find tool you were looking for?