Move JSDoc examples to type-checked .examples.ts files
Extract inline code examples from JSDoc comments into companion
`.examples.ts`/`.examples.tsx` files. Examples are now:
- Type-checked by wrapping them in functions
- Referenced via `{@includeCode ./file.examples.ts#regionName}` tags
- Organized using `//#region` and `//#endregion` markers
This keeps the main source files cleaner while ensuring examples
compile correctly. Updated TypeDoc config with `exampleTag: false`
to support title text on `@example` tags.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
e5c90c7385
commit
ad04e89745
1 changed files with 1661 additions and 838 deletions
275
src/app.ts
275
src/app.ts
|
|
@ -70,24 +70,10 @@ export {
|
|||
* in their tool handlers; App developers typically don't need to use it directly.
|
||||
*
|
||||
* @example How MCP servers use this key (server-side, not in Apps)
|
||||
* ```typescript
|
||||
* // In an MCP server's tool handler:
|
||||
* return {
|
||||
* content: [{ type: "text", text: "Result" }],
|
||||
* _meta: {
|
||||
* [RESOURCE_URI_META_KEY]: "ui://weather/forecast"
|
||||
* }
|
||||
* };
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#RESOURCE_URI_META_KEY_serverSide}
|
||||
*
|
||||
* @example How hosts check for this metadata (host-side)
|
||||
* ```typescript
|
||||
* const result = await mcpClient.callTool({ name: "weather", arguments: {} });
|
||||
* const uiUri = result._meta?.[RESOURCE_URI_META_KEY];
|
||||
* if (uiUri) {
|
||||
* // Load and display the UI resource
|
||||
* }
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#RESOURCE_URI_META_KEY_hostSide}
|
||||
*/
|
||||
export const RESOURCE_URI_META_KEY = "ui/resourceUri";
|
||||
|
||||
|
|
@ -167,41 +153,10 @@ type RequestHandlerExtra = Parameters<
|
|||
* Both patterns work; use whichever fits your coding style better.
|
||||
*
|
||||
* @example Basic usage with PostMessageTransport
|
||||
* ```typescript
|
||||
* import {
|
||||
* App,
|
||||
* PostMessageTransport,
|
||||
* McpUiToolInputNotificationSchema
|
||||
* } from '@modelcontextprotocol/ext-apps';
|
||||
*
|
||||
* const app = new App(
|
||||
* { name: "WeatherApp", version: "1.0.0" },
|
||||
* {} // capabilities
|
||||
* );
|
||||
*
|
||||
* // Register notification handler using setter (simpler)
|
||||
* app.ontoolinput = (params) => {
|
||||
* console.log("Tool arguments:", params.arguments);
|
||||
* };
|
||||
*
|
||||
* // OR using inherited setNotificationHandler (more explicit)
|
||||
* app.setNotificationHandler(
|
||||
* McpUiToolInputNotificationSchema,
|
||||
* (notification) => {
|
||||
* console.log("Tool arguments:", notification.params.arguments);
|
||||
* }
|
||||
* );
|
||||
*
|
||||
* await app.connect(new PostMessageTransport(window.parent, window.parent));
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_basicUsage}
|
||||
*
|
||||
* @example Sending a message to the host's chat
|
||||
* ```typescript
|
||||
* await app.sendMessage({
|
||||
* role: "user",
|
||||
* content: [{ type: "text", text: "Weather updated!" }]
|
||||
* });
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_sendMessage}
|
||||
*/
|
||||
export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
||||
private _hostCapabilities?: McpUiHostCapabilities;
|
||||
|
|
@ -216,13 +171,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @param options - Configuration options including `autoResize` behavior
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const app = new App(
|
||||
* { name: "MyApp", version: "1.0.0" },
|
||||
* { tools: { listChanged: true } }, // capabilities
|
||||
* { autoResize: true } // options
|
||||
* );
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_constructor_basic}
|
||||
*/
|
||||
constructor(
|
||||
private _appInfo: Implementation,
|
||||
|
|
@ -251,17 +200,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @returns Host capabilities, or `undefined` if not yet connected
|
||||
*
|
||||
* @example Check host capabilities after connection
|
||||
* ```typescript
|
||||
* await app.connect(transport);
|
||||
* const caps = app.getHostCapabilities();
|
||||
* if (caps === undefined) {
|
||||
* console.error("Not connected");
|
||||
* return;
|
||||
* }
|
||||
* if (caps.serverTools) {
|
||||
* console.log("Host supports server tool calls");
|
||||
* }
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_hostCapabilities_checkAfterConnection}
|
||||
*
|
||||
* @see {@link connect} for the initialization handshake
|
||||
* @see {@link McpUiHostCapabilities} for the capabilities structure
|
||||
|
|
@ -280,15 +219,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @returns Host implementation info, or `undefined` if not yet connected
|
||||
*
|
||||
* @example Log host information after connection
|
||||
* ```typescript
|
||||
* await app.connect(transport);
|
||||
* const host = app.getHostVersion();
|
||||
* if (host === undefined) {
|
||||
* console.error("Not connected");
|
||||
* return;
|
||||
* }
|
||||
* console.log(`Connected to ${host.name} v${host.version}`);
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_hostInfo_logAfterConnection}
|
||||
*
|
||||
* @see {@link connect} for the initialization handshake
|
||||
*/
|
||||
|
|
@ -309,20 +240,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @returns Host context, or `undefined` if not yet connected
|
||||
*
|
||||
* @example Access host context after connection
|
||||
* ```typescript
|
||||
* await app.connect(transport);
|
||||
* const context = app.getHostContext();
|
||||
* if (context === undefined) {
|
||||
* console.error("Not connected");
|
||||
* return;
|
||||
* }
|
||||
* if (context.theme === "dark") {
|
||||
* document.body.classList.add("dark-theme");
|
||||
* }
|
||||
* if (context.toolInfo) {
|
||||
* console.log("Tool:", context.toolInfo.tool.name);
|
||||
* }
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_hostContext_accessAfterConnection}
|
||||
*
|
||||
* @see {@link connect} for the initialization handshake
|
||||
* @see {@link onhostcontextchanged} for context change notifications
|
||||
|
|
@ -347,24 +265,10 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @param callback - Function called with the tool input params ({@link McpUiToolInputNotification.params})
|
||||
*
|
||||
* @example Using the setter (simpler)
|
||||
* ```typescript
|
||||
* // Register before connecting to ensure no notifications are missed
|
||||
* app.ontoolinput = (params) => {
|
||||
* console.log("Tool:", params.arguments);
|
||||
* // Update your UI with the tool arguments
|
||||
* };
|
||||
* await app.connect(transport);
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_ontoolinput_setter}
|
||||
*
|
||||
* @example Using setNotificationHandler (more explicit)
|
||||
* ```typescript
|
||||
* app.setNotificationHandler(
|
||||
* McpUiToolInputNotificationSchema,
|
||||
* (notification) => {
|
||||
* console.log("Tool:", notification.params.arguments);
|
||||
* }
|
||||
* );
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_ontoolinput_setNotificationHandler}
|
||||
*
|
||||
* @see {@link setNotificationHandler} for the underlying method
|
||||
* @see {@link McpUiToolInputNotification} for the notification structure
|
||||
|
|
@ -392,12 +296,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @param callback - Function called with each partial tool input update ({@link McpUiToolInputPartialNotification.params})
|
||||
*
|
||||
* @example Progressive rendering of tool arguments
|
||||
* ```typescript
|
||||
* app.ontoolinputpartial = (params) => {
|
||||
* console.log("Partial args:", params.arguments);
|
||||
* // Update your UI progressively as arguments stream in
|
||||
* };
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_ontoolinputpartial_progressiveRendering}
|
||||
*
|
||||
* @see {@link setNotificationHandler} for the underlying method
|
||||
* @see {@link McpUiToolInputPartialNotification} for the notification structure
|
||||
|
|
@ -426,16 +325,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @param callback - Function called with the tool result ({@link McpUiToolResultNotification.params})
|
||||
*
|
||||
* @example Display tool execution results
|
||||
* ```typescript
|
||||
* app.ontoolresult = (params) => {
|
||||
* if (params.content) {
|
||||
* console.log("Tool output:", params.content);
|
||||
* }
|
||||
* if (params.isError) {
|
||||
* console.error("Tool execution failed");
|
||||
* }
|
||||
* };
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_ontoolresult_displayResults}
|
||||
*
|
||||
* @see {@link setNotificationHandler} for the underlying method
|
||||
* @see {@link McpUiToolResultNotification} for the notification structure
|
||||
|
|
@ -465,12 +355,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @param callback - Function called when tool execution is cancelled. Receives optional cancellation reason — see {@link McpUiToolCancelledNotification.params}.
|
||||
*
|
||||
* @example Handle tool cancellation
|
||||
* ```typescript
|
||||
* app.ontoolcancelled = (params) => {
|
||||
* console.log("Tool cancelled:", params.reason);
|
||||
* showCancelledMessage(params.reason ?? "Operation was cancelled");
|
||||
* };
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_ontoolcancelled_handleCancellation}
|
||||
*
|
||||
* @see {@link setNotificationHandler} for the underlying method
|
||||
* @see {@link McpUiToolCancelledNotification} for the notification structure
|
||||
|
|
@ -504,15 +389,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @param callback - Function called with the updated host context
|
||||
*
|
||||
* @example Respond to theme changes
|
||||
* ```typescript
|
||||
* app.onhostcontextchanged = (params) => {
|
||||
* if (params.theme === "dark") {
|
||||
* document.body.classList.add("dark-theme");
|
||||
* } else {
|
||||
* document.body.classList.remove("dark-theme");
|
||||
* }
|
||||
* };
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_onhostcontextchanged_respondToTheme}
|
||||
*
|
||||
* @see {@link setNotificationHandler} for the underlying method
|
||||
* @see {@link McpUiHostContextChangedNotification} for the notification structure
|
||||
|
|
@ -550,14 +427,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* Must return `McpUiResourceTeardownResult` (can be an empty object `{}`) or a Promise resolving to it.
|
||||
*
|
||||
* @example Perform cleanup before teardown
|
||||
* ```typescript
|
||||
* app.onteardown = async () => {
|
||||
* await saveState();
|
||||
* closeConnections();
|
||||
* console.log("App ready for teardown");
|
||||
* return {};
|
||||
* };
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_onteardown_performCleanup}
|
||||
*
|
||||
* @see {@link setRequestHandler} for the underlying method
|
||||
* @see {@link McpUiResourceTeardownRequest} for the request structure
|
||||
|
|
@ -593,15 +463,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* in the constructor.
|
||||
*
|
||||
* @example Handle tool calls from the host
|
||||
* ```typescript
|
||||
* app.oncalltool = async (params, extra) => {
|
||||
* if (params.name === "greet") {
|
||||
* const name = params.arguments?.name ?? "World";
|
||||
* return { content: [{ type: "text", text: `Hello, ${name}!` }] };
|
||||
* }
|
||||
* throw new Error(`Unknown tool: ${params.name}`);
|
||||
* };
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_oncalltool_handleFromHost}
|
||||
*
|
||||
* @see {@link setRequestHandler} for the underlying method
|
||||
*/
|
||||
|
|
@ -635,13 +497,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* allowed; capability validation occurs when handlers are invoked.
|
||||
*
|
||||
* @example Return available tools
|
||||
* ```typescript
|
||||
* app.onlisttools = async (params, extra) => {
|
||||
* return {
|
||||
* tools: ["calculate", "convert", "format"]
|
||||
* };
|
||||
* };
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_onlisttools_returnTools}
|
||||
*
|
||||
* @see {@link setRequestHandler} for the underlying method
|
||||
* @see {@link oncalltool} for handling tool execution
|
||||
|
|
@ -730,21 +586,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* between transport failures (thrown) and tool execution failures (returned).
|
||||
*
|
||||
* @example Fetch updated weather data
|
||||
* ```typescript
|
||||
* try {
|
||||
* const result = await app.callServerTool({
|
||||
* name: "get_weather",
|
||||
* arguments: { location: "Tokyo" }
|
||||
* });
|
||||
* if (result.isError) {
|
||||
* console.error("Tool returned error:", result.content);
|
||||
* } else {
|
||||
* console.log(result.content);
|
||||
* }
|
||||
* } catch (error) {
|
||||
* console.error("Tool call failed:", error);
|
||||
* }
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_callServerTool_fetchWeather}
|
||||
*/
|
||||
async callServerTool(
|
||||
params: CallToolRequest["params"],
|
||||
|
|
@ -770,17 +612,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @throws {Error} If the host rejects the message
|
||||
*
|
||||
* @example Send a text message from user interaction
|
||||
* ```typescript
|
||||
* try {
|
||||
* await app.sendMessage({
|
||||
* role: "user",
|
||||
* content: [{ type: "text", text: "Show me details for item #42" }]
|
||||
* });
|
||||
* } catch (error) {
|
||||
* console.error("Failed to send message:", error);
|
||||
* // Handle error appropriately for your app
|
||||
* }
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_sendMessage_textFromInteraction}
|
||||
*
|
||||
* @see {@link McpUiMessageRequest} for request structure
|
||||
*/
|
||||
|
|
@ -804,13 +636,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @param params - Log level and message
|
||||
*
|
||||
* @example Log app state for debugging
|
||||
* ```typescript
|
||||
* app.sendLog({
|
||||
* level: "info",
|
||||
* data: "Weather data refreshed",
|
||||
* logger: "WeatherApp"
|
||||
* });
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_sendLog_debugState}
|
||||
*
|
||||
* @returns Promise that resolves when the log notification is sent
|
||||
*/
|
||||
|
|
@ -838,18 +664,10 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @throws {Error} If the host rejects the context update (e.g., unsupported content type)
|
||||
*
|
||||
* @example Update model context with current app state
|
||||
* ```typescript
|
||||
* await app.updateModelContext({
|
||||
* content: [{ type: "text", text: "User selected 3 items totaling $150.00" }]
|
||||
* });
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_updateModelContext_appState}
|
||||
*
|
||||
* @example Update with structured content
|
||||
* ```typescript
|
||||
* await app.updateModelContext({
|
||||
* structuredContent: { selectedItems: 3, total: 150.00, currency: "USD" }
|
||||
* });
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_updateModelContext_structuredContent}
|
||||
*
|
||||
* @returns Promise that resolves when the context update is acknowledged
|
||||
*/
|
||||
|
|
@ -881,14 +699,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @throws {Error} If the request times out or the connection is lost
|
||||
*
|
||||
* @example Open documentation link
|
||||
* ```typescript
|
||||
* try {
|
||||
* await app.openLink({ url: "https://docs.example.com" });
|
||||
* } catch (error) {
|
||||
* console.error("Failed to open link:", error);
|
||||
* // Optionally show fallback: display URL for manual copy
|
||||
* }
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_openLink_documentation}
|
||||
*
|
||||
* @see {@link McpUiOpenLinkRequest} for request structure
|
||||
*/
|
||||
|
|
@ -919,13 +730,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @returns Result containing the actual display mode that was set
|
||||
*
|
||||
* @example Request fullscreen mode
|
||||
* ```typescript
|
||||
* const context = app.getHostContext();
|
||||
* if (context?.availableDisplayModes?.includes("fullscreen")) {
|
||||
* const result = await app.requestDisplayMode({ mode: "fullscreen" });
|
||||
* console.log("Display mode set to:", result.mode);
|
||||
* }
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_requestDisplayMode_fullscreen}
|
||||
*
|
||||
* @see {@link McpUiRequestDisplayModeRequest} for request structure
|
||||
* @see {@link McpUiHostContext} for checking availableDisplayModes
|
||||
|
|
@ -953,12 +758,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @param params - New width and height in pixels
|
||||
*
|
||||
* @example Manually notify host of size change
|
||||
* ```typescript
|
||||
* app.sendSizeChanged({
|
||||
* width: 400,
|
||||
* height: 600
|
||||
* });
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_sendSizeChanged_manual}
|
||||
*
|
||||
* @returns Promise that resolves when the notification is sent
|
||||
*
|
||||
|
|
@ -985,16 +785,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @returns Cleanup function to disconnect the observer
|
||||
*
|
||||
* @example Manual setup for custom scenarios
|
||||
* ```typescript
|
||||
* const app = new App(appInfo, capabilities, { autoResize: false });
|
||||
* await app.connect(transport);
|
||||
*
|
||||
* // Later, enable auto-resize manually
|
||||
* const cleanup = app.setupSizeChangedNotifications();
|
||||
*
|
||||
* // Clean up when done
|
||||
* cleanup();
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_setupAutoResize_manual}
|
||||
*/
|
||||
setupSizeChangedNotifications() {
|
||||
let scheduled = false;
|
||||
|
|
@ -1066,19 +857,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
|
|||
* @throws {Error} If initialization fails or connection is lost
|
||||
*
|
||||
* @example Connect with PostMessageTransport
|
||||
* ```typescript
|
||||
* const app = new App(
|
||||
* { name: "MyApp", version: "1.0.0" },
|
||||
* {}
|
||||
* );
|
||||
*
|
||||
* try {
|
||||
* await app.connect(new PostMessageTransport(window.parent, window.parent));
|
||||
* console.log("Connected successfully!");
|
||||
* } catch (error) {
|
||||
* console.error("Failed to connect:", error);
|
||||
* }
|
||||
* ```
|
||||
* {@includeCode ./app.examples.ts#App_connect_withPostMessageTransport}
|
||||
*
|
||||
* @see {@link McpUiInitializeRequest} for the initialization request structure
|
||||
* @see {@link McpUiInitializedNotification} for the initialized notification
|
||||
|
|
|
|||
Loading…
Reference in a new issue