open-mcp-app 0.1.2 → 0.1.4

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.
@@ -1,6 +1,7 @@
1
- import { ToolResult, WidgetState, Environment, DisplayMode, AdapterKind, HostContext, WebSocketStatus } from '../core/index.js';
2
- export { BaseHostClient, BaseHostClientEvents, ChatGptAdapter, CreatureAdapter, HostAdapter, HostClientConfig, HostClientState, HostIdentity, KNOWN_HOSTS, LogLevel, McpAppsAdapter, StandaloneAdapter, StructuredWidgetState, UnifiedHostClient, UnifiedHostClientEvents, UpgradingMcpAppsClient, WebSocketClient, WebSocketClientConfig, createHost, createHostAsync, createWebSocket, detectEnvironment, getHostIdentity, isHost, parseHostUserAgent } from '../core/index.js';
1
+ import { ToolResult, WidgetState, Environment, DisplayMode, AdapterKind, HostContext, ExperimentalHostApi, WebSocketStatus, UnifiedHostClient } from '../core/index.js';
2
+ export { BaseHostClient, BaseHostClientEvents, ChatGptAdapter, CreatureAdapter, HostAdapter, HostClientConfig, HostClientState, HostIdentity, KNOWN_HOSTS, LogLevel, McpAppsAdapter, StandaloneAdapter, StructuredWidgetState, UnifiedHostClientEvents, UpgradingMcpAppsClient, WebSocketClient, WebSocketClientConfig, createHost, createHostAsync, createWebSocket, detectEnvironment, getHostIdentity, isHost, parseHostUserAgent } from '../core/index.js';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import { ReactNode } from 'react';
4
5
  export { applyDocumentTheme, applyHostFonts, applyHostStyleVariables, getDocumentTheme } from '@modelcontextprotocol/ext-apps';
5
6
 
