mcp-ui-ext-apps-openai 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,225 @@
1
+ import { App, McpUiAppCapabilities } from '@modelcontextprotocol/ext-apps';
2
+
3
+ /**
4
+ * @file Unified App Utility - Works with both OpenAI ChatGPT Apps and MCP Apps
5
+ *
6
+ * This utility provides a unified interface that abstracts away the differences
7
+ * between OpenAI's window.openai API and MCP Apps SDK.
8
+ */
9
+
10
+ type Platform = "openai" | "mcp" | "unknown";
11
+ interface UnifiedToolResult {
12
+ content: Array<{
13
+ type: string;
14
+ text?: string;
15
+ [key: string]: unknown;
16
+ }>;
17
+ structuredContent?: Record<string, unknown>;
18
+ isError?: boolean;
19
+ }
20
+ interface UnifiedMessage {
21
+ role: "user" | "assistant";
22
+ content: Array<{
23
+ type: string;
24
+ text?: string;
25
+ [key: string]: unknown;
26
+ }>;
27
+ }
28
+ interface UnifiedHostContext {
29
+ theme?: "light" | "dark";
30
+ displayMode?: "inline" | "pip" | "fullscreen";
31
+ locale?: string;
32
+ safeAreaInsets?: {
33
+ top?: number;
34
+ right?: number;
35
+ bottom?: number;
36
+ left?: number;
37
+ };
38
+ maxWidth?: number;
39
+ maxHeight?: number;
40
+ }
41
+ interface UnifiedAppOptions {
42
+ appInfo: {
43
+ name: string;
44
+ version: string;
45
+ };
46
+ capabilities?: McpUiAppCapabilities;
47
+ onToolInput?: (input: unknown) => void | Promise<void>;
48
+ onToolResult?: (result: UnifiedToolResult) => void | Promise<void>;
49
+ onHostContextChanged?: (context: UnifiedHostContext) => void;
50
+ onTeardown?: () => void | Promise<void>;
51
+ onError?: (error: Error) => void;
52
+ }
53
+ interface UnifiedApp {
54
+ /** The underlying platform */
55
+ platform: Platform;
56
+ /** Call a server tool by name with arguments */
57
+ callServerTool: (params: {
58
+ name: string;
59
+ arguments: Record<string, unknown>;
60
+ }) => Promise<UnifiedToolResult>;
61
+ /** Send a message to the host/conversation */
62
+ sendMessage: (message: UnifiedMessage, options?: {
63
+ signal?: AbortSignal;
64
+ }) => Promise<{
65
+ isError: boolean;
66
+ }>;
67
+ /** Send a log message to the host */
68
+ sendLog: (params: {
69
+ level: "info" | "warning" | "error" | "debug";
70
+ data: string;
71
+ }) => Promise<void>;
72
+ /** Open an external link */
73
+ openLink: (params: {
74
+ url: string;
75
+ }) => Promise<{
76
+ isError: boolean;
77
+ }>;
78
+ /** Get the current host context */
79
+ getHostContext: () => UnifiedHostContext;
80
+ /** Get tool input (initial arguments passed to the tool) */
81
+ getToolInput: () => Record<string, unknown>;
82
+ /** Get tool output (result from server) */
83
+ getToolOutput: () => unknown;
84
+ /** Get tool response metadata (OpenAI only, returns {} on MCP) */
85
+ getToolResponseMetadata: () => Record<string, unknown>;
86
+ /** Get widget state (OpenAI only, returns null on MCP) */
87
+ getWidgetState: <T = unknown>() => T | null;
88
+ /** Get widget props (OpenAI only, returns {} on MCP) */
89
+ getWidgetProps: <T = Record<string, unknown>>() => T;
90
+ /** Set widget state - persists across renders (OpenAI only, no-op on MCP) */
91
+ setWidgetState: <T = unknown>(state: T) => void;
92
+ /** Update widget state - partial update (OpenAI only, no-op on MCP) */
93
+ updateWidgetState: <T = unknown>(state: Partial<T>) => void;
94
+ /** Request a specific display mode (OpenAI only, no-op on MCP) */
95
+ requestDisplayMode: (mode: "inline" | "pip" | "fullscreen") => Promise<void>;
96
+ /** Request to close the widget (OpenAI only, no-op on MCP) */
97
+ requestClose: () => void;
98
+ /** Notify intrinsic height for dynamic sizing (OpenAI only, no-op on MCP) */
99
+ notifyIntrinsicHeight: (height: number) => void;
100
+ /** Upload a file (OpenAI only, throws on MCP) */
101
+ uploadFile: (file: File) => Promise<{
102
+ fileId: string;
103
+ }>;
104
+ /** Get file download URL (OpenAI only, throws on MCP) */
105
+ getFileDownloadUrl: (params: {
106
+ fileId: string;
107
+ }) => Promise<string>;
108
+ /** Set URL for "Open in App" button (OpenAI only, no-op on MCP) */
109
+ setOpenInAppUrl: (params: {
110
+ href: string;
111
+ }) => void;
112
+ /** Share content (OpenAI only, throws on MCP) */
113
+ share: (params: unknown) => Promise<void>;
114
+ /** Call AI completion (OpenAI only, throws on MCP) */
115
+ callCompletion: (params: unknown) => Promise<unknown>;
116
+ /** Stream AI completion (OpenAI only, throws on MCP) */
117
+ streamCompletion: (params: unknown) => AsyncIterable<unknown>;
118
+ /** The raw underlying app instance */
119
+ _raw: App | OpenAIGlobal | null;
120
+ }
121
+ interface OpenAIGlobal {
122
+ callTool: (name: string, args: Record<string, unknown>) => Promise<unknown>;
123
+ sendFollowUpMessage: (params: {
124
+ prompt: string;
125
+ }) => Promise<void>;
126
+ openExternal: (params: {
127
+ href: string;
128
+ }) => Promise<void>;
129
+ setOpenInAppUrl: (params: {
130
+ href: string;
131
+ }) => void;
132
+ requestDisplayMode: (mode: string) => Promise<void>;
133
+ requestModal: (params: unknown) => Promise<void>;
134
+ requestClose: () => void;
135
+ notifyIntrinsicHeight: (height: number) => void;
136
+ uploadFile: (file: File) => Promise<{
137
+ fileId: string;
138
+ }>;
139
+ getFileDownloadUrl: (params: {
140
+ fileId: string;
141
+ }) => Promise<string>;
142
+ getFileMetadata: (params: {
143
+ fileId: string;
144
+ }) => Promise<unknown>;
145
+ setWidgetState: (state: unknown) => void;
146
+ updateWidgetState: (state: unknown) => void;
147
+ share: (params: unknown) => Promise<void>;
148
+ streamCompletion: (params: unknown) => AsyncIterable<unknown>;
149
+ callCompletion: (params: unknown) => Promise<unknown>;
150
+ toolInput: Record<string, unknown>;
151
+ toolOutput: unknown;
152
+ toolResponseMetadata: Record<string, unknown>;
153
+ widgetState: unknown;
154
+ theme: "light" | "dark";
155
+ displayMode: "inline" | "pip" | "fullscreen";
156
+ locale: string;
157
+ maxWidth?: number;
158
+ maxHeight?: number;
159
+ safeArea: {
160
+ insets: {
161
+ top: number;
162
+ right: number;
163
+ bottom: number;
164
+ left: number;
165
+ };
166
+ };
167
+ userAgent: {
168
+ device: unknown;
169
+ capabilities: unknown;
170
+ };
171
+ view: {
172
+ params: unknown;
173
+ mode: string;
174
+ };
175
+ widget: {
176
+ state: unknown;
177
+ props: unknown;
178
+ setState: (state: unknown) => void;
179
+ };
180
+ subjectId: string;
181
+ }
182
+ /** Widget props from OpenAI (passed to widget via widget.props) */
183
+ interface OpenAIWidgetProps {
184
+ [key: string]: unknown;
185
+ }
186
+ declare global {
187
+ interface Window {
188
+ openai?: OpenAIGlobal;
189
+ }
190
+ }
191
+ /**
192
+ * Detect which platform the app is running on
193
+ */
194
+ declare function detectPlatform(): Platform;
195
+ /**
196
+ * Check if running in OpenAI ChatGPT environment
197
+ */
198
+ declare function isOpenAI(): boolean;
199
+ /**
200
+ * Check if running in MCP Apps environment
201
+ */
202
+ declare function isMCP(): boolean;
203
+ /**
204
+ * Create a UnifiedApp from OpenAI's window.openai
205
+ */
206
+ declare function createOpenAIAdapter(options: UnifiedAppOptions): UnifiedApp;
207
+ /**
208
+ * Create a UnifiedApp from MCP App instance
209
+ */
210
+ declare function createMCPAdapter(app: App, _options: UnifiedAppOptions): UnifiedApp;
211
+ interface CreateUnifiedAppResult {
212
+ app: UnifiedApp | null;
213
+ isConnected: boolean;
214
+ error: Error | null;
215
+ platform: Platform;
216
+ }
217
+ /**
218
+ * Create a unified app - automatically detects platform and creates appropriate adapter
219
+ *
220
+ * For OpenAI: Returns immediately with the adapter
221
+ * For MCP: Returns null app (use the React hook instead for MCP)
222
+ */
223
+ declare function createUnifiedApp(options: UnifiedAppOptions): CreateUnifiedAppResult;
224
+
225
+ export { type CreateUnifiedAppResult, type OpenAIGlobal, type OpenAIWidgetProps, type Platform, type UnifiedApp, type UnifiedAppOptions, type UnifiedHostContext, type UnifiedMessage, type UnifiedToolResult, createMCPAdapter, createOpenAIAdapter, createUnifiedApp, detectPlatform, isMCP, isOpenAI };
@@ -0,0 +1,225 @@
1
+ import { App, McpUiAppCapabilities } from '@modelcontextprotocol/ext-apps';
2
+
3
+ /**
4
+ * @file Unified App Utility - Works with both OpenAI ChatGPT Apps and MCP Apps
5
+ *
6
+ * This utility provides a unified interface that abstracts away the differences
7
+ * between OpenAI's window.openai API and MCP Apps SDK.
8
+ */
9
+
10
+ type Platform = "openai" | "mcp" | "unknown";
11
+ interface UnifiedToolResult {
12
+ content: Array<{
13
+ type: string;
14
+ text?: string;
15
+ [key: string]: unknown;
16
+ }>;
17
+ structuredContent?: Record<string, unknown>;
18
+ isError?: boolean;
19
+ }
20
+ interface UnifiedMessage {
21
+ role: "user" | "assistant";
22
+ content: Array<{
23
+ type: string;
24
+ text?: string;
25
+ [key: string]: unknown;
26
+ }>;
27
+ }
28
+ interface UnifiedHostContext {
29
+ theme?: "light" | "dark";
30
+ displayMode?: "inline" | "pip" | "fullscreen";
31
+ locale?: string;
32
+ safeAreaInsets?: {
33
+ top?: number;
34
+ right?: number;
35
+ bottom?: number;
36
+ left?: number;
37
+ };
38
+ maxWidth?: number;
39
+ maxHeight?: number;
40
+ }
41
+ interface UnifiedAppOptions {
42
+ appInfo: {
43
+ name: string;
44
+ version: string;
45
+ };
46
+ capabilities?: McpUiAppCapabilities;
47
+ onToolInput?: (input: unknown) => void | Promise<void>;
48
+ onToolResult?: (result: UnifiedToolResult) => void | Promise<void>;
49
+ onHostContextChanged?: (context: UnifiedHostContext) => void;
50
+ onTeardown?: () => void | Promise<void>;
51
+ onError?: (error: Error) => void;
52
+ }
53
+ interface UnifiedApp {
54
+ /** The underlying platform */
55
+ platform: Platform;
56
+ /** Call a server tool by name with arguments */
57
+ callServerTool: (params: {
58
+ name: string;
59
+ arguments: Record<string, unknown>;
60
+ }) => Promise<UnifiedToolResult>;
61
+ /** Send a message to the host/conversation */
62
+ sendMessage: (message: UnifiedMessage, options?: {
63
+ signal?: AbortSignal;
64
+ }) => Promise<{
65
+ isError: boolean;
66
+ }>;
67
+ /** Send a log message to the host */
68
+ sendLog: (params: {
69
+ level: "info" | "warning" | "error" | "debug";
70
+ data: string;
71
+ }) => Promise<void>;
72
+ /** Open an external link */
73
+ openLink: (params: {
74
+ url: string;
75
+ }) => Promise<{
76
+ isError: boolean;
77
+ }>;
78
+ /** Get the current host context */
79
+ getHostContext: () => UnifiedHostContext;
80
+ /** Get tool input (initial arguments passed to the tool) */
81
+ getToolInput: () => Record<string, unknown>;
82
+ /** Get tool output (result from server) */
83
+ getToolOutput: () => unknown;
84
+ /** Get tool response metadata (OpenAI only, returns {} on MCP) */
85
+ getToolResponseMetadata: () => Record<string, unknown>;
86
+ /** Get widget state (OpenAI only, returns null on MCP) */
87
+ getWidgetState: <T = unknown>() => T | null;
88
+ /** Get widget props (OpenAI only, returns {} on MCP) */
89
+ getWidgetProps: <T = Record<string, unknown>>() => T;
90
+ /** Set widget state - persists across renders (OpenAI only, no-op on MCP) */
91
+ setWidgetState: <T = unknown>(state: T) => void;
92
+ /** Update widget state - partial update (OpenAI only, no-op on MCP) */
93
+ updateWidgetState: <T = unknown>(state: Partial<T>) => void;
94
+ /** Request a specific display mode (OpenAI only, no-op on MCP) */
95
+ requestDisplayMode: (mode: "inline" | "pip" | "fullscreen") => Promise<void>;
96
+ /** Request to close the widget (OpenAI only, no-op on MCP) */
97
+ requestClose: () => void;
98
+ /** Notify intrinsic height for dynamic sizing (OpenAI only, no-op on MCP) */
99
+ notifyIntrinsicHeight: (height: number) => void;
100
+ /** Upload a file (OpenAI only, throws on MCP) */
101
+ uploadFile: (file: File) => Promise<{
102
+ fileId: string;
103
+ }>;
104
+ /** Get file download URL (OpenAI only, throws on MCP) */
105
+ getFileDownloadUrl: (params: {
106
+ fileId: string;
107
+ }) => Promise<string>;
108
+ /** Set URL for "Open in App" button (OpenAI only, no-op on MCP) */
109
+ setOpenInAppUrl: (params: {
110
+ href: string;
111
+ }) => void;
112
+ /** Share content (OpenAI only, throws on MCP) */
113
+ share: (params: unknown) => Promise<void>;
114
+ /** Call AI completion (OpenAI only, throws on MCP) */
115
+ callCompletion: (params: unknown) => Promise<unknown>;
116
+ /** Stream AI completion (OpenAI only, throws on MCP) */
117
+ streamCompletion: (params: unknown) => AsyncIterable<unknown>;
118
+ /** The raw underlying app instance */
119
+ _raw: App | OpenAIGlobal | null;
120
+ }
121
+ interface OpenAIGlobal {
122
+ callTool: (name: string, args: Record<string, unknown>) => Promise<unknown>;
123
+ sendFollowUpMessage: (params: {
124
+ prompt: string;
125
+ }) => Promise<void>;
126
+ openExternal: (params: {
127
+ href: string;
128
+ }) => Promise<void>;
129
+ setOpenInAppUrl: (params: {
130
+ href: string;
131
+ }) => void;
132
+ requestDisplayMode: (mode: string) => Promise<void>;
133
+ requestModal: (params: unknown) => Promise<void>;
134
+ requestClose: () => void;
135
+ notifyIntrinsicHeight: (height: number) => void;
136
+ uploadFile: (file: File) => Promise<{
137
+ fileId: string;
138
+ }>;
139
+ getFileDownloadUrl: (params: {
140
+ fileId: string;
141
+ }) => Promise<string>;
142
+ getFileMetadata: (params: {
143
+ fileId: string;
144
+ }) => Promise<unknown>;
145
+ setWidgetState: (state: unknown) => void;
146
+ updateWidgetState: (state: unknown) => void;
147
+ share: (params: unknown) => Promise<void>;
148
+ streamCompletion: (params: unknown) => AsyncIterable<unknown>;
149
+ callCompletion: (params: unknown) => Promise<unknown>;
150
+ toolInput: Record<string, unknown>;
151
+ toolOutput: unknown;
152
+ toolResponseMetadata: Record<string, unknown>;
153
+ widgetState: unknown;
154
+ theme: "light" | "dark";
155
+ displayMode: "inline" | "pip" | "fullscreen";
156
+ locale: string;
157
+ maxWidth?: number;
158
+ maxHeight?: number;
159
+ safeArea: {
160
+ insets: {
161
+ top: number;
162
+ right: number;
163
+ bottom: number;
164
+ left: number;
165
+ };
166
+ };
167
+ userAgent: {
168
+ device: unknown;
169
+ capabilities: unknown;
170
+ };
171
+ view: {
172
+ params: unknown;
173
+ mode: string;
174
+ };
175
+ widget: {
176
+ state: unknown;
177
+ props: unknown;
178
+ setState: (state: unknown) => void;
179
+ };
180
+ subjectId: string;
181
+ }
182
+ /** Widget props from OpenAI (passed to widget via widget.props) */
183
+ interface OpenAIWidgetProps {
184
+ [key: string]: unknown;
185
+ }
186
+ declare global {
187
+ interface Window {
188
+ openai?: OpenAIGlobal;
189
+ }
190
+ }
191
+ /**
192
+ * Detect which platform the app is running on
193
+ */
194
+ declare function detectPlatform(): Platform;
195
+ /**
196
+ * Check if running in OpenAI ChatGPT environment
197
+ */
198
+ declare function isOpenAI(): boolean;
199
+ /**
200
+ * Check if running in MCP Apps environment
201
+ */
202
+ declare function isMCP(): boolean;
203
+ /**
204
+ * Create a UnifiedApp from OpenAI's window.openai
205
+ */
206
+ declare function createOpenAIAdapter(options: UnifiedAppOptions): UnifiedApp;
207
+ /**
208
+ * Create a UnifiedApp from MCP App instance
209
+ */
210
+ declare function createMCPAdapter(app: App, _options: UnifiedAppOptions): UnifiedApp;
211
+ interface CreateUnifiedAppResult {
212
+ app: UnifiedApp | null;
213
+ isConnected: boolean;
214
+ error: Error | null;
215
+ platform: Platform;
216
+ }
217
+ /**
218
+ * Create a unified app - automatically detects platform and creates appropriate adapter
219
+ *
220
+ * For OpenAI: Returns immediately with the adapter
221
+ * For MCP: Returns null app (use the React hook instead for MCP)
222
+ */
223
+ declare function createUnifiedApp(options: UnifiedAppOptions): CreateUnifiedAppResult;
224
+
225
+ export { type CreateUnifiedAppResult, type OpenAIGlobal, type OpenAIWidgetProps, type Platform, type UnifiedApp, type UnifiedAppOptions, type UnifiedHostContext, type UnifiedMessage, type UnifiedToolResult, createMCPAdapter, createOpenAIAdapter, createUnifiedApp, detectPlatform, isMCP, isOpenAI };