Add new pattern showing how to combine `updateModelContext()` with
`sendMessage()` when data exceeds message size limits. The example
demonstrates offloading a large transcript to model context first,
then sending a brief trigger message.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Documents `updateModelContext` for keeping the model informed about user
interactions. The example shows a shopping cart use case with YAML frontmatter
for structured, parseable context.
Also refines the `updateModelContext` JSDoc to clarify the difference from
`sendMessage` and removes the `structuredContent` example.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds JSDoc example `App_updateModelContext_reportError` showing how to
report runtime errors (e.g., microphone permission denied) back to the
model using `updateModelContext`.
Updates patterns.md with clearer framing:
- Server-side (tool handler): return `{ isError: true, ... }`
- Client-side (app): use `updateModelContext` for runtime errors
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Expand `App_ontoolinputpartial_progressiveRendering` example in
`app.examples.ts` to show full state management pattern with
`toolInputs` and `toolInputsPartial` variables
- Add healed JSON caveat to `ontoolinputpartial` JSDoc in `app.ts`
- Update `patterns.md` to reference the expanded example and document
the streaming preview pattern
- Remove empty `lowerPerceivedLatency` placeholder from `patterns.tsx`
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add `App_onhostcontextchanged_respondToDisplayMode` example showing how to
listen for display mode changes and update UI with `classList.toggle()`.
Update `App_requestDisplayMode_fullscreen` to `App_requestDisplayMode_toggle`
to show the common toggle pattern checking `availableDisplayModes` first.
Refactor full examples (pdf-server, shadertoy-server) to use
`classList.toggle(class, condition)` instead of add/remove branches.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Follow-up to the examples extraction: pass dependencies as function
parameters instead of using global stub declarations, rename region
names to match method names (e.g., `AppBridge_guestCapabilities_*` →
`AppBridge_getAppCapabilities_*`), and simplify examples using optional
chaining.
Also clarifies `RESOURCE_URI_META_KEY` documentation to indicate it's
for tool definition metadata (from `tools/list`), not tool result
metadata, and removes the redundant `setNotificationHandler` example
in favor of the simpler event setter approach.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
Key improvements:
- Add `{@link}` cross-references throughout the codebase to make API
documentation navigable and help AI models understand relationships
- Use `{@link module!Export}` syntax for cross-module references
- Add backticks for inline code formatting (`ResizeObserver`, `App`, etc)
- Fix `PostMessageTransport` examples to show required two-argument form
- Clarify `onteardown` callback return type requirement
- Document React hooks cleanup behavior and Strict Mode considerations
- Add tool visibility example for `registerAppTool`
- Add CSP example for `registerAppResource`
- Fix notification direction documentation in `spec.types.ts`
TypeDoc config migrated from `typedoc.json` to `typedoc.config.mjs` to:
- Support custom `@description` block tag
- Add `intentionallyNotExported` for internal types
- Include `src/server/index.ts` entry point
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix(app): add source validation to default PostMessageTransport
App.connect() now passes window.parent as both eventTarget and eventSource,
enabling source validation by default. This ensures apps only accept
messages from their parent window, preventing potential cross-app
message spoofing attacks.
Previously, the default transport only specified the target but not the
source for validation, meaning apps would accept messages from ANY window.
* fix(sandbox): add origin validation for host messages
The sandbox proxy now validates that messages from the parent window
come from the expected host origin (derived from document.referrer).
This prevents malicious pages from sending spoofed messages to the sandbox.
Changes:
- Extract EXPECTED_HOST_ORIGIN from document.referrer
- Validate event.origin against expected origin for parent messages
- Use specific origin instead of '*' when sending to parent
- Reject and log messages from unexpected origins
This addresses the TODO comment that was previously in the code.
* validate messages from app come from same origin as sandbox proxy
* fix(basic-host): be resilient to individual server connection failures
Use Promise.allSettled instead of Promise.all when connecting to
servers, so that a single server failure doesn't crash the entire UI.
Failed connections are logged as warnings but the UI continues with
the servers that connected successfully.
Also fixes video-resource-server missing server-utils.ts.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: rename request methods to remove send prefix
Following the MCP TS SDK convention where request methods don't have
the "send" prefix (reserved for notifications):
- App.sendMessage() → App.message()
- App.sendOpenLink() → App.openLink()
- AppBridge.sendResourceTeardown() → AppBridge.resourceTeardown()
The old method names are kept as deprecated aliases for backwards
compatibility.
Updated all examples to use the new method names.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test: add tests for deprecated method aliases
- Update existing tests to use new method names (message, openLink)
- Add tests verifying deprecated aliases are same reference as new methods
- Add tests verifying deprecated aliases still work functionally
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: rename message→sendMessage, resourceTeardown→teardownResource
- App.message() → App.sendMessage() (with deprecated message alias)
- AppBridge.resourceTeardown() → AppBridge.teardownResource() (with deprecated aliases)
This better follows the pattern where methods that send data have 'send' or action verb prefix.
* fix: update examples to use sendMessage instead of message
* fix: update basic-host to use teardownResource
* fix: update threejs-server to use sendMessage
* refactor: remove deprecated app.message alias
The app.message alias was removed since sendMessage is the correct name.
sendResourceTeardown already exists in AppBridge.
* refactor: remove resourceTeardown alias, keep only sendResourceTeardown
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add server helpers and optional connect() transport
Add `src/server/` with convenience functions for registering MCP App tools
and resources:
- `registerAppTool(server, name, config, handler)`
- `registerAppResource(server, name, uri, config, callback)`
The `transport` parameter in `App.connect()` is now optional, defaulting to
`PostMessageTransport(window.parent)`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Update src/server/index.ts
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
* fix: refine server helper types
- Make RESOURCE_URI_META_KEY required in McpUiAppToolConfig (tools need a UI resource)
- Make _meta optional in McpUiAppResourceConfig (not all resources need custom metadata)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: simplify RESOURCE_URI_META_KEY re-export
* refactor: consolidate export statements
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
* Add setter-based handlers for MCP request/notification forwarding
- Add oncalltool, onlistresources, onlistresourcetemplates, onreadresource, onlistprompts setters for Guest UI → Host requests
- Add sendToolListChanged, sendResourceListChanged, sendPromptListChanged methods for Host → Guest UI notifications
- Refactor connect() to use new setters with inlined callbacks
- Update documentation to clarify optional client parameter behavior
- Remove unused forwardRequest/forwardNotification helper methods
- Add comprehensive tests for AppBridge without MCP client (manual handlers)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Potential fix for pull request finding 'Unused variable, import, function or class'
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
* fix: move prettier to dependencies for git-based installs
* fix: add explicit prettierrc to prevent inheriting parent configs during git-based installs
* Apply suggestions from code review
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
* refactor(tests): factor out test values and add missing assertions
Address PR review feedback:
- Factor out test value objects (toolCall, resultContent, etc.) for clearer tests
- Add missing assertions on receivedRequests[0] for list handlers
- Improve test readability by defining expected values at the top of each test
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* docs: improve TypeDoc formatting and use `as const` for notification methods
- Use proper TypeDoc syntax with `@param callback.params` and `@param callback.extra`
- Add {@link ResultType} references for return types
- Replace `as Notification` with `as const` on method literals where possible
(sendResourceListChanged, sendPromptListChanged)
- Simplify sendHostContextChange cast syntax
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor(types): use explicit type unions for AppBridge protocol types
- Add AppBridgeRequest, AppBridgeNotification, AppBridgeResult type unions
that explicitly list all valid types for the protocol
- Replace generic SDK Request/Notification/Result with our specific types
- Remove all type casts by using `as const` on method literals
- Add index signature to McpUiHostContext for forward compatibility
This improves type safety and documents exactly what the AppBridge supports.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: move AppRequest/AppNotification/AppResult to types.ts
Move protocol type unions from app-bridge.ts to types.ts where they
belong with other type definitions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: regenerate schemas with clean npm install
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
* feat: store and expose hostContext in App class
Fixes#129 - The App class now stores the initial hostContext received
during initialization and exposes it via getHostContext().
Changes:
- Add _hostContext private property to App class
- Store result.hostContext in connect() method
- Add getHostContext() getter method (parallel to getHostCapabilities())
- Update onhostcontextchanged setter to merge partial updates into
stored context
- Add default notification handler to update context even when
user hasn't set onhostcontextchanged
This enables apps to:
- Access toolInfo immediately after connection (only in initial context)
- Render with correct theme/locale without waiting for first notification
- Synchronously access viewport, timezone, and other initial state
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: use sendHostContextChange for partial update accumulation test
Address PR review feedback: The test was using setHostContext with full
context spreads which didn't clearly demonstrate partial update
accumulation. Now uses sendHostContextChange directly to send truly
partial updates (only theme, then only viewport), making it clear
the App correctly merges multiple partial notifications.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat: implement ui/notifications/tool-cancelled throughout SDK
Wire the tool-cancelled notification that hosts MUST send when tool
execution is cancelled (user action, timeout, classifier intervention, etc.):
- Add McpUiToolCancelledNotification type in spec.types.ts
- Generate Zod schema via ts-to-zod
- Add AppBridge.sendToolCancelled() method for hosts
- Add App.ontoolcancelled setter for guest UIs
- Export type and schema from types.ts
- Add tests for notification with/without reason
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: add App.onteardown handler for graceful shutdown
Wire the guest UI side of ui/resource-teardown request:
- Add onteardown setter in App class for guest UIs to handle teardown
- Allow ui/resource-teardown in assertRequestHandlerCapability
- Import McpUiResourceTeardownRequest/Result types
- Add tests for sync and async cleanup handlers
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat(example): wire tool-cancelled and teardown in basic-host
Update basic-host example to properly use the new notifications:
- Send sendToolCancelled when tool call promise rejects
- Send sendResourceTeardown when React component unmounts
- Store appBridge ref for cleanup access
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(example): implement graceful teardown per spec recommendation
Address review feedback: the host now waits for guest's teardown
response before unmounting, following the spec: "Host SHOULD wait
for a response before tearing down the resource (to prevent data loss)."
Changes:
- Add close button to tool call panels
- Two-phase unmount: isDestroying state dims panel and disables events
- sendResourceTeardown() completes before component removal
- Non-app tool results close immediately
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat(examples): add onteardown handlers to demo apps
Demonstrate graceful shutdown with simulated 500ms cleanup work.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
- Fix RESOURCE_MIME_TYPE to match spec: "text/html;profile=mcp-app"
- Add CSP field to McpUiSandboxResourceReadyNotification type and schema
- Update basic-host to extract and pass CSP metadata from resources
- Update sandbox.ts to dynamically inject CSP meta tag into inner iframe
- Remove static CSP from sandbox.html (now dynamic based on resource metadata)
- Update QR server to use custom read_resource handler for _meta injection
- Update requirements.txt to require mcp[cli]>=1.23.3
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
The host implementation has been fixed to return the correct result
format, so this workaround is no longer needed.
Reverts the hack added in #82.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
* Fix compatibility with @modelcontextprotocol/sdk 1.23+
Implement required abstract methods `assertTaskCapability` and
`assertTaskHandlerCapability` in App and AppBridge classes. These
were added to the Protocol base class in SDK 1.23+.
Also regenerates package-lock.json with valid npm registry versions
(previously had non-existent vite@6.4.1).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add pkg-pr-new workflow for PR/commit publishing
Enables automatic publishing of any commit or PR to pkg.pr.new,
allowing consumers to install directly from git commits:
npm install https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/ext-apps@<commit-or-pr>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Some host implementations incorrectly return the full JSON-RPC envelope
(with result, jsonrpc, id fields) instead of just the unwrapped result.
This causes apps using callServerTool() to fail when accessing result.content.
This fix detects wrapped responses and unwraps them automatically.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The previous approach measured html/body elements which expand to fill
the viewport, causing the iframe to be larger than necessary.
Fix by using CSS fit-content to measure the true minimum content size:
- Temporarily set html to fit-content to shrink it to content
- This automatically includes body margins
- Cache last sent size to prevent feedback loops from style changes
- Simplify scrollbar compensation (already 0 when no scrollbar)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
Compensate for viewport scrollbar width in size change notifications.
On Linux/Windows, scrollbars consume space from the content area, causing
a feedback loop where the iframe progressively shrinks to zero.
- Use window.innerWidth - clientWidth to detect scrollbar width
- Use max of getBoundingClientRect (CSS transforms) and scroll dimensions
(content overflow) to report accurate size
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
* Refactor types.ts to use explicit interfaces with JSDoc
Replace z.infer<typeof Schema> patterns with explicit interface
definitions for all MCP UI types. Add VerifySchemaMatches helper
type to ensure compile-time verification that schemas match their
interfaces.
Add comprehensive JSDoc documentation to all exported types including:
- Clear descriptions of purpose and usage
- @see references to related types and methods
- Code examples where helpful
- @internal markers for implementation details
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add JSDoc documentation and TypeDoc tooling
Add comprehensive JSDoc documentation to:
- AppBridge class and all methods
- App class and all methods
- PostMessageTransport class and callbacks
- React hooks (useApp, useAutoResize)
- React module index
Set up TypeDoc for API documentation generation:
- Add typedoc.json configuration
- Add docs and docs:watch npm scripts
- Add typedoc dev dependency
- Update .gitignore to exclude generated docs
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add JSDoc documentation for callback handler setters
Document all notification and request handler setters in AppBridge
and App classes with comprehensive JSDoc comments including:
- Clear descriptions of when handlers are called
- Parameter documentation and types
- Practical code examples with error handling
- Cross-references to related types and methods
- Security considerations where relevant
Also update types.ts to document optional isError fields in result
types and make McpUiInitializedNotification params optional.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add JSDoc for new App methods and fix result type compatibility
Document new public APIs introduced in merge commit 74a7b1f:
- getHostCapabilities() - getter for host capabilities after connect
- getHostVersion() - getter for host implementation info after connect
- oncalltool setter - convenience handler for tool call requests
- onlisttools setter - convenience handler for tool listing requests
- RESOURCE_URI_META_KEY constant - metadata key for resource URIs
Add index signatures to McpUiMessageResult and McpUiOpenLinkResult
for MCP SDK Protocol class compatibility, matching the existing
pattern in McpUiInitializeResult.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add comprehensive JSDoc documentation across library
- Document App methods with detailed descriptions and examples
- Add JSDoc to AppBridge methods including getters and setters
- Document PostMessageTransport callback properties
- Improve React hook documentation (useApp, useAutoResize)
- Add documentation for types.ts result and notification types
- Add @see cross-references between related methods
- Fix code examples to use correct syntax and patterns
- Clarify error handling behavior in method descriptions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix TypeDoc cross-module link resolution warnings
Replace unqualified @link references with module-qualified syntax to fix
"Failed to resolve link" warnings during docs generation. TypeDoc cannot
resolve links like {@link App.sendOpenLink} without imports, so use the
module-qualified format {@link app.App.sendOpenLink} instead.
Changes:
- types.ts: Fix 9 cross-module links to App and AppBridge methods
- app-bridge.ts: Fix 2 references to App.sendSizeChange
- message-transport.ts: Fix 2 references to App.connect and AppBridge.connect
This eliminates all "Failed to resolve link" warnings without requiring
circular imports or removing documentation cross-references.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Remove TypeDoc links to undocumented external types
Remove @link references to types that are either:
- Not exported (AppOptions) - internal implementation detail
- From external packages (@modelcontextprotocol/sdk) - not included in docs
This eliminates warnings about resolved but undocumented types. The type
information is still available through TypeScript's type system and parameter
documentation, but without broken links in the generated documentation.
Removed links to:
- AppOptions (internal type)
- Implementation, CallToolRequest, CallToolResult (MCP SDK types)
- ListToolsRequest, LoggingMessageNotification (MCP SDK types)
Reduces warnings from 12 to 4 (remaining are about missing example files).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Bump @modelcontextprotocol/sdk to ^1.23.0
Update SDK dependency to fix CI build failures caused by version
mismatch. CI was installing 1.23.0 (latest compatible with ^1.22.0)
while local builds used 1.22.0.
Note: package-lock.json is gitignored, which prevents reproducible
builds. Consider committing it to ensure CI uses the same versions
as local development.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix Zod type compatibility with @modelcontextprotocol/sdk
The SDK imports Zod from 'zod/v4' while this package imported from
'zod'. Although both resolve to the same version (3.25.x), TypeScript
sees them as separate modules with incompatible type declarations.
This caused type errors when:
- Extending SDK schemas like RequestSchema.extend()
- Passing SDK schemas to setRequestHandler/setNotificationHandler
- Using ZodObject/ZodLiteral types from different import paths
Changes:
- Import zod from 'zod/v4' to match SDK import path
- Update z.record() calls to use Zod v4 signature (requires both
key and value schemas)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add GitHub Actions workflow to deploy docs to gh-pages
Adds a workflow with manual trigger (workflow_dispatch) that generates
TypeDoc documentation and publishes it to the gh-pages branch using
peaceiris/actions-gh-pages.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add docs index.html redirect to API documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Revise README for clarity and audience focus
- Add API documentation badge linking to GitHub Pages
- Reorganize content around two audiences: App Developers and Host Developers
- Convert relative links to absolute GitHub URLs for better portability
- Simplify installation and examples sections
- Add Resources section with links to docs, spec, and discussion
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Update src/app-bridge.ts
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Olivier Chafik <ochafik@anthropic.com>