6
7
  interface UseHostConfig {
@@ -13,6 +14,45 @@ interface UseHostConfig {
13
14
  /** Called when widget state changes (restored from host or updated) */
14
15
  onWidgetStateChange?: (widgetState: WidgetState | null) => void;
15
16
  }
17
+ /**
18
+ * Status of a tool call.
19
+ */
20
+ type ToolCallStatus = "idle" | "loading" | "success" | "error";
21
+ /**
22
+ * State returned from a tool call.
23
+ * Contains the status, data, and metadata from the tool result.
24
+ */
25
+ interface ToolCallState<T = Record<string, unknown>> {
26
+ /** Current status of the tool call */
27
+ status: ToolCallStatus;
28
+ /** Structured data from tool result (from structuredContent) */
29
+ data: T | null;
30
+ /** Full tool result object */
31
+ result: ToolResult<T> | null;
32
+ /** Error if the tool call failed */
33
+ error: unknown | null;
34
+ /** Whether the result is an error (from isError flag or thrown exception) */
35
+ isError: boolean;
36
+ /** Text content for AI context (from content[0].text) */
37
+ text: string | null;
38
+ /** Title for PIP tab (from structuredContent.title) */
39
+ title: string | null;
40
+ /** Instance ID for this widget (from structuredContent.instanceId) */
41
+ instanceId: string | null;
42
+ }
43
+ /**
44
+ * Function to call a tool with optional arguments.
45
+ * Returns a promise that resolves to the tool result.
46
+ */
47
+ type ToolCallFunction<T = Record<string, unknown>> = (args?: Record<string, unknown>) => Promise<ToolResult<T>>;
48
+ /**
49
+ * Tuple returned from callTool().
50
+ * First element is the function to call the tool, second is the current state.
51
+ */
52
+ type ToolCallTuple<T = Record<string, unknown>> = [
53
+ ToolCallFunction<T>,
54
+ ToolCallState<T>
55
+ ];
16
56
  /**
17
57
  * Logger interface with convenience methods for each log level.
18
58
  *
@@ -49,22 +89,36 @@ interface Logger {
49
89
  }
50
90
  interface UseHostReturn {
51
91
  isReady: boolean;
52
- callTool: <T = Record<string, unknown>>(toolName: string, args: Record<string, unknown>) => Promise<ToolResult<T>>;
53
- sendNotification: (method: string, params: unknown) => void;
54
- environment: Environment;
55
- widgetState: WidgetState | null;
56
- setWidgetState: (state: WidgetState | null) => void;
57
92
  /**
58
- * Set the pip/widget title displayed in the host UI.
93
+ * Get a tool caller for the given tool name.
94
+ * Returns a tuple of [callFn, state] where:
95
+ * - callFn: Function to call the tool with optional args (defaults to {})
96
+ * - state: Current state of the tool call (status, data, error, etc.)
59
97
  *
60
- * Useful for updating the title based on user actions (e.g., switching tabs)
61
- * without making a tool call.
98
+ * @example
99
+ * ```tsx
100
+ * const { callTool, isReady } = useHost({ name: "my-app", version: "1.0.0" });
101
+ * const [listTodos, listTodosState] = callTool<TodoData>("todos_list");
102
+ * const [addTodo, addTodoState] = callTool<TodoData>("todos_add");
62
103
  *
63
- * Note: Creature-specific extension, no-op on ChatGPT Apps.
104
+ * useEffect(() => {
105
+ * if (isReady) {
106
+ * listTodos(); // Call with no args
107
+ * }
108
+ * }, [isReady, listTodos]);
64
109
  *
65
- * @param title - The new title to display
110
+ * // Use the state
111
+ * if (listTodosState.status === "loading") return <Spinner />;
112
+ * if (listTodosState.data) return <TodoList todos={listTodosState.data.todos} />;
113
+ *
114
+ * // Call with args
115
+ * <button onClick={() => addTodo({ text: "New todo" })}>Add</button>
116
+ * ```
66
117
  */
67
- setTitle: (title: string) => void;
118
+ callTool: <T = Record<string, unknown>>(toolName: string) => ToolCallTuple<T>;
119
+ environment: Environment;
120
+ /** Current widget state (read-only). Use experimental_widgetState() for read/write access. */
121
+ widgetState: WidgetState | null;
68
122
  requestDisplayMode: (params: {
69
123
  mode: DisplayMode;
70
124
  }) => Promise<{
@@ -109,6 +163,52 @@ interface UseHostReturn {
109
163
  * ```
110
164
  */
111
165
  log: Logger;
166
+ /**
167
+ * Experimental APIs that are not part of the MCP Apps spec.
168
+ *
169
+ * These APIs provide access to Creature-specific features and other
170
+ * non-standard extensions. They may change or be removed in future versions.
171
+ *
172
+ * @example
173
+ * ```tsx
174
+ * const { experimental, isCreature } = useHost({ name: "my-app", version: "1.0.0" });
175
+ *
176
+ * // Set widget state (non-spec extension)
177
+ * experimental.setWidgetState({ count: 42 });
178
+ *
179
+ * // Set title (Creature-only)
180
+ * if (isCreature) {
181
+ * experimental.setTitle("My Widget");
182
+ * }
183
+ *
184
+ * // Get Creature-specific styles
185
+ * const styles = experimental.getCreatureStyles();
186
+ * ```
187
+ */
188
+ experimental: ExperimentalHostApi;
189
+ /**
190
+ * Get widget state as a useState-like tuple.
191
+ * Returns [state, setState] for reading and updating widget state.
192
+ *
193
+ * Widget state is persisted by the host across sessions and restored
194
+ * when the widget is re-opened.
195
+ *
196
+ * @example
197
+ * ```tsx
198
+ * const { experimental_widgetState } = useHost({ name: "my-app", version: "1.0.0" });
199
+ * const [widgetState, setWidgetState] = experimental_widgetState<MyState>();
200
+ *
201
+ * return (
202
+ * <button onClick={() => setWidgetState({ count: (widgetState?.count ?? 0) + 1 })}>
203
+ * Count: {widgetState?.count ?? 0}
204
+ * </button>
205
+ * );
206
+ * ```
207
+ */
208
+ experimental_widgetState: <T extends WidgetState = WidgetState>() => [
209
+ T | null,
210
+ (state: T | null) => void
211
+ ];
112
212
  }
113
213
  interface UseToolResultReturn<T> {
114
214
  /** Structured data from tool result */
@@ -153,28 +253,52 @@ interface CreatureIconProps {
153
253
  /**
154
254
  * React hook for connecting to an MCP Apps host.
155
255
  *
156
- * Creates a host client instance and manages its lifecycle. Automatically
157
- * connects on mount and disconnects on unmount. Uses refs for callbacks
158
- * to prevent reconnection loops when consumers pass inline functions.
256
+ * Can be used in two ways:
257
+ *
258
+ * 1. **With HostProvider** (recommended): Call `useHost()` with no arguments
259
+ * inside a component wrapped by `<HostProvider>`. The client is shared
260
+ * via context, and connection is managed by the provider.
261
+ *
262
+ * 2. **Standalone**: Pass config to create and manage your own client.
263
+ * The hook handles connection/disconnection automatically.
159
264
  *
160
- * @param config - Configuration including app info and event handlers
265
+ * @param config - Optional configuration. If omitted, uses HostProvider context.
161
266
  * @returns Current state and methods for interacting with the host
162
267
  *
163
- * @example
268
+ * @example With HostProvider (recommended)
164
269
  * ```tsx
165
- * const { isReady, callTool, log } = useHost({
166
- * name: "my-app",
167
- * version: "1.0.0",
168
- * onToolResult: (result) => setData(result.structuredContent),
169
- * });
170
- *
171
- * // Logging
172
- * log("User action"); // default info level
173
- * log.debug("Verbose info");
174
- * log.error("Something failed", { error: err.message });
270
+ * // App.tsx
271
+ * function App() {
272
+ * return (
273
+ * <HostProvider name="my-app" version="1.0.0">
274
+ * <MyWidget />
275
+ * </HostProvider>
276
+ * );
277
+ * }
278
+ *
279
+ * // MyWidget.tsx
280
+ * function MyWidget() {
281
+ * const { callTool, isReady, log, experimental_widgetState } = useHost();
282
+ * const [widgetState, setWidgetState] = experimental_widgetState();
283
+ * const [listTodos, listTodosData] = callTool("todos_list");
284
+ *
285
+ * useEffect(() => {
286
+ * if (isReady) listTodos();
287
+ * }, [isReady, listTodos]);
288
+ * }
289
+ * ```
290
+ *
291
+ * @example Standalone (creates own client)
292
+ * ```tsx
293
+ * function MyApp() {
294
+ * const { isReady, callTool, log } = useHost({
295
+ * name: "my-app",
296
+ * version: "1.0.0",
297
+ * });
298
+ * }
175
299
  * ```
176
300
  */
177
- declare function useHost(config: UseHostConfig): UseHostReturn;
301
+ declare function useHost(config?: UseHostConfig): UseHostReturn;
178
302
 
179
303
  /**
180
304
  * Hook to access tool result data.
@@ -193,4 +317,157 @@ declare function useWebSocket<TSend = unknown, TReceive = unknown>(url: string |
193
317
  */
194
318
  declare function CreatureIcon({ isDarkMode, showEyes, enableBlink, width, height, className, }: CreatureIconProps): react_jsx_runtime.JSX.Element;
195
319
 
196
- export { AdapterKind, CreatureIcon, type CreatureIconProps, DisplayMode, Environment, HostContext, type Logger, ToolResult, type UseHostConfig, type UseHostReturn, type UseToolResultReturn, type UseWebSocketConfig, type UseWebSocketReturn, WebSocketStatus, WidgetState, useHost, useToolResult, useWebSocket };
320
+ /**
321
+ * Get the host client from context.
322
+ *
323
+ * @throws Error if used outside of HostProvider
324
+ */
325
+ declare function useHostClient(): UnifiedHostClient;
326
+ /**
327
+ * Get the host client from context, or null if not in a provider.
328
+ * Useful for optional host features.
329
+ */
330
+ declare function useHostClientOptional(): UnifiedHostClient | null;
331
+ interface HostProviderProps {
332
+ /** App name for the host client */
333
+ name: string;
334
+ /** App version for the host client */
335
+ version: string;
336
+ /** Child components */
337
+ children: ReactNode;
338
+ /**
339
+ * Called when tool input is received.
340
+ * Note: For tool results, use onToolResult in individual components.
341
+ */
342
+ onToolInput?: (args: Record<string, unknown>) => void;
343
+ /** Called when theme changes (MCP Apps only) */
344
+ onThemeChange?: (theme: "light" | "dark") => void;
345
+ /** Called when host requests teardown (MCP Apps only) */
346
+ onTeardown?: () => Promise<void> | void;
347
+ }
348
+ /**
349
+ * Provides the host client to child components.
350
+ *
351
+ * Creates a single host client instance that is shared across all children.
352
+ * The client connects on mount and disconnects on unmount.
353
+ *
354
+ * @example
355
+ * ```tsx
356
+ * import { HostProvider } from 'open-mcp-app/react';
357
+ *
358
+ * function App() {
359
+ * return (
360
+ * <HostProvider name="my-app" version="1.0.0">
361
+ * <MyWidget />
362
+ * </HostProvider>
363
+ * );
364
+ * }
365
+ * ```
366
+ */
367
+ declare function HostProvider({ name, version, children, onToolInput, onThemeChange, onTeardown, }: HostProviderProps): react_jsx_runtime.JSX.Element;
368
+
369
+ /**
370
+ * Experimental React Hooks
371
+ *
372
+ * These hooks provide React-idiomatic APIs for non-spec host features.
373
+ * They follow the Vercel AI SDK naming convention with `experimental_` prefix.
374
+ *
375
+ * Usage:
376
+ * ```tsx
377
+ * import {
378
+ * experimental_useWidgetState as useWidgetState,
379
+ * experimental_useTitle as useTitle,
380
+ * } from 'open-mcp-app/react';
381
+ * ```
382
+ */
383
+
384
+ /**
385
+ * React hook for managing widget state with host synchronization.
386
+ *
387
+ * Returns a tuple similar to `useState`, but the state is:
388
+ * - Persisted by the host across sessions
389
+ * - Restored when the widget is re-opened
390
+ * - Optionally visible to the AI model (via `modelContent`)
391
+ *
392
+ * **Experimental:** This uses the `ui/notifications/widget-state-changed`
393
+ * notification which is not part of the MCP Apps specification.
394
+ *
395
+ * @returns Tuple of [state, setState] like useState
396
+ *
397
+ * @example
398
+ * ```tsx
399
+ * import { experimental_useWidgetState as useWidgetState } from 'open-mcp-app/react';
400
+ *
401
+ * function Counter() {
402
+ * const [state, setState] = useWidgetState<{ count: number }>();
403
+ *
404
+ * return (
405
+ * <button onClick={() => setState({ count: (state?.count ?? 0) + 1 })}>
406
+ * Count: {state?.count ?? 0}
407
+ * </button>
408
+ * );
409
+ * }
410
+ * ```
411
+ */
412
+ declare function experimental_useWidgetState<T extends WidgetState = WidgetState>(): [
413
+ T | null,
414
+ (state: T | null) => void
415
+ ];
416
+ /**
417
+ * React hook for setting the widget/PiP title.
418
+ *
419
+ * Returns a setter function to update the title displayed in the host UI.
420
+ * This is useful for dynamic titles that change based on widget state.
421
+ *
422
+ * **Experimental:** This uses the `ui/notifications/title-changed`
423
+ * notification which is a Creature-specific extension, not part of
424
+ * the MCP Apps specification. No-op on other hosts.
425
+ *
426
+ * @returns Function to set the title
427
+ *
428
+ * @example
429
+ * ```tsx
430
+ * import { experimental_useTitle as useTitle } from 'open-mcp-app/react';
431
+ *
432
+ * function DocumentEditor() {
433
+ * const setTitle = useTitle();
434
+ * const [docName, setDocName] = useState("Untitled");
435
+ *
436
+ * useEffect(() => {
437
+ * setTitle(`Editing: ${docName}`);
438
+ * }, [docName, setTitle]);
439
+ *
440
+ * return <input value={docName} onChange={(e) => setDocName(e.target.value)} />;
441
+ * }
442
+ * ```
443
+ */
444
+ declare function experimental_useTitle(): (title: string) => void;
445
+ /**
446
+ * React hook for accessing Creature-specific CSS style variables.
447
+ *
448
+ * Returns the custom CSS variables provided by the Creature host,
449
+ * or null if not running in Creature.
450
+ *
451
+ * **Experimental:** This is a Creature-specific extension, not part of
452
+ * the MCP Apps specification.
453
+ *
454
+ * @returns Creature styles object or null
455
+ *
456
+ * @example
457
+ * ```tsx
458
+ * import { experimental_useCreatureStyles as useCreatureStyles } from 'open-mcp-app/react';
459
+ *
460
+ * function ThemedComponent() {
461
+ * const styles = useCreatureStyles();
462
+ *
463
+ * return (
464
+ * <div style={{ color: styles?.['--creature-accent-color'] }}>
465
+ * Themed content
466
+ * </div>
467
+ * );
468
+ * }
469
+ * ```
470
+ */
471
+ declare function experimental_useCreatureStyles(): Record<string, string | undefined> | null;
472
+
473
+ export { AdapterKind, CreatureIcon, type CreatureIconProps, DisplayMode, Environment, ExperimentalHostApi, HostContext, HostProvider, type HostProviderProps, type Logger, type ToolCallFunction, type ToolCallState, type ToolCallStatus, type ToolCallTuple, ToolResult, UnifiedHostClient, type UseHostConfig, type UseHostReturn, type UseToolResultReturn, type UseWebSocketConfig, type UseWebSocketReturn, WebSocketStatus, WidgetState, experimental_useCreatureStyles, experimental_useTitle, experimental_useWidgetState, useHost, useHostClient, useHostClientOptional, useToolResult, useWebSocket };