Skip to main content
Every Interactive Tool in an MCP App is written once in BindJS and compiles to three rendering targets:
  • React in MCP hosts (Claude Desktop, ChatGPT, VS Code, Cursor) via @metabindai/bindjs-react, inside a sandboxed iframe.
  • SwiftUI on iOS, macOS, and visionOS via the BindJS library from bindjs-apple, when embedded in your own app via the Assistant SDK.
  • Jetpack Compose on Android via bindjs-android, when embedded via the Assistant SDK.
The same component definition reaches every surface. Same governance, same brand, same behavior. The renderer changes; the component does not.
A single BindJS layout component renders as SwiftUI on iOS via bindjs-apple, as Jetpack Compose on Android via bindjs-android, and as React on the web via @metabindai/bindjs-react.

Why this works

BindJS is a declarative, SwiftUI-inspired component language. A component author writes layout, behavior, and styling using primitives like VStack, HStack, Text, Image, frame, padding, and foregroundStyle. These primitives have a well-defined semantic meaning, and each renderer maps them to the platform’s native equivalent: Because each renderer targets the platform’s own UI toolkit, the mobile output isn’t a web view in disguise — it’s real SwiftUI and real Jetpack Compose, with 60 FPS scrolling, native gestures, and platform conventions. On the web, the output is React components in the DOM.

Two rendering paths

A single BindJS component compiles to one bundle and reaches two paths: MCP hosts (sandboxed iframe + @metabindai/bindjs-react) and Assistant SDK (SwiftUI / Compose / React inside your app).
Both paths receive the same compiled bundle from the Metabind server. The difference is what’s on the other side of the renderer interface.

What’s compiled and what’s runtime

Components are compiled to a portable BindJS bundle on the server when a Type is published or when a tool call resolves. The bundle is a content-addressed package containing:
  • The compiled body function for each component.
  • Asset references resolved to CDN URLs.
  • Dependency packages (other projects’ components your project imports).
The bundle is delivered to the renderer, which executes the body function with the validated input. Rendering happens in the renderer’s process — there is no JavaScript executing on the host MCP server during a render. For Data Tools, the equivalent compilation produces a JavaScript bundle that runs in a V8 sandbox on the Metabind server (not in the renderer). See Tools and Types.

What’s available and where

Every rendering target is open source under Apache 2.0. The BindJS runtime and React renderer — @metabindai/bindjs-runtime and @metabindai/bindjs-react, from the bindjs-runtime repo — power what Claude, ChatGPT, and every other MCP host show your users. The SwiftUI engine (bindjs-apple, covering iOS, macOS, and visionOS) and the Jetpack Compose engine (bindjs-android) render the same components when embedded in your own app via the Assistant SDK. Your tool definitions, schemas, and components are exportable; the protocol path on the wire is open MCP. The hosted platform — MCP App Studio, the hosted MCP App Server, and the agent proxy — is the commercial product.

Performance characteristics

  • Edge-cached bundles. Compiled component bundles are content-addressed by hash and pushed to global CDN edges. The first request to a render path is one round trip; subsequent requests hit the cache.
  • No cold starts on the render path. The renderer is preloaded in the host or SDK; rendering a tool result is bundle parse + body execution.
  • Native gestures and animations. On iOS and Android, rendering is platform-native, so scroll velocity, gesture recognition, and animation timing match the rest of the embedding app.
  • Rendering logic lives in the app binary. Only tool specifications (data) are delivered over the network. The renderer is signed and bundled with your app at build time; the network surface is data, not executable layout code.

When the rendering target matters for the component author

Most BindJS components compile cleanly across all three targets without special-casing. There are a few areas where the renderer’s capabilities differ:
  • Custom drawing. Canvas-based components, WebGL, or Shader components have a primary target and may render as a static fallback on others.
  • Platform-specific gestures. A SwiftUI-only gesture pattern can be expressed in BindJS, but it’ll behave differently on Compose and React.
  • 3D models. USDZ on iOS, GLB on Android and web. The platform picks the right format from the asset’s model references.
Where target-specific behavior matters, BindJS provides surfaces for declaring it; otherwise the platform handles the mapping.

Components and Packages

The unit that gets compiled to each rendering target.

MCP Apps integration

How rendering works inside Claude Desktop and other MCP hosts.

Assistant SDK

Native rendering inside your own iOS, Android, or web app.

BindJS Reference

Component primitives, modifiers, and property system.