Add skeleton docs/patterns.md with type-checked companion file
Introduces a patterns documentation page for common MCP Apps recipes. The skeleton includes TODO sections for: perceived latency, iframe/MCP Apps coexistence, authenticated calls, private tools, theme changes, fullscreen, host styling, data persistence, OpenAI migration, and error handling. - Add `docs/patterns.md` to `projectDocuments` in `typedoc.config.mjs` - Add `docs/patterns.ts` companion file with region-delimited code stubs - Include `docs/**/*.ts` in `tsconfig.json` for type-checking - Document the standalone docs pattern in `CLAUDE.md` Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
26ae13df0f
commit
78b24ae2ac
5 changed files with 206 additions and 2 deletions
|
|
@ -82,6 +82,8 @@ Guest UI (App) <--PostMessageTransport--> Host (AppBridge) <--MCP Client--> MCP
|
|||
|
||||
JSDoc `@example` tags use `{@includeCode ./file.examples.ts#regionName}` to pull in type-checked code from companion `.examples.ts`/`.examples.tsx` files. Regions are marked with `//#region name` and `//#endregion name`, wrapped in functions (whose parameters provide types for external values). Region names follow `exportedName_variant` or `ClassName_methodName_variant` pattern (e.g., `useApp_basicUsage`, `App_hostCapabilities_checkAfterConnection`).
|
||||
|
||||
Standalone docs in `docs/` (listed in `typedoc.config.mjs` `projectDocuments`) can also have type-checked companion `.ts` files using the same `@includeCode` pattern.
|
||||
|
||||
## Full Examples
|
||||
|
||||
Uses npm workspaces. Full examples in `examples/` are separate packages:
|
||||
|
|
|
|||
69
docs/patterns.md
Normal file
69
docs/patterns.md
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
title: Patterns
|
||||
---
|
||||
|
||||
# MCP Apps Patterns
|
||||
|
||||
This document covers common patterns and recipes for building MCP Apps.
|
||||
|
||||
## [TODO] Tools that are private to Apps
|
||||
|
||||
Use `Tool._meta.ui.visibility: ["apps"]` to make tools only visible to Apps.
|
||||
|
||||
{@includeCode ./patterns.ts#privateTools}
|
||||
|
||||
## [TODO] Authenticated calls from App
|
||||
|
||||
- Use tool calls / read resources
|
||||
- See [PDF example](https://github.com/modelcontextprotocol/ext-apps/blob/main/examples/pdf-viewer) to read binaries by chunks to avoid call tool size limitations on platforms like claude.ai
|
||||
- Pass auth token in `_meta` (will be loaded again in the future) + refresh token + store in local storage (see Persist data section below)
|
||||
|
||||
{@includeCode ./patterns.ts#authenticatedCalls}
|
||||
|
||||
## [TODO] Giving errors back to model
|
||||
|
||||
- Before app runs: validate inputs in tool call
|
||||
- After it runs: use `updateModelContext`
|
||||
|
||||
{@includeCode ./patterns.ts#errorsToModel}
|
||||
|
||||
## [TODO] Support native host styling / use CSS variables
|
||||
|
||||
{@includeCode ./patterns.ts#hostStyling}
|
||||
|
||||
## [TODO] Reacting to light/dark theme changes
|
||||
|
||||
{@includeCode ./patterns.ts#lightDarkTheme}
|
||||
|
||||
## [TODO] Support fullscreen / exit fullscreen
|
||||
|
||||
{@includeCode ./patterns.ts#fullscreen}
|
||||
|
||||
## [TODO] Persist data (incl. widget state)
|
||||
|
||||
- Note: OAI's `window.openai.setWidgetState({modelContent, privateContent, imageIds})` has only a partial equivalent in the MCP Apps spec (for now!): `App.updateModelContext({content, structuredContent})`
|
||||
- For data persistence / to reload when conversation is reloaded, you must use localStorage / IndexedDb with `hostInfo.toolInfo.id` as key returned `CallToolResult._meta.widgetUUID = randomUUID()`
|
||||
|
||||
{@includeCode ./patterns.ts#persistData}
|
||||
|
||||
## [TODO] Lower perceived latency / manage loading time
|
||||
|
||||
Leverage partial inputs to show widgets as possible.
|
||||
|
||||
Beware of partial JSON being partial (but healed), so some of your objects may not be complete (e.g. in a list you may need to skip the last item if your code validates input schemas strictly).
|
||||
|
||||
{@includeCode ./patterns.ts#lowerPerceivedLatency}
|
||||
|
||||
## [TODO] Supporting both iframe & MCP Apps in same binary
|
||||
|
||||
See recipe: https://github.com/modelcontextprotocol/ext-apps/issues/34
|
||||
|
||||
{@includeCode ./patterns.ts#iframeAndMcpApps}
|
||||
|
||||
## [TODO] Migrating from OpenAI to MCP Apps
|
||||
|
||||
See [OpenAI -> MCP Apps](https://docs.google.com/document/d/13ROImOR9B8xc32yhqsFyC9Hh3_H63JFORDIyjyIPcU4/edit) migration guide.
|
||||
|
||||
Also: [Managing State](https://platform.openai.com/docs/actions/managing-state) (OpenAI)
|
||||
|
||||
{@includeCode ./patterns.ts#migrateFromOpenai}
|
||||
133
docs/patterns.ts
Normal file
133
docs/patterns.ts
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* Type-checked code examples for the patterns documentation.
|
||||
*
|
||||
* These examples are included in {@link ./patterns.md} via `@includeCode` tags.
|
||||
* Each function's region markers define the code snippet that appears in the docs.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
import { App } from "../src/app.js";
|
||||
|
||||
// TODO: Add imports as patterns are implemented
|
||||
|
||||
/**
|
||||
* Example: Tools that are private to Apps
|
||||
*/
|
||||
function privateTools() {
|
||||
//#region privateTools
|
||||
// TODO: Tool._meta.ui.visibility: ["apps"]
|
||||
//#endregion privateTools
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Authenticated calls from App
|
||||
*/
|
||||
function authenticatedCalls(app: App) {
|
||||
//#region authenticatedCalls
|
||||
// TODO: Use tool calls / read resources
|
||||
// See PDF example to read binaries by chunks
|
||||
// Pass auth token in _meta + refresh token + store in local storage
|
||||
//#endregion authenticatedCalls
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Giving errors back to model
|
||||
*/
|
||||
function errorsToModel(app: App) {
|
||||
//#region errorsToModel
|
||||
// Before app runs: validate inputs in tool call
|
||||
// After it runs: updateModelContext
|
||||
// TODO: Complete implementation
|
||||
//#endregion errorsToModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Support native host styling / use CSS variables
|
||||
*/
|
||||
function hostStyling() {
|
||||
//#region hostStyling
|
||||
// TODO: Implement host styling support via CSS variables
|
||||
//#endregion hostStyling
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Reacting to light/dark theme changes
|
||||
*/
|
||||
function lightDarkTheme(app: App) {
|
||||
//#region lightDarkTheme
|
||||
const applyTheme = (theme: string) => {
|
||||
document.documentElement.dataset.theme = theme;
|
||||
};
|
||||
|
||||
applyTheme(app.getHostContext()?.theme ?? "light");
|
||||
app.onhostcontextchanged = (params) => {
|
||||
if (params.theme) applyTheme(params.theme);
|
||||
};
|
||||
//#endregion lightDarkTheme
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Support fullscreen / exit fullscreen
|
||||
*/
|
||||
function fullscreen() {
|
||||
//#region fullscreen
|
||||
// TODO: Implement fullscreen support
|
||||
//#endregion fullscreen
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Persist data (incl. widget state)
|
||||
*/
|
||||
function persistData(app: App) {
|
||||
//#region persistData
|
||||
// Note: OAI's window.openai.setWidgetState({modelContent, privateContent, imageIds})
|
||||
// has only a partial equivalent in MCP Apps: App.updateModelContext({content, structuredContent})
|
||||
// For data persistence / to reload when conversation is reloaded,
|
||||
// use localStorage / IndexedDb with hostInfo.toolInfo.id as key
|
||||
// returned CallToolResult._meta.widgetUUID = randomUUID()
|
||||
// TODO: Complete implementation
|
||||
//#endregion persistData
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Lower perceived latency / manage loading time
|
||||
*/
|
||||
function lowerPerceivedLatency(app: App) {
|
||||
//#region lowerPerceivedLatency
|
||||
// TODO: Leverage partial inputs to show widgets as possible.
|
||||
// Beware of partial JSON being partial (but healed),
|
||||
// so some objects may not be complete.
|
||||
//#endregion lowerPerceivedLatency
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Supporting both iframe & MCP Apps in same binary
|
||||
*/
|
||||
function iframeAndMcpApps() {
|
||||
//#region iframeAndMcpApps
|
||||
// TODO: See recipe: https://github.com/modelcontextprotocol/ext-apps/issues/34
|
||||
//#endregion iframeAndMcpApps
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Migrating from OpenAI to MCP Apps
|
||||
*/
|
||||
function migrateFromOpenai() {
|
||||
//#region migrateFromOpenai
|
||||
// TODO: See OpenAI -> MCP Apps migration guide
|
||||
// https://docs.google.com/document/d/13ROImOR9B8xc32yhqsFyC9Hh3_H63JFORDIyjyIPcU4/edit
|
||||
//#endregion migrateFromOpenai
|
||||
}
|
||||
|
||||
// Suppress unused variable warnings
|
||||
void privateTools;
|
||||
void authenticatedCalls;
|
||||
void errorsToModel;
|
||||
void hostStyling;
|
||||
void lightDarkTheme;
|
||||
void fullscreen;
|
||||
void persistData;
|
||||
void lowerPerceivedLatency;
|
||||
void iframeAndMcpApps;
|
||||
void migrateFromOpenai;
|
||||
|
|
@ -15,6 +15,6 @@
|
|||
"skipLibCheck": true,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx", "docs/**/*.ts"],
|
||||
"exclude": ["node_modules", "dist", "examples/**/*.ts"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { OptionDefaults } from "typedoc";
|
|||
const config = {
|
||||
blockTags: [...OptionDefaults.blockTags, "@description"],
|
||||
intentionallyNotExported: ["AppOptions"],
|
||||
projectDocuments: ["docs/quickstart.md"],
|
||||
projectDocuments: ["docs/quickstart.md", "docs/patterns.md"],
|
||||
entryPoints: [
|
||||
"src/server/index.ts",
|
||||
"src/app.ts",
|
||||
|
|
|
|||
Loading…
Reference in a new issue