PluginBench
Skill
Official
Pass
Audit score 90

mcp

vercel-labs/json-render

Build interactive UIs in Claude, ChatGPT, Cursor, and VS Code via MCP servers using json-render.

What is mcp?

MCP Apps integration that serves json-render UIs as interactive applications inside MCP-capable clients. Use this when building MCP servers that need to render dynamic, interactive interfaces or when integrating json-render with the Model Context Protocol.

  • Register a render-ui tool on MCP servers that generates interactive UI specs
  • Serve UI resources as single-file HTML apps bundled with React and json-render renderers
  • Connect client-side React components to MCP servers via postMessage for real-time interaction
  • Support shadcn component definitions and custom component catalogs
  • Enable LLMs to generate valid UI specs using catalog-aware prompts

How to install mcp

npx skills add https://github.com/vercel-labs/json-render --skill mcp
Prerequisites
  • Node.js runtime
  • @json-render/mcp, @json-render/core, and @modelcontextprotocol/sdk packages
  • Vite and vite-plugin-singlefile for bundling the iframe HTML
  • MCP-capable client (Claude Desktop, Cursor, VS Code, or ChatGPT)
Claude Code
Cursor
Windsurf
Cline

How to use mcp

  1. 1.Install dependencies: npm install @json-render/mcp @json-render/core @modelcontextprotocol/sdk
  2. 2.Create a server file that calls createMcpApp() with your catalog and bundled HTML
  3. 3.Build the React iframe app using Vite with vite-plugin-singlefile to generate dist/index.html
  4. 4.Configure your MCP client (.cursor/mcp.json or Claude Desktop config) to run your server
  5. 5.Start the MCP server; the render-ui tool and ui:// resource will be available to the LLM

Use cases

Good for
  • Building an MCP server that renders form-based interfaces for data collection in Claude
  • Creating interactive dashboards in Cursor that update based on LLM-generated specifications
  • Serving a configuration UI as an MCP App accessible from VS Code
  • Integrating json-render with existing MCP servers to add visual output capabilities
  • Developing LLM-driven applications that need rich, interactive frontends
Who it's for
  • MCP server developers
  • Full-stack engineers building AI-integrated tools
  • Teams using Claude, ChatGPT, Cursor, or VS Code with MCP support
  • Developers wanting to add interactive UIs to LLM applications

mcp FAQ

What is the difference between the server and client in this integration?

The server (Node.js) creates an MCP server that registers tools and resources; the client (React in iframe) runs inside the MCP-capable application and renders UI specs by connecting to the server via postMessage.

Do I need to use shadcn components?

No; shadcnComponentDefinitions is provided as a default, but you can define your own component catalog via the catalog option in createMcpApp().

How does the LLM know what UI to generate?

The catalog prompt is automatically included in the render-ui tool description, so the LLM understands the available components and actions.

Can I use this with existing MCP servers?

Yes; use registerJsonRenderTool() and registerJsonRenderResource() to add json-render capabilities to an existing MCP server instead of using createMcpApp().

What clients support this integration?

Claude Desktop, Cursor, VS Code (with MCP support), and ChatGPT (if configured with MCP).

Full instructions (SKILL.md)

Source of truth, from vercel-labs/json-render.


name: mcp description: MCP Apps integration for json-render. Use when building MCP servers that render interactive UIs in Claude, ChatGPT, Cursor, or VS Code, or when integrating json-render with the Model Context Protocol.

@json-render/mcp

MCP Apps integration that serves json-render UIs as interactive MCP Apps inside Claude, ChatGPT, Cursor, VS Code, and other MCP-capable clients.

Quick Start

Server (Node.js)

import { createMcpApp } from "@json-render/mcp";
import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/react/schema";
import { shadcnComponentDefinitions } from "@json-render/shadcn/catalog";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import fs from "node:fs";

const catalog = defineCatalog(schema, {
  components: { ...shadcnComponentDefinitions },
  actions: {},
});

const server = createMcpApp({
  name: "My App",
  version: "1.0.0",
  catalog,
  html: fs.readFileSync("dist/index.html", "utf-8"),
});

await server.connect(new StdioServerTransport());

Client (React, inside iframe)

import { useJsonRenderApp } from "@json-render/mcp/app";
import { JSONUIProvider, Renderer } from "@json-render/react";

function McpAppView({ registry }) {
  const { spec, loading, error } = useJsonRenderApp();
  if (error) return <div>Error: {error.message}</div>;
  if (!spec) return <div>Waiting...</div>;
  return (
    <JSONUIProvider registry={registry} initialState={spec.state ?? {}}>
      <Renderer spec={spec} registry={registry} loading={loading} />
    </JSONUIProvider>
  );
}

Architecture

  1. createMcpApp() creates an McpServer that registers a render-ui tool and a ui:// HTML resource
  2. The tool description includes the catalog prompt so the LLM knows how to generate valid specs
  3. The HTML resource is a Vite-bundled single-file React app with json-render renderers
  4. Inside the iframe, useJsonRenderApp() connects to the host via postMessage and renders specs

Server API

  • createMcpApp(options) - main entry, creates a full MCP server
  • registerJsonRenderTool(server, options) - register a json-render tool on an existing server
  • registerJsonRenderResource(server, options) - register the UI resource

Client API (@json-render/mcp/app)

  • useJsonRenderApp(options?) - React hook, returns { spec, loading, connected, error, callServerTool }
  • buildAppHtml(options) - generate HTML from bundled JS/CSS

Building the iframe HTML

Bundle the React app into a single self-contained HTML file using Vite + vite-plugin-singlefile:

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { viteSingleFile } from "vite-plugin-singlefile";

export default defineConfig({
  plugins: [react(), viteSingleFile()],
  build: { outDir: "dist" },
});

Client Configuration

Cursor (.cursor/mcp.json)

{
  "mcpServers": {
    "my-app": {
      "command": "npx",
      "args": ["tsx", "server.ts", "--stdio"]
    }
  }
}

Claude Desktop

{
  "mcpServers": {
    "my-app": {
      "command": "npx",
      "args": ["tsx", "/path/to/server.ts", "--stdio"]
    }
  }
}

Dependencies

# Server
npm install @json-render/mcp @json-render/core @modelcontextprotocol/sdk

# Client (iframe)
npm install @json-render/react @json-render/shadcn react react-dom

# Build tools
npm install -D vite @vitejs/plugin-react vite-plugin-singlefile