page.mdx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. import { pageMetadata } from "@/lib/page-metadata"
  2. export const metadata = pageMetadata("docs/api/mcp")
  3. # @json-render/mcp
  4. MCP Apps integration for json-render. Serve json-render UIs as interactive [MCP Apps](https://modelcontextprotocol.io/docs/extensions/apps) inside Claude, ChatGPT, Cursor, VS Code, and other MCP-capable clients.
  5. ## Install
  6. ```bash
  7. npm install @json-render/mcp @json-render/core @modelcontextprotocol/sdk
  8. ```
  9. For the iframe-side React UI, also install:
  10. ```bash
  11. npm install @json-render/react react react-dom
  12. ```
  13. See the [MCP example](https://github.com/vercel-labs/json-render/tree/main/examples/mcp) for a full working example.
  14. ## Overview
  15. MCP Apps let MCP servers return interactive HTML UIs that render directly inside chat conversations. `@json-render/mcp` bridges json-render catalogs with the MCP Apps protocol:
  16. 1. Your **catalog** defines which components and actions the AI can use
  17. 2. The **MCP server** exposes the catalog as a tool with the spec schema
  18. 3. The **bundled HTML** renders json-render specs inside the host's sandboxed iframe
  19. 4. The AI generates a spec, the host renders it, and users interact with the live UI
  20. ## Server API
  21. ### createMcpApp
  22. Create a fully-configured MCP server. This is the main entry point.
  23. ```typescript
  24. import { createMcpApp } from "@json-render/mcp";
  25. import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
  26. import fs from "node:fs";
  27. const server = createMcpApp({
  28. name: "My Dashboard",
  29. version: "1.0.0",
  30. catalog: myCatalog,
  31. html: fs.readFileSync("dist/index.html", "utf-8"),
  32. });
  33. await server.connect(new StdioServerTransport());
  34. ```
  35. #### CreateMcpAppOptions
  36. <table>
  37. <thead>
  38. <tr>
  39. <th>Option</th>
  40. <th>Type</th>
  41. <th>Description</th>
  42. </tr>
  43. </thead>
  44. <tbody>
  45. <tr>
  46. <td><code>name</code></td>
  47. <td><code>string</code></td>
  48. <td>Server name shown in client UIs</td>
  49. </tr>
  50. <tr>
  51. <td><code>version</code></td>
  52. <td><code>string</code></td>
  53. <td>Server version</td>
  54. </tr>
  55. <tr>
  56. <td><code>catalog</code></td>
  57. <td><code>Catalog</code></td>
  58. <td>json-render catalog defining available components</td>
  59. </tr>
  60. <tr>
  61. <td><code>html</code></td>
  62. <td><code>string</code></td>
  63. <td>Self-contained HTML for the iframe UI</td>
  64. </tr>
  65. <tr>
  66. <td><code>tool</code></td>
  67. <td><code>McpToolOptions</code></td>
  68. <td>Optional tool name/title/description overrides</td>
  69. </tr>
  70. </tbody>
  71. </table>
  72. ### registerJsonRenderTool
  73. Register a json-render tool on an existing `McpServer`. Use this when you need to add json-render to a server that has other tools.
  74. ```typescript
  75. import { registerJsonRenderTool } from "@json-render/mcp";
  76. registerJsonRenderTool(server, {
  77. catalog,
  78. name: "render-ui",
  79. title: "Render UI",
  80. description: "Render an interactive UI",
  81. resourceUri: "ui://render-ui/view.html",
  82. });
  83. ```
  84. ### registerJsonRenderResource
  85. Register the UI resource that serves the bundled HTML.
  86. ```typescript
  87. import { registerJsonRenderResource } from "@json-render/mcp";
  88. registerJsonRenderResource(server, {
  89. resourceUri: "ui://render-ui/view.html",
  90. html: bundledHtml,
  91. });
  92. ```
  93. ## Client API (`@json-render/mcp/app`)
  94. These exports run inside the sandboxed iframe rendered by the MCP host.
  95. ### useJsonRenderApp
  96. React hook that connects to the MCP host, listens for tool results, and maintains the current json-render spec.
  97. ```tsx
  98. import { useJsonRenderApp } from "@json-render/mcp/app";
  99. import { JSONUIProvider, Renderer } from "@json-render/react";
  100. function McpAppView({ registry }) {
  101. const { spec, loading, connected, error } = useJsonRenderApp({
  102. name: "my-app",
  103. version: "1.0.0",
  104. });
  105. if (error) return <div>Error: {error.message}</div>;
  106. if (!spec) return <div>Waiting...</div>;
  107. return (
  108. <JSONUIProvider registry={registry} initialState={spec.state ?? {}}>
  109. <Renderer spec={spec} registry={registry} loading={loading} />
  110. </JSONUIProvider>
  111. );
  112. }
  113. ```
  114. #### UseJsonRenderAppReturn
  115. <table>
  116. <thead>
  117. <tr>
  118. <th>Field</th>
  119. <th>Type</th>
  120. <th>Description</th>
  121. </tr>
  122. </thead>
  123. <tbody>
  124. <tr>
  125. <td><code>spec</code></td>
  126. <td><code>{'Spec | null'}</code></td>
  127. <td>Current json-render spec</td>
  128. </tr>
  129. <tr>
  130. <td><code>loading</code></td>
  131. <td><code>boolean</code></td>
  132. <td>Whether the spec is still being received</td>
  133. </tr>
  134. <tr>
  135. <td><code>connected</code></td>
  136. <td><code>boolean</code></td>
  137. <td>Whether connected to the host</td>
  138. </tr>
  139. <tr>
  140. <td><code>connecting</code></td>
  141. <td><code>boolean</code></td>
  142. <td>Whether currently connecting</td>
  143. </tr>
  144. <tr>
  145. <td><code>error</code></td>
  146. <td><code>{'Error | null'}</code></td>
  147. <td>Connection error, if any</td>
  148. </tr>
  149. <tr>
  150. <td><code>app</code></td>
  151. <td><code>{'App | null'}</code></td>
  152. <td>The underlying MCP App instance</td>
  153. </tr>
  154. <tr>
  155. <td><code>callServerTool</code></td>
  156. <td><code>{'(name, args?) => Promise<void>'}</code></td>
  157. <td>Call an MCP server tool and update spec from result</td>
  158. </tr>
  159. </tbody>
  160. </table>
  161. ### buildAppHtml
  162. Generate a self-contained HTML page from bundled JavaScript and CSS.
  163. ```typescript
  164. import { buildAppHtml } from "@json-render/mcp/app";
  165. import fs from "node:fs";
  166. const html = buildAppHtml({
  167. title: "Dashboard",
  168. js: fs.readFileSync("dist/app.js", "utf-8"),
  169. css: fs.readFileSync("dist/app.css", "utf-8"),
  170. });
  171. ```
  172. ## Client Configuration
  173. ### Cursor
  174. Add to `.cursor/mcp.json`:
  175. ```json
  176. {
  177. "mcpServers": {
  178. "json-render": {
  179. "command": "npx",
  180. "args": ["tsx", "path/to/server.ts", "--stdio"]
  181. }
  182. }
  183. }
  184. ```
  185. ### Claude Desktop
  186. Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
  187. ```json
  188. {
  189. "mcpServers": {
  190. "json-render": {
  191. "command": "npx",
  192. "args": ["tsx", "/absolute/path/to/server.ts", "--stdio"]
  193. }
  194. }
  195. }
  196. ```
  197. ## Supported Clients
  198. MCP Apps are supported by Claude (web and desktop), ChatGPT, VS Code (GitHub Copilot), Cursor, Goose, and Postman.