About UI Ext Apps Openai
UI Ext Apps Openai is an MCP server published by lkm1developer in the AI category: unified utility for building apps that work on both OpenAI ChatGPT and MCP Apps platforms.
The repository has 1 stars and 0 forks, with the last commit 2 months ago. Recent commit activity is the strongest signal that reported issues will get attention.
Install
git clone https://github.com/lkm1developer/mcp-ui-ext-apps-openaiThis server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.
Ask AI
Ask AI about UI Ext Apps Openai
Powered by Claude · Grounded in docs
Security checks
Static checks derived from the repository 5 days ago. Heuristics on the source, not an audit.
- ✓README presentThe repository ships documentation.
- !License declaredNo license file. Legally you have no right to use it in a product.
- ✓Tests presentA test suite exists in the repository.
- ✓Dependencies pinnedA lockfile pins dependency versions.
- ✓No dynamic code executionSource scan found no eval, dynamic Function, or shell execution.
- !Scoped permissionsDoesn't declare a permission scope. Assume it can do anything its process can.
README
mcp-ui-ext-apps-openai
Unified utility for building apps that work on both OpenAI ChatGPT and MCP Apps platforms.
Author: lkm1developer
Installation
npm install mcp-ui-ext-apps-openai
Peer Dependencies
This package requires the following peer dependencies:
npm install @modelcontextprotocol/ext-apps react
Usage
React Hook (Recommended)
import { useUnifiedApp } from "mcp-ui-ext-apps-openai/react";
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
// Define your structured data type
interface CounterData {
status: boolean;
value?: number;
error?: string;
}
function CounterApp() {
const {
app,
isConnected,
platform,
hostContext,
initialProps,
widgetState,
setWidgetState,
} = useUnifiedApp({
appInfo: { name: "Counter App", version: "1.0.0" },
capabilities: {},
onError: (e) => console.error("[CounterApp]", e),
});
// Get counter value from widget state
const counter = (widgetState as { value?: number } | null)?.value ?? 0;
// Fetch counter from server
const fetchCounter = async () => {
if (!app) return;
const result = await app.callServerTool({ name: "get-counter", arguments: {} });
const data = (result as CallToolResult).structuredContent as unknown as CounterData;
if (data.status && data.value !== undefined) {
setWidgetState({ value: data.value });
}
};
// Initialize from initialProps (OpenAI) or fetch from server (MCP)
useEffect(() => {
if (!app || !isConnected) return;
if (initialProps !== undefined) {
const data = (initialProps as CallToolResult).structuredContent as unknown as CounterData;
if (data?.status && data.value !== undefined) {
setWidgetState({ value: data.value });
return;
}
}
fetchCounter();
}, [app, isConnected, initialProps]);
// Increment counter
const handleIncrement = async () => {
if (!app) return;
const newValue = counter + 1;
setWidgetState({ value: newValue }); // Optimistic update
const result = await app.callServerTool({
name: "set-counter",
arguments: { value: newValue }
});
const data = (result as CallToolResult).structuredContent as unknown as CounterData;
if (!data.status) {
setWidgetState({ value: counter }); // Revert on error
}
};
return (
<div>
<p>Platform: {platform}</p>
<p>Theme: {hostContext?.theme}</p>
<p>Counter: {counter}</p>
<button onClick={handleIncrement}>+</button>
<button onClick={fetchCounter}>Refresh</button>
</div>
);
}
Core Utilities (No React)
import { detectPlatform, isOpenAI, isMCP, createUnifiedApp } from "mcp-ui-ext-apps-openai";
// Check platform
const platform = detectPlatform(); // "openai" | "mcp" | "unknown"
if (isOpenAI()) {
console.log("Running on OpenAI ChatGPT");
} else if (isMCP()) {
console.log("Running on MCP Apps");
}
// Create unified app (for OpenAI only - use React hook for MCP)
const { app, isConnected, error } = createUnifiedApp({
appInfo: { name: "My App", version: "1.0.0" },
onError: console.error,
});
if (app && isConnected) {
const result = await app.callServerTool({ name: "my-tool", arguments: {} });
}
API Reference
useUnifiedApp(options)
React hook that provides a unified app interface for both platforms.
Options
| Option | Type | Description |
|---|---|---|
appInfo |
{ name: string; version: string } |
App information |
capabilities |
McpUiAppCapabilities |
Optional capabilities |
onToolInput |
(input: unknown) => void |
Called when tool input is received |
onToolResult |
(result: UnifiedToolResult) => void |
Called when tool result is received |
onHostContextChanged |
(context: UnifiedHostContext) => void |
Called when host context changes |
onTeardown |
() => void |
Called when app is being torn down |
onError |
(error: Error) => void |
Called on errors (also logs to console) |
Returns
| Property | Type | Description |
|---|---|---|
app |
UnifiedApp | null |
The unified app instance |
isConnected |
boolean |
Whether connected to host |
error |
Error | null |
Any connection error |
platform |
"openai" | "mcp" | "unknown" |
Detected platform |
hostContext |
UnifiedHostContext |
Current host context (theme, locale, etc.) |
initialProps |
unknown |
Initial props from toolOutput (OpenAI only) |
widgetProps |
Record<string, unknown> |
Widget props (OpenAI only) |
widgetState |
unknown |
Widget state (works on both platforms) |
setWidgetState |
(state: T) => void |
Set widget state |
updateWidgetState |
(state: Partial<T>) => void |
Partially update widget state |
UnifiedApp Interface
| Method | Description |
|---|---|
callServerTool({ name, arguments }) |
Call a server tool |
sendMessage(message, options?) |
Send a message to the host |
sendLog({ level, data }) |
Send a log message |
openLink({ url }) |
Open an external link |
getHostContext() |
Get current host context |
setWidgetState(state) |
Set widget state (OpenAI only) |
updateWidgetState(state) |
Update widget state partially (OpenAI only) |
requestDisplayMode(mode) |
Request display mode (OpenAI only) |
requestClose() |
Request to close widget (OpenAI only) |
uploadFile(file) |
Upload a file (OpenAI only) |
getFileDownloadUrl({ fileId }) |
Get file download URL (OpenAI only) |
Platform-Specific Behavior
| Feature | OpenAI | MCP |
|---|---|---|
widgetState |
Syncs to OpenAI + React state | React state only |
initialProps |
From toolOutput |
undefined |
widgetProps |
From widget.props |
{} |
uploadFile |
Works | Throws error |
requestDisplayMode |
Works | No-op |
callCompletion |
Works | Throws error |
Structured Tool Data
Tools should return structured data in structuredContent:
// Server tool response format
{
status: true,
value: 42,
// or on error:
// status: false,
// error: "Something went wrong"
}
// Access in client
const result = await app.callServerTool({ name: "get-counter", arguments: {} });
const data = (result as CallToolResult).structuredContent as unknown as CounterData;
if (data.status) {
console.log("Value:", data.value);
} else {
console.error("Error:", data.error);
}
License
MIT
Examples
The examples/ directory contains a complete counter app example:
Structure
examples/
├── server/ # MCP server with counter tools
│ ├── server.ts # Express + MCP server
│ └── package.json
└── ui/ # React counter app
├── src/main.tsx # Counter UI using useUnifiedApp
└── package.json
Server Example (examples/server/)
A fully-featured MCP server that:
- Auto-detects OpenAI vs MCP Apps clients via user-agent
- Uses proper MIME types (
text/html+skybridgefor OpenAI, standard for MCP) - Registers resources with
registerAppResource - Registers tools with
registerAppTool - Manages sessions (stateful, 5 min timeout)
Tools:
counter- Widget tool with resource bindingget-counter- Returns{ status: true, value: number }set-counter- Accepts{ value: number }, returns{ status: true, value: number }
Run:
cd examples/server
npm install
npm run dev # Starts on http://localhost:3001
UI Example (examples/ui/)
A React counter app that:
- Uses
useUnifiedApphook for cross-platform support - Initializes from
initialProps(OpenAI) or fetches viaget-counter(MCP) - Shows counter with +/- buttons
- Optimistically updates UI, reverts on error
- Persists changes via
set-countertool
Run:
cd examples/ui
npm install
npm run build # Builds to dist/index.html
The built dist/index.html is served by the server as the widget HTML resource.
Running the Full Example
-
Build the UI:
cd examples/ui && npm install && npm run build -
Start the server:
cd examples/server && npm install && npm run dev -
Connect from OpenAI ChatGPT or MCP Apps client to
http://localhost:3001/mcp
README fetched from the repository 5 days ago. The original is authoritative.