* feat(basic-host): add theme toggle and MCP style variables
Add theme support to basic-host example:
- theme.ts: Global theme manager with light/dark toggle
- host-styles.ts: Full set of MCP CSS variables using light-dark()
- ThemeToggle component with sun/moon icons
- Theme-aware CSS using CSS custom properties
- Pass theme + styles to apps via hostContext
- Notify apps when theme changes via sendHostContextChange
Apps now receive:
- hostContext.theme: 'light' | 'dark'
- hostContext.styles.variables: All 60+ MCP CSS variables
- onhostcontextchanged notifications when theme changes
* test: update e2e goldens for theme changes
* fix(say-server): add --index flag to uv run for PyPI resolution
The pocket-tts dependency wasn't resolving without explicit --index flag
when invoked via npm scripts.
* fix(qr-server): allow Docker bridge IP in transport security
Add 172.17.0.1:* to allowed_hosts to fix 421 Misdirected Request errors
when the server is accessed from Docker containers.
* feat(server): add hasUiSupport/getUiCapability for experimental+extensions
Support double-tagging for MCP Apps capability negotiation:
- Check both experimental and extensions fields in client capabilities
- Add hasUiSupport() to easily check if client supports MCP Apps
- Add getUiCapability() to retrieve the capability settings
- Update spec to document both capability locations
This enables forward compatibility as MCP transitions from experimental
to the extensions field (SEP-1724).
Claude-Generated-By: Claude Code (cli/claude-opus-4-5=100%)
Claude-Steers: 0
Claude-Permission-Prompts: 0
Claude-Escapes: 0
* fix: update @types/node version in package-lock.json
Replace invalid 22.19.5/22.19.6/22.19.7 versions with valid 22.19.3
* docs(spec): clarify hosts SHOULD double-tag, servers SHOULD check both
- Hosts SHOULD advertise capabilities in both experimental and extensions
- Servers SHOULD check both locations, preferring extensions when present
- Updated example to show double-tagging pattern
* chore: remove double-tagging recommendation, keep hasUiSupport helper
Reverts the spec changes that recommended clients double-tag capabilities
in both experimental and extensions fields. The helper functions remain
as they're useful for checking capability in either location.
* refactor(server): simplify to only getUiCapability, remove hasUiSupport
- Remove hasUiSupport function (use getUiCapability directly)
- Remove double-tagging logic (only check extensions field)
- Add ClientCapabilitiesWithExtensions type using SDK's ClientCapabilities
- Update spec to use getUiCapability
- Simplify tests
* fix: update @see link to getUiCapability
* refactor(server): inline ClientCapabilitiesWithExtensions type in getUiCapability
* refactor: move McpUiClientCapabilities to spec.types.ts
* fix(test): update map-server test to expect 'CesiumJS Map Server'
The server name was renamed but the E2E test config was not updated.
* fix: change in another file
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Olivier Chafik <ochafik@anthropic.com>
Migrate JSDoc and markdown documentation from `{@includeCode ./file#region}`
tags to inline code fences with `source="./file#region"` attributes.
Code examples are now visible directly in source files while remaining
type-checked via their `.examples.ts` source files.
Add `scripts/sync-snippets.ts` to extract code from `//#region` blocks
and sync it into labeled fences. Run with `npm run sync:snippets`.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Update spec: drop Intents reference, rename Notify to Log
- Remove "intent" from the list of MCP-UI message types in the rationale
section (Intents concept is being dropped)
- Rename "Notify" to "Log" in the lifecycle diagram to better reflect
that notifications/message is for debugging/telemetry logging, not
for sending messages to the chat (which is now ui/message)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* spec: remove Intents reference from rationale
Remove 'intent' from the list of MCP-UI message types - Intents concept was dropped in earlier discussions.
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat(examples): add debug-server example
A comprehensive debug/development server for testing MCP Apps SDK features:
- Vanilla TypeScript UI with collapsible panels
- Message visualization (sent, received, errors)
- Server tool calling interface
- Multiple tool endpoints for testing
* refactor(debug-server): convert to React
- Replace vanilla TypeScript with React components
- Add comprehensive Host Styles panel showing all CSS variables grouped by category
- Use React hooks (useApp, useHostStyles, useAutoResize)
- Cleaner state management with useReducer for event log
- Collapsible sections for better organization
- CSS modules for scoped styling
* fix(debug-server): correct server name in main.ts
* Revert "refactor(debug-server): convert to React"
This reverts commit 5d22d2daa9a98ba412892447202ef10fbdb62f5b.
* fix(debug-server): update default values for multipleBlocks and includeMeta
* fix(debug-server): correct serve script and server name
- serve script now runs main.ts instead of server.ts
- Updated server name to 'Debug Server'
- Fixed npx command in comment
* fix: increase maxHeight to 6000px and add tools capability to debug app
- basic-host: Increase maxHeight from 600 to 6000px
- debug-server: Add tools capability to enable oncalltool/onlisttools handlers
* fix(debug-server): use consistent callback names for event tracking
Event types now match callback names (ontoolinput, ontoolresult, etc.)
so the Callback Status panel shows correct counts and payloads.
* feat(debug-server): add Update (Image) button for model context
* feat(debug-server): add expandable event log entries
- Click on any event log row to expand/collapse
- Arrow indicator rotates when expanded
- Full JSON payload shown indented in pre block
- Max height with scroll for large payloads
* style(debug-server): format long line in fullPayload function
* test(debug-server): add to E2E tests and screenshot specs
* chore: regenerate package-lock.json for cross-platform compatibility
* update dep
* fix(map-server): simplify location update message format
* fix(say-server): pass host to streamable_http_app for non-localhost deployments
* refactor(pdf-server): simplify to stateless range-query architecture
- Remove caching/indexing in favor of direct HTTP Range requests
- Use HEAD requests to get file size (no full download)
- Use Range requests to proxy byte chunks (no caching)
- Local files: fs.read with offset/length
- Remote files: HTTP Range header
- Zero memory footprint (no PDF caching)
- Truly stateless (no session management needed)
- Single server.ts (~350 lines) + main.ts CLI entry point
- Instant startup (no preloading)
- Security: whitelist local files, allowed origins
Removed files:
- src/pdf-indexer.ts
- src/pdf-loader.ts
- src/types.ts
* feat(pdf-server): add dark mode support
- Add CSS variables with light-dark() function for automatic theme switching
- Sync theme with host via applyDocumentTheme()
- Apply host CSS variables via applyHostStyleVariables()
* feat(pdf-server): add list_pdfs tool back
Lists local files and allowed remote origins.
Also moves CHUNK_SIZE to module level constant.
* feat(pdf-server): improve tool descriptions and increase context limit
- display_pdf: list all allowed domains in description
- Increase MAX_MODEL_CONTEXT_LENGTH to 15000
- Move CHUNK_SIZE to module level constant
* chore(say-server): remove deployment docs from repo
Keep server.py fix for non-localhost deployments.
Deployment docs kept locally but not in repo.
* refactor(pdf-server): simplify updateModelContext format
- Add widget ID for multi-widget disambiguation
- Use concise header: 'PDF viewer (id) | title | Current Page: X/Y'
- Add 'Page content:' prefix before text
- Keep selection markers (<pdf-selection>...</pdf-selection>)
* refactor: rename widgetUUID to viewUUID for consistency
Aligns with main's standardization on 'view' terminology (PR #325).
Also dynamically generate allowed domains in display_pdf description.
* viewUUID
* fix(map-server): fix syntax error in location update message
* fix(pdf-server): restore package.json, improve server docs
- Restore --external pdfjs-dist in build
- Rewrite server.ts header for newcomers (list tools, not implementation details)
- Minimize main.ts diff
* chore(pdf-server): remove unused addAllowedOrigin/addAllowedLocalFile
* docs(pdf-server): update README for new architecture
* docs(pdf-server): restore full README, add theming section, remove get_pdf_info
* rm
* fix(pdf-server): restore createMcpExpressApp and error handling
- Use createMcpExpressApp for DNS rebinding protection
- Restore error callback in app.listen()
* fix(say-server): pass host to streamable_http_app for non-localhost deployments
* chore(say-server): remove deployment docs from repo
* widgetId->tool id
* fix(map-server): add null check for center in location update
chore(pdf-server): dedupe and sort allowed origins
* fix(map-server): use transparent background for rounded corners
* prettier
* docs: standardize UI terminology to use "view" consistently
Replaces "widget" and "Guest UI" terminology with "view" across
the codebase as decided in the community survey.
This change updates:
- Specification document
- SDK source code and JSDoc comments
- Example servers and documentation
- Plugin documentation and skills
Closes#71
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add explicit backtick-wrapped display text to all `{@link}` tags for
monospace rendering in TypeDoc output. This improves readability by:
- Using monospace font for code references (types, methods, functions)
- Stripping module prefixes from display text (e.g., `app!App.connect`
displays as `App.connect`)
Updated files across the SDK including `App`, `AppBridge`,
`PostMessageTransport`, React hooks, server helpers, types, and
documentation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Configure TypeDoc to use the GitHub-styled theme for better visual
consistency with the project's GitHub presence. Also reorganize the
config options and enable group navigation for improved documentation
structure.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(qr-server): embed widget HTML for self-contained usage
Embed the widget HTML directly in server.py following the same pattern
as the say-server. This allows the QR server to be run without any
local file dependencies using `uv run <url>`.
The get_widget_html() function prefers the built version from dist/
for local development but falls back to the embedded HTML for unbundled
usage.
* refactor(qr-server): remove widget.html and simplify embedded HTML
Address PR review feedback:
- Remove separate widget.html file (no longer needed)
- Remove get_widget_html() function and dist/mcp-app.html reference
- Inline EMBEDDED_WIDGET_HTML directly in widget() resource
- Remove unused Path import
The server is now fully self-contained in a single file.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Update the spec to clarify that:
- ui.domain format and validation rules are host-dependent
- Servers must consult host-specific documentation for expected format
- Common patterns: hash-based subdomains, URL-derived subdomains
- Updated examples to reflect realistic host-controlled domains
This addresses the gap between the spec's previous implied flexibility
(arbitrary domains like weather-widget.example.com) and real-world
constraints where hosts must control sandbox domains for security.
Each pattern section now includes a "See examples/..." link pointing
to a working implementation in the repository. This helps readers
quickly find real code demonstrating each pattern.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
Add `IntersectionObserver` pattern for pausing expensive operations
(animations, WebGL, polling) when widgets scroll out of view.
- Add `visibilityBasedPause` example to `patterns.tsx` with play/pause
callbacks and `onteardown` cleanup
- Document pattern in `patterns.md` with link to MDN docs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replaces the TODO stub with complete server-side and client-side examples
based on the `pdf-server` implementation pattern:
- Server: shows returning `widgetUUID` via `CallToolResult._meta`
- Client: shows receiving UUID via `ontoolresult`, using it as localStorage
key with generic `saveState<T>()` / `loadState<T>()` helpers
Also clarifies the distinction between widget state persistence (UI state
surviving page reloads) and `updateModelContext()` (model-visible state).
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>
Merge the separate "Support native host styling using CSS variables" and
"Reacting to light/dark theme changes" sections into a single "Matching
host styling (CSS variables, theme, and fonts)" pattern. This provides
clearer guidance by covering all three concerns together.
- Rename `docs/patterns.ts` to `docs/patterns.tsx` for JSX support
- Add `hostStylingVanillaJs` and `hostStylingReact` consolidated examples
- Enhance `applyHostFonts_fromHostContext` to apply initial fonts after
`connect()`, not just on context change
- Add CSS usage examples to `applyHostStyleVariables()` JSDoc
- Update font example to use `var(--font-sans, system-ui, sans-serif)`
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reference existing JSDoc examples instead of maintaining a separate one in
`docs/patterns.ts`:
- Vanilla JS: `applyDocumentTheme_fromHostContext` from `styles.examples.ts`
- React: `useDocumentTheme_conditionalRender` for reactive theme reading
Expand `applyDocumentTheme_fromHostContext` example to show both the
`onhostcontextchanged` handler and initial theme application after `connect()`.
Note in the docs that `useHostStyles()` applies theme automatically, so React
apps don't need additional setup unless they want to read the theme reactively
for conditional rendering.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
References existing type-checked examples instead of a stub:
- Vanilla JS: `applyHostStyleVariables_fromHostContext` from `src/styles.examples.ts`
- React: `useHostStyles_basicUsage` from `src/react/useHostStyles.examples.tsx`
Expanded `applyHostStyleVariables_fromHostContext` to show the full pattern:
using CSS variables in styles, applying on `onhostcontextchanged`, and
applying initial styles after `connect()`.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document the `_meta.ui.visibility: ["app"]` feature in `docs/patterns.md`
by referencing the existing type-checked example from
`src/server/index.examples.ts#registerAppTool_toolVisibility`.
- Fix typo: `["apps"]` → `["app"]` (singular)
- Remove placeholder function from `docs/patterns.ts`
- Expand description to explain use cases
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
After commit 65a62a9f, the server startup code was moved from server.ts
to main.ts, but the serve:http script was not updated accordingly.
This caused 9 example servers to fail to start when running npm start:
- budget-allocator-server
- cohort-heatmap-server
- customer-segmentation-server
- integration-server
- map-server
- scenario-modeler-server
- system-monitor-server
- threejs-server
- wiki-explorer-server
The server.ts file now only exports createServer(), while main.ts
contains the actual server startup logic.
This enables users to install the `mcp-apps` plugin via:
/plugin marketplace add modelcontextprotocol/ext-apps
/plugin install mcp-apps@modelcontextprotocol-ext-apps
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>
Relative directory links like `](examples/map-server)` caused TypeDoc
warnings ("relative path is not a file") and resulted in broken links
in the generated API documentation. Converted all 20 example directory
links to full GitHub URLs while keeping image paths relative.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>