1. Conduid
  2. AI
  3. UI Ext Apps Openai
MCP server · AI

UI Ext Apps Openai

Unified utility for building apps that work on both OpenAI ChatGPT and MCP Apps platforms

Unclaimed ai
48Fair

Scored 5 days ago · breakdown

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

From source
git clone https://github.com/lkm1developer/mcp-ui-ext-apps-openai

This 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

I know everything about UI Ext Apps Openai. Ask me about installation, configuration, usage, or troubleshooting.

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

npm version GitHub

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+skybridge for OpenAI, standard for MCP)
  • Registers resources with registerAppResource
  • Registers tools with registerAppTool
  • Manages sessions (stateful, 5 min timeout)

Tools:

  • counter - Widget tool with resource binding
  • get-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 useUnifiedApp hook for cross-platform support
  • Initializes from initialProps (OpenAI) or fetches via get-counter (MCP)
  • Shows counter with +/- buttons
  • Optimistically updates UI, reverts on error
  • Persists changes via set-counter tool

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

  1. Build the UI:

    cd examples/ui && npm install && npm run build
    
  2. Start the server:

    cd examples/server && npm install && npm run dev
    
  3. 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.

Questions

About UI Ext Apps Openai

How do I install UI Ext Apps Openai?

No package has been published for this server, so install it from source: clone the repository and follow its README.

Is UI Ext Apps Openai safe to use with an AI agent?

Its trust score is 48 out of 100 (fair). It passes 4 of the 6 static security checks run so far; the failures are listed above. It has no ConduID identity yet, so agent calls to it are not receipted.

Is UI Ext Apps Openai still maintained?

Yes — the last commit was 2 months ago. The repository has 1 stars and 0 forks.