Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9184830
UITemplatedToolCallRendererProps for MCP Apps
ochafik Nov 21, 2025
73c2c0d
Upgrade MCP SDK to 1.22.0 (many (Embedded)Resource type fixes)
ochafik Nov 22, 2025
3b23ede
Update adapter.ts
ochafik Nov 22, 2025
5342f81
Update UIResourceRendererWC.test.tsx
ochafik Nov 22, 2025
6d07a4b
add missing client dep (vite-tsconfig-paths)
ochafik Nov 22, 2025
098d10e
Merge branch 'ochafik/upgrade' into mcp-apps
ochafik Nov 22, 2025
c55ef76
update to latest ext-apps example renderer
ochafik Nov 24, 2025
e0c4421
Sync with latest ext-apps, fix PR review comments
ochafik Dec 8, 2025
d12ddcc
Add AppFrame component, refactor AppRenderer, use ext-apps v0.1.0
ochafik Dec 12, 2025
8aa7205
Merge branch 'main' into mcp-apps
ochafik Dec 12, 2025
a312e52
feat: use ext-apps branch with setter-based MCP forwarding handlers
ochafik Dec 12, 2025
cae7999
Merge upstream/main into mcp-apps
ochafik Dec 12, 2025
3cf3c37
feat(client): expose MCP request handlers and AppBridge ref
ochafik Dec 12, 2025
e6dbe15
refactor(client): require AppBridge in AppFrame, cleaner AppRenderer API
ochafik Dec 12, 2025
fc16af4
refactor(client): require AppBridge in AppFrame, cleaner AppRenderer API
ochafik Dec 12, 2025
196401e
Merge origin/mcp-apps and use hostContext prop instead of setHostCont…
ochafik Dec 12, 2025
681bb43
chore: prettier formatting + re-export McpUiHostContext type
ochafik Dec 12, 2025
a84faee
refactor(client): cleaner API with props instead of ref methods
ochafik Dec 12, 2025
fc32fc6
refactor(client): use camelCase for all callback props
ochafik Dec 12, 2025
f750c98
test(client): add comprehensive tests for AppRenderer
ochafik Dec 12, 2025
d2d350c
chore: update ext-apps to latest, fix test types
ochafik Dec 13, 2025
38a7fd0
chore: add ESLint flat config for v9 compatibility
ochafik Dec 13, 2025
93f8759
chore: switch ext-apps dependency to main branch
ochafik Dec 15, 2025
b2673b9
chore(client): regenerate iframe-bundle with updated dependencies
ochafik Dec 16, 2025
fece80e
feat(client): make Client optional with onReadResource alternative
ochafik Dec 16, 2025
23f28e9
chore: update ext-apps to ^0.2.0 and MCP SDK to ^1.24.0
ochafik Dec 16, 2025
28f61b7
docs: add AppRenderer/AppFrame docs, fix sandbox promise rejection
ochafik Dec 16, 2025
8ff3186
Merge origin/main into mcp-apps to update PR #147
idosal Dec 18, 2025
0d64f86
fix build
idosal Dec 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions docs/src/guide/mcp-apps.md
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,113 @@ The adapter logs debug information to the browser console. Look for messages pre
[MCP Apps Adapter] Intercepted MCP-UI message: prompt
```

## Host-Side Rendering (Client SDK)

The `@mcp-ui/client` package provides React components for rendering MCP Apps tool UIs in your host application.

### AppRenderer Component

`AppRenderer` is the high-level component that handles the complete lifecycle of rendering an MCP tool's UI:

```tsx
import { AppRenderer, type AppRendererHandle } from '@mcp-ui/client';

