mcp-app-studio 0.3.2

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,508 @@
1
+ import { Platform, ExtendedBridge, HostContext, HostCapabilities, ToolResult, DisplayMode, ContentBlock, FeatureKey } from './core/index.js';
2
+ export { AudioContentBlock, CHATGPT_CAPABILITIES, ChatMessage, ContainerDimensions, ContentBlockAnnotations, ContentBlockIcon, HostBridge, HostContextChangedCallback, HostStyles, ImageContentBlock, MCP_CAPABILITIES, ResourceContentBlock, ResourceLinkContentBlock, TeardownCallback, TextContentBlock, Theme, ToolCancelledCallback, ToolInputCallback, ToolInputPartialCallback, ToolResultCallback, hasFeature, imageBlock, textBlock } from './core/index.js';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import { ReactNode } from 'react';
5
+ import { A as AppCapabilities } from './bridge-BOSEqpaS.js';
6
+ import '@modelcontextprotocol/ext-apps';
7
+
8
+ /**
9
+ * Detection result with detailed information about what was checked.
10
+ */
11
+ interface DetectionResult {
12
+ /** The detected platform */
13
+ platform: Platform;
14
+ /** What marker was found (if any) */
15
+ detectedBy: string | null;
16
+ /** All markers that were checked */
17
+ checks: {
18
+ windowOpenai: boolean;
19
+ mcpUrlParam: boolean;
20
+ mcpWindowProp: boolean;
21
+ mcpDataAttr: boolean;
22
+ };
23
+ }
24
+ /**
25
+ * Detects the current platform with detailed results.
26
+ * Useful for debugging platform detection issues.
27
+ *
28
+ * @returns Detection result with platform and diagnostic info
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * const result = detectPlatformDetailed();
33
+ * console.log('Platform:', result.platform);
34
+ * console.log('Detected by:', result.detectedBy);
35
+ * console.log('Checks:', result.checks);
36
+ * ```
37
+ */
38
+ declare function detectPlatformDetailed(): DetectionResult;
39
+ /**
40
+ * Detects the current platform the widget is running on.
41
+ *
42
+ * Detection priority:
43
+ * 1. `window.openai` exists → ChatGPT
44
+ * 2. URL has `?mcp-host` param → MCP
45
+ * 3. `window.__MCP_HOST__` exists → MCP
46
+ * 4. iframe has `data-mcp-host` attribute → MCP
47
+ * 5. None of the above → unknown
48
+ *
49
+ * **Debugging tip:** Set `window.__CHATGPT_APP_DEBUG__ = true` before
50
+ * loading your widget to see detailed detection logs in the console.
51
+ *
52
+ * @returns The detected platform: "chatgpt", "mcp", or "unknown"
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * const platform = detectPlatform();
57
+ * if (platform === 'unknown') {
58
+ * console.log('Running in development mode or unsupported host');
59
+ * }
60
+ * ```
61
+ */
62
+ declare function detectPlatform(): Platform;
63
+ /**
64
+ * Returns true if running inside ChatGPT.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * if (isChatGPT()) {
69
+ * // Use ChatGPT-specific features
70
+ * }
71
+ * ```
72
+ */
73
+ declare function isChatGPT(): boolean;
74
+ /**
75
+ * Returns true if running inside an MCP host (e.g., Claude Desktop).
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * if (isMCP()) {
80
+ * // Use MCP-specific features
81
+ * }
82
+ * ```
83
+ */
84
+ declare function isMCP(): boolean;
85
+ /**
86
+ * Enable debug mode for platform detection.
87
+ * Logs detailed information about what markers are being checked.
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * import { enableDebugMode } from 'mcp-app-studio';
92
+ *
93
+ * // Enable before your app initializes
94
+ * enableDebugMode();
95
+ *
96
+ * // Now detection will log to console
97
+ * const platform = detectPlatform();
98
+ * ```
99
+ */
100
+ declare function enableDebugMode(): void;
101
+ /**
102
+ * Disable debug mode for platform detection.
103
+ */
104
+ declare function disableDebugMode(): void;
105
+
106
+ interface UniversalProviderProps {
107
+ children: ReactNode;
108
+ appInfo?: {
109
+ name: string;
110
+ version: string;
111
+ };
112
+ appCapabilities?: AppCapabilities;
113
+ }
114
+ declare function UniversalProvider({ children, appInfo, appCapabilities, }: UniversalProviderProps): react_jsx_runtime.JSX.Element | null;
115
+ declare function useUniversalBridge(): ExtendedBridge | null;
116
+ declare function usePlatform(): Platform;
117
+
118
+ /**
119
+ * Returns the current host context with environment information.
120
+ * Updates automatically when the host context changes.
121
+ *
122
+ * @returns The host context object, or null if not connected
123
+ *
124
+ * @example
125
+ * ```tsx
126
+ * function MyWidget() {
127
+ * const context = useHostContext();
128
+ *
129
+ * if (!context) return <div>Loading...</div>;
130
+ *
131
+ * return (
132
+ * <div>
133
+ * <p>Theme: {context.theme}</p>
134
+ * <p>Locale: {context.locale}</p>
135
+ * <p>Display mode: {context.displayMode}</p>
136
+ * </div>
137
+ * );
138
+ * }
139
+ * ```
140
+ */
141
+ declare function useHostContext(): HostContext | null;
142
+ /**
143
+ * Returns the current color theme ("light" or "dark").
144
+ * Defaults to "light" if theme is not available.
145
+ *
146
+ * @returns Current theme
147
+ *
148
+ * @example
149
+ * ```tsx
150
+ * function MyWidget() {
151
+ * const theme = useTheme();
152
+ *
153
+ * return (
154
+ * <div className={theme === 'dark' ? 'bg-gray-900 text-white' : 'bg-white text-black'}>
155
+ * Content
156
+ * </div>
157
+ * );
158
+ * }
159
+ * ```
160
+ */
161
+ declare function useTheme(): "light" | "dark";
162
+ /**
163
+ * Returns the capabilities supported by the current host platform.
164
+ * Use this to conditionally enable features based on platform support.
165
+ *
166
+ * @returns Host capabilities object, or null if not connected
167
+ *
168
+ * @example
169
+ * ```tsx
170
+ * function MyWidget() {
171
+ * const capabilities = useCapabilities();
172
+ *
173
+ * return (
174
+ * <div>
175
+ * {capabilities?.widgetState && (
176
+ * <button>Save State (ChatGPT only)</button>
177
+ * )}
178
+ * {capabilities?.modelContext && (
179
+ * <button>Update Context (MCP only)</button>
180
+ * )}
181
+ * </div>
182
+ * );
183
+ * }
184
+ * ```
185
+ */
186
+ declare function useCapabilities(): HostCapabilities | null;
187
+ /**
188
+ * Returns the input arguments passed to the tool that invoked this widget.
189
+ * Generic type parameter allows you to specify the expected input shape.
190
+ *
191
+ * @typeParam T - The expected shape of the tool input
192
+ * @returns Tool input object, or null if not yet received
193
+ *
194
+ * @example
195
+ * ```tsx
196
+ * interface SearchInput {
197
+ * query: string;
198
+ * limit?: number;
199
+ * }
200
+ *
201
+ * function SearchWidget() {
202
+ * const input = useToolInput<SearchInput>();
203
+ *
204
+ * if (!input) return <div>Waiting for search query...</div>;
205
+ *
206
+ * return <SearchResults query={input.query} limit={input.limit ?? 10} />;
207
+ * }
208
+ * ```
209
+ */
210
+ declare function useToolInput<T = Record<string, unknown>>(): T | null;
211
+ /**
212
+ * Returns partial tool input as it's being streamed (MCP only).
213
+ * Useful for showing real-time feedback as the user types.
214
+ *
215
+ * **Platform support:** MCP only. Returns null on ChatGPT.
216
+ *
217
+ * @typeParam T - The expected shape of the tool input
218
+ * @returns Partial tool input, or null
219
+ *
220
+ * @example
221
+ * ```tsx
222
+ * function StreamingInput() {
223
+ * const partial = useToolInputPartial<{ query: string }>();
224
+ * const final = useToolInput<{ query: string }>();
225
+ *
226
+ * // Show partial input with typing indicator
227
+ * if (partial && !final) {
228
+ * return <div className="opacity-50">{partial.query}...</div>;
229
+ * }
230
+ *
231
+ * return <div>{final?.query}</div>;
232
+ * }
233
+ * ```
234
+ */
235
+ declare function useToolInputPartial<T = Record<string, unknown>>(): T | null;
236
+ /**
237
+ * Returns the result from a tool call made by the widget.
238
+ * Updates when tool calls complete.
239
+ *
240
+ * @returns Tool result object, or null if no result yet
241
+ *
242
+ * @example
243
+ * ```tsx
244
+ * function ToolResultDisplay() {
245
+ * const result = useToolResult();
246
+ *
247
+ * if (!result) return null;
248
+ *
249
+ * if (result.isError) {
250
+ * return <div className="text-red-500">Error: {result.content?.[0]?.text}</div>;
251
+ * }
252
+ *
253
+ * return <div>{JSON.stringify(result.structuredContent)}</div>;
254
+ * }
255
+ * ```
256
+ */
257
+ declare function useToolResult(): ToolResult | null;
258
+ /**
259
+ * Returns the current display mode and a function to request a mode change.
260
+ * Display mode controls how the widget is presented (inline, fullscreen, or pip).
261
+ *
262
+ * @returns Tuple of [currentMode, setMode]
263
+ *
264
+ * @example
265
+ * ```tsx
266
+ * function ExpandableWidget() {
267
+ * const [mode, setMode] = useDisplayMode();
268
+ *
269
+ * return (
270
+ * <div>
271
+ * <p>Current mode: {mode}</p>
272
+ * {mode === 'inline' && (
273
+ * <button onClick={() => setMode('fullscreen')}>
274
+ * Expand to Fullscreen
275
+ * </button>
276
+ * )}
277
+ * {mode === 'fullscreen' && (
278
+ * <button onClick={() => setMode('inline')}>
279
+ * Collapse
280
+ * </button>
281
+ * )}
282
+ * </div>
283
+ * );
284
+ * }
285
+ * ```
286
+ */
287
+ declare function useDisplayMode(): [
288
+ DisplayMode,
289
+ (mode: DisplayMode) => Promise<void>
290
+ ];
291
+ /**
292
+ * Returns a function to call tools registered with the host.
293
+ * Tools allow your widget to perform actions and get data from the AI.
294
+ *
295
+ * @returns Async function to call tools
296
+ * @throws Error if bridge is not connected
297
+ *
298
+ * @example
299
+ * ```tsx
300
+ * function SearchWidget() {
301
+ * const callTool = useCallTool();
302
+ * const [results, setResults] = useState(null);
303
+ * const [loading, setLoading] = useState(false);
304
+ *
305
+ * const handleSearch = async (query: string) => {
306
+ * setLoading(true);
307
+ * try {
308
+ * const result = await callTool('search', { query, limit: 10 });
309
+ * if (result.isError) {
310
+ * console.error('Search failed');
311
+ * } else {
312
+ * setResults(result.structuredContent);
313
+ * }
314
+ * } finally {
315
+ * setLoading(false);
316
+ * }
317
+ * };
318
+ *
319
+ * return <SearchUI onSearch={handleSearch} results={results} loading={loading} />;
320
+ * }
321
+ * ```
322
+ */
323
+ declare function useCallTool(): (name: string, args: Record<string, unknown>) => Promise<ToolResult>;
324
+ /**
325
+ * Returns a function to open links in the user's browser.
326
+ * This is the recommended way to open external URLs from your widget.
327
+ *
328
+ * @returns Async function to open links
329
+ * @throws Error if bridge is not connected
330
+ *
331
+ * @example
332
+ * ```tsx
333
+ * function LinkButton({ url, label }: { url: string; label: string }) {
334
+ * const openLink = useOpenLink();
335
+ *
336
+ * return (
337
+ * <button onClick={() => openLink(url)}>
338
+ * {label} ↗
339
+ * </button>
340
+ * );
341
+ * }
342
+ * ```
343
+ */
344
+ declare function useOpenLink(): (url: string) => Promise<void>;
345
+ /**
346
+ * Returns a function to send a message to the conversation.
347
+ * Useful for suggesting follow-up prompts or triggering new interactions.
348
+ *
349
+ * @returns Async function to send messages
350
+ * @throws Error if bridge is not connected or sendMessage not supported
351
+ *
352
+ * @example
353
+ * ```tsx
354
+ * function SuggestionChips() {
355
+ * const sendMessage = useSendMessage();
356
+ *
357
+ * const suggestions = ['Tell me more', 'Show examples', 'Explain in detail'];
358
+ *
359
+ * return (
360
+ * <div className="flex gap-2">
361
+ * {suggestions.map(text => (
362
+ * <button key={text} onClick={() => sendMessage(text)}>
363
+ * {text}
364
+ * </button>
365
+ * ))}
366
+ * </div>
367
+ * );
368
+ * }
369
+ * ```
370
+ */
371
+ declare function useSendMessage(): (text: string) => Promise<void>;
372
+ /**
373
+ * Returns a function to update the model's context (MCP only).
374
+ * Use this to provide additional context to the AI model.
375
+ *
376
+ * **Platform support:** MCP only. Logs a warning on ChatGPT.
377
+ *
378
+ * @returns Async function to update model context
379
+ *
380
+ * @example
381
+ * ```tsx
382
+ * function DataViewer({ data }: { data: object }) {
383
+ * const updateContext = useUpdateModelContext();
384
+ * const platform = usePlatform();
385
+ *
386
+ * useEffect(() => {
387
+ * if (platform === 'mcp') {
388
+ * updateContext({
389
+ * structuredContent: { currentData: data }
390
+ * });
391
+ * }
392
+ * }, [data, platform, updateContext]);
393
+ *
394
+ * return <pre>{JSON.stringify(data, null, 2)}</pre>;
395
+ * }
396
+ * ```
397
+ */
398
+ declare function useUpdateModelContext(): (ctx: {
399
+ content?: ContentBlock[];
400
+ structuredContent?: Record<string, unknown>;
401
+ }) => Promise<void>;
402
+ /**
403
+ * Returns persisted widget state and a setter (ChatGPT only).
404
+ * State is preserved across page refreshes and conversation turns.
405
+ *
406
+ * **Platform support:** ChatGPT only. Logs a warning on MCP.
407
+ *
408
+ * @typeParam T - The shape of your widget state
409
+ * @returns Tuple of [state, setState]
410
+ *
411
+ * @example
412
+ * ```tsx
413
+ * interface MapState {
414
+ * center: { lat: number; lng: number };
415
+ * zoom: number;
416
+ * selectedMarker: string | null;
417
+ * }
418
+ *
419
+ * function MapWidget() {
420
+ * const [state, setState] = useWidgetState<MapState>();
421
+ *
422
+ * const handleZoom = (zoom: number) => {
423
+ * setState(prev => prev ? { ...prev, zoom } : { center: { lat: 0, lng: 0 }, zoom, selectedMarker: null });
424
+ * };
425
+ *
426
+ * return (
427
+ * <Map
428
+ * center={state?.center ?? { lat: 0, lng: 0 }}
429
+ * zoom={state?.zoom ?? 10}
430
+ * onZoomChange={handleZoom}
431
+ * />
432
+ * );
433
+ * }
434
+ * ```
435
+ */
436
+ declare function useWidgetState<T = Record<string, unknown>>(): [
437
+ T | null,
438
+ (state: T | null) => void
439
+ ];
440
+ /**
441
+ * Returns a function for structured logging (MCP only).
442
+ * Logs are sent to the MCP host for debugging and monitoring.
443
+ *
444
+ * **Platform support:** MCP only. Falls back to console.log on other platforms.
445
+ *
446
+ * @returns Log function that accepts level and message
447
+ *
448
+ * @example
449
+ * ```tsx
450
+ * function DataProcessor() {
451
+ * const log = useLog();
452
+ *
453
+ * const processData = async (data: unknown) => {
454
+ * log('info', 'Starting data processing');
455
+ * try {
456
+ * // Process data...
457
+ * log('debug', `Processed ${data.length} items`);
458
+ * } catch (error) {
459
+ * log('error', `Processing failed: ${error.message}`);
460
+ * }
461
+ * };
462
+ *
463
+ * return <button onClick={() => processData(someData)}>Process</button>;
464
+ * }
465
+ * ```
466
+ */
467
+ declare function useLog(): (level: "debug" | "info" | "warning" | "error", data: string) => void;
468
+ /**
469
+ * Check if a specific feature is available on the current platform.
470
+ * This is a convenient wrapper around `useCapabilities()` for single feature checks.
471
+ *
472
+ * @param feature - The feature key to check
473
+ * @returns Whether the feature is available
474
+ *
475
+ * @example
476
+ * ```tsx
477
+ * function ConditionalFeatures() {
478
+ * const hasWidgetState = useFeature('widgetState');
479
+ * const hasModelContext = useFeature('modelContext');
480
+ *
481
+ * return (
482
+ * <div>
483
+ * {hasWidgetState && <StatePersistence />}
484
+ * {hasModelContext && <ContextUpdater />}
485
+ * </div>
486
+ * );
487
+ * }
488
+ * ```
489
+ *
490
+ * @example
491
+ * ```tsx
492
+ * // Combine with usePlatform for platform-specific UI
493
+ * function PlatformAwareWidget() {
494
+ * const platform = usePlatform();
495
+ * const hasFileUpload = useFeature('fileUpload');
496
+ *
497
+ * return (
498
+ * <div>
499
+ * <p>Running on: {platform}</p>
500
+ * {hasFileUpload ? <FileUploader /> : <p>File upload not available</p>}
501
+ * </div>
502
+ * );
503
+ * }
504
+ * ```
505
+ */
506
+ declare function useFeature(feature: FeatureKey): boolean;
507
+
508
+ export { ContentBlock, type DetectionResult, DisplayMode, ExtendedBridge, FeatureKey, HostCapabilities, HostContext, Platform, ToolResult, UniversalProvider, type UniversalProviderProps, detectPlatform, detectPlatformDetailed, disableDebugMode, enableDebugMode, isChatGPT, isMCP, useCallTool, useCapabilities, useDisplayMode, useFeature, useHostContext, useLog, useOpenLink, usePlatform, useSendMessage, useTheme, useToolInput, useToolInputPartial, useToolResult, useUniversalBridge, useUpdateModelContext, useWidgetState };