/** * @file App that demonstrates a few features using MCP Apps SDK + React. */ import type { App, McpUiHostContext } from "@modelcontextprotocol/ext-apps"; import { useApp } from "@modelcontextprotocol/ext-apps/react"; import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { StrictMode, useCallback, useEffect, useState } from "react"; import { createRoot } from "react-dom/client"; import styles from "./mcp-app.module.css"; function extractTime(callToolResult: CallToolResult): string { const { text } = callToolResult.content?.find((c) => c.type === "text")!; return text; } function GetTimeApp() { const [toolResult, setToolResult] = useState(null); const [hostContext, setHostContext] = useState(); // `useApp` (1) creates an `App` instance, (2) calls `onAppCreated` to // register handlers, and (3) calls `connect()` on the `App` instance. const { app, error } = useApp({ appInfo: { name: "Get Time App", version: "1.0.0" }, capabilities: {}, onAppCreated: (app) => { app.onteardown = async () => { console.info("App is being torn down"); return {}; }; app.ontoolinput = async (input) => { console.info("Received tool call input:", input); }; app.ontoolresult = async (result) => { console.info("Received tool call result:", result); setToolResult(result); }; app.ontoolcancelled = (params) => { console.info("Tool call cancelled:", params.reason); }; app.onerror = console.error; app.onhostcontextchanged = (params) => { setHostContext((prev) => ({ ...prev, ...params })); }; }, }); useEffect(() => { if (app) { setHostContext(app.getHostContext()); } }, [app]); if (error) return
ERROR: {error.message}
; if (!app) return
Connecting...
; return ; } interface GetTimeAppInnerProps { app: App; toolResult: CallToolResult | null; hostContext?: McpUiHostContext; } function GetTimeAppInner({ app, toolResult, hostContext }: GetTimeAppInnerProps) { const [serverTime, setServerTime] = useState("Loading..."); const [messageText, setMessageText] = useState("This is message text."); const [logText, setLogText] = useState("This is log text."); const [linkUrl, setLinkUrl] = useState("https://modelcontextprotocol.io/"); useEffect(() => { if (toolResult) { setServerTime(extractTime(toolResult)); } }, [toolResult]); const handleGetTime = useCallback(async () => { try { console.info("Calling get-time tool..."); const result = await app.callServerTool({ name: "get-time", arguments: {} }); console.info("get-time result:", result); setServerTime(extractTime(result)); } catch (e) { console.error(e); setServerTime("[ERROR]"); } }, [app]); const handleSendMessage = useCallback(async () => { const signal = AbortSignal.timeout(5000); try { console.info("Sending message text to Host:", messageText); const { isError } = await app.sendMessage( { role: "user", content: [{ type: "text", text: messageText }] }, { signal }, ); console.info("Message", isError ? "rejected" : "accepted"); } catch (e) { console.error("Message send error:", signal.aborted ? "timed out" : e); } }, [app, messageText]); const handleSendLog = useCallback(async () => { console.info("Sending log text to Host:", logText); await app.sendLog({ level: "info", data: logText }); }, [app, logText]); const handleOpenLink = useCallback(async () => { console.info("Sending open link request to Host:", linkUrl); const { isError } = await app.openLink({ url: linkUrl }); console.info("Open link request", isError ? "rejected" : "accepted"); }, [app, linkUrl]); return (

Watch activity in the DevTools console!

Server Time: {serverTime}