function ToolUI({ client, toolName, toolInput, toolResult }) {
const appRef = useRef<AppRendererHandle>(null);

return (
<AppRenderer
ref={appRef}
client={client}
toolName={toolName}
sandbox={{ url: new URL('http://localhost:8765/sandbox_proxy.html') }}
toolInput={toolInput}
toolResult={toolResult}
hostContext={{ theme: 'dark' }}
onOpenLink={async ({ url }) => window.open(url)}
onMessage={async (params) => {
console.log('Message from tool UI:', params);
return { isError: false };
}}
onError={(error) => console.error('Tool UI error:', error)}
/>
);
}
```

**Key Props:**
- `client` - Optional MCP client for automatic resource fetching and MCP request forwarding
- `toolName` - Name of the tool to render UI for
- `sandbox` - Sandbox configuration with the sandbox proxy URL
- `html` - Optional pre-fetched HTML (skips resource fetching)
- `toolResourceUri` - Optional pre-fetched resource URI
- `toolInput` / `toolResult` - Tool arguments and results to pass to the UI
- `hostContext` - Theme, locale, viewport info for the guest UI
- `onOpenLink` / `onMessage` / `onLoggingMessage` - Handlers for guest UI requests

**Ref Methods:**
- `sendToolListChanged()` - Notify guest when tools change
- `sendResourceListChanged()` - Notify guest when resources change
- `sendPromptListChanged()` - Notify guest when prompts change
- `teardownResource()` - Clean up before unmounting

### Using Without an MCP Client

You can use `AppRenderer` without a full MCP client by providing custom handlers:

```tsx
<AppRenderer
// No client - use callbacks instead
toolName="my-tool"
toolResourceUri="ui://my-server/my-tool"
sandbox={{ url: sandboxUrl }}
onReadResource={async ({ uri }) => {
// Proxy to your MCP client in a different context
return myMcpProxy.readResource({ uri });
}}
onCallTool={async (params) => {
return myMcpProxy.callTool(params);
}}
/>
```

Or provide pre-fetched HTML directly:

```tsx
<AppRenderer
toolName="my-tool"
sandbox={{ url: sandboxUrl }}
html={preloadedHtml} // Skip all resource fetching
toolInput={args}
/>
```

### AppFrame Component

`AppFrame` is the lower-level component for when you already have the HTML content and an `AppBridge` instance:

```tsx
import { AppFrame, AppBridge } from '@mcp-ui/client';

function LowLevelToolUI({ html, client }) {
const bridge = useMemo(() => new AppBridge(client, hostInfo, capabilities), [client]);

return (
<AppFrame
html={html}
sandbox={{ url: sandboxUrl }}
appBridge={bridge}
toolInput={{ query: 'test' }}
onSizeChanged={(size) => console.log('Size changed:', size)}
/>
);
}
```

### Sandbox Proxy

Both components require a sandbox proxy HTML file to be served. This provides security isolation for the guest UI. The sandbox proxy URL should point to a page that loads the MCP Apps sandbox proxy script.

## Related Resources

- [MCP Apps SEP Specification](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx)
Expand Down
2 changes: 1 addition & 1 deletion examples/mcp-apps-demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"dependencies": {
"@mcp-ui/server": "workspace:*",
"@modelcontextprotocol/ext-apps": "^0.2.2",
"@modelcontextprotocol/sdk": "^1.22.0",
"@modelcontextprotocol/sdk": "^1.25.1",
"cors": "^2.8.5",
"express": "^4.18.2",
"zod": "^3.22.4"
Expand Down
61 changes: 22 additions & 39 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions sdks/typescript/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@
"dist"
],
"dependencies": {
"@modelcontextprotocol/sdk": "^1.22.0",
"@modelcontextprotocol/ext-apps": "^0.2.0",
"@modelcontextprotocol/sdk": "^1.24.0",
"@mcp-ui/shared": "workspace:*",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ochafik was this change needed? it is causing a resolution issue when trying to install locally ➤ YN0001: │ Error: @mcp-ui/shared@workspace:*: Workspace not found (@mcp-ui/shared@workspace:*) removing this line fixes the error

"@quilted/threads": "^3.1.3",
"@r2wc/react-to-web-component": "^2.0.4",
"@remote-dom/core": "^1.8.0",
"@remote-dom/react": "^1.2.2"
"@remote-dom/react": "^1.2.2",
"zod": "^3.23.8"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.0.0",
Expand Down
Loading
Loading