mcp-app-view.tsx 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import { JSONUIProvider, Renderer } from "@json-render/react";
  2. import { shadcnComponents } from "@json-render/shadcn";
  3. import { defineRegistry } from "@json-render/react";
  4. import { useJsonRenderApp } from "@json-render/mcp/app";
  5. import { catalog } from "./catalog";
  6. import { useState, useEffect } from "react";
  7. const { registry } = defineRegistry(catalog, {
  8. components: {
  9. ...shadcnComponents,
  10. },
  11. });
  12. const debugStyle = {
  13. padding: 12,
  14. fontFamily: "monospace",
  15. fontSize: 12,
  16. color: "#000",
  17. background: "#fffbe6",
  18. border: "1px solid #faad14",
  19. borderRadius: 4,
  20. margin: 8,
  21. whiteSpace: "pre-wrap" as const,
  22. wordBreak: "break-all" as const,
  23. };
  24. export function McpAppView() {
  25. const [logs, setLogs] = useState<string[]>(["App mounted"]);
  26. const addLog = (msg: string) => {
  27. setLogs((prev) => [
  28. ...prev,
  29. `${new Date().toISOString().slice(11, 23)} ${msg}`,
  30. ]);
  31. };
  32. const { spec, loading, connected, connecting, error } = useJsonRenderApp({
  33. name: "json-render-mcp-example",
  34. version: "1.0.0",
  35. });
  36. useEffect(() => {
  37. addLog(
  38. `State: connecting=${connecting} connected=${connected} error=${error?.message ?? "none"} loading=${loading} spec=${spec ? "yes" : "null"}`,
  39. );
  40. }, [connecting, connected, error, loading, spec]);
  41. useEffect(() => {
  42. if (spec) {
  43. addLog(
  44. `Spec received: root=${spec.root}, elements=${Object.keys(spec.elements ?? {}).join(",")}`,
  45. );
  46. }
  47. }, [spec]);
  48. if (error) {
  49. return (
  50. <div style={debugStyle}>
  51. <div style={{ color: "#ef4444", fontWeight: "bold" }}>
  52. Connection error: {error.message}
  53. </div>
  54. <div style={{ marginTop: 8 }}>{logs.join("\n")}</div>
  55. </div>
  56. );
  57. }
  58. if (!spec) {
  59. return (
  60. <div style={debugStyle}>
  61. <div>
  62. {connecting
  63. ? "Connecting to host..."
  64. : loading
  65. ? "Waiting for UI spec..."
  66. : "No spec received."}
  67. </div>
  68. <div style={{ marginTop: 8 }}>{logs.join("\n")}</div>
  69. </div>
  70. );
  71. }
  72. return (
  73. <div>
  74. <JSONUIProvider registry={registry} initialState={spec.state ?? {}}>
  75. <Renderer spec={spec} registry={registry} loading={loading} />
  76. </JSONUIProvider>
  77. </div>
  78. );
  79. }