Initial commit

This commit is contained in:
Olivier Chafik 2025-11-21 11:56:27 +00:00
commit 92f42cf533
No known key found for this signature in database
2 changed files with 2534 additions and 0 deletions

70
react/useApp.tsx Normal file
View file

@ -0,0 +1,70 @@
import { useEffect, useState } from "react";
import { Implementation } from "@modelcontextprotocol/sdk/types.js";
import { Client } from "@modelcontextprotocol/sdk/client";
import { App, McpUiAppCapabilities, PostMessageTransport } from "../app";
export * from "../app";
export interface UseAppOptions {
appInfo: Implementation;
capabilities: McpUiAppCapabilities;
/**
* Called after client is created but before connection.
* Use this to register request/notification handlers via
* client.setRequestHandler() and client.setNotificationHandler().
*/
onAppCreated?: (app: App) => void;
}
export interface AppState {
app: App | null;
isConnected: boolean;
error: Error | null;
}
export function useApp({
appInfo,
capabilities,
onAppCreated,
}: UseAppOptions): AppState {
const [app, setApp] = useState<App | null>(null);
const [isConnected, setIsConnected] = useState(false);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
let mounted = true;
async function connect() {
try {
const transport = new PostMessageTransport(window.parent);
const app = new App(appInfo, capabilities);
// Register handlers BEFORE connecting
onAppCreated?.(app);
await app.connect(transport);
if (mounted) {
setApp(app);
setIsConnected(true);
setError(null);
}
} catch (error) {
if (mounted) {
setApp(null);
setIsConnected(false);
setError(
error instanceof Error ? error : new Error("Failed to connect"),
);
}
}
}
connect();
return () => {
mounted = false;
};
}, []); // Intentionally not including options to avoid reconnection
return { app, isConnected, error };
}

20
react/useAutoResize.ts Normal file
View file

@ -0,0 +1,20 @@
import { useEffect, RefObject } from "react";
import { App } from "../app";
/**
* Custom hook that automatically reports size changes to the parent window.
*
* @param client - MCP UI client for sending size notifications
*/
export function useAutoResize(
app: App | null,
elementRef?: RefObject<HTMLElement | null>,
) {
useEffect(() => {
if (!app) {
return;
}
return app.setupSizeChangeNotifications();
}, [app, elementRef]);
}