The override pinning @hono/node-server to 1.19.7 was added in 71976101
as a workaround when @modelcontextprotocol/sdk 1.25.3 required ^1.19.9,
which did not yet exist on the public npm registry.
That constraint is now obsolete: the SDK is pinned to 1.25.2 (requires
^1.19.7), and 1.19.8-1.19.11 have since been published. Removing the
override lets npm naturally resolve 1.19.11, which includes the fix for
the HIGH-severity auth bypass in the Serve Static middleware
(GHSA-wc8c-qw6v-h7f6, fixed in 1.19.10).
Lockfile regenerated against registry.npmjs.org (no artifactory URLs).
- Switch npm install -> npm ci in ci.yml (build, build-wsl) and docs.yml
to fail on lockfile drift rather than silently tolerating it
- Add cache: npm to all setup-node steps that have a lockfile to hash
(skipped test-git-install which has no checkout, and WSL which has no
setup-node action)
- Add TypeDoc link validation step after build (Linux x64 only, matching
existing single-OS gate pattern for MCPB). Verified passing on main.
- Align all workflows on Node 22 (active LTS) — previously CI used 20
but publish workflows used 22, so releases were tested on a different
Node than PRs
- Add engines.node >=20 to package.json so consumers on Node 18 get a
warning
Bug 1: generate-grid-screenshots.spec.ts was running on every CI E2E
invocation because playwright.config.ts had no testIgnore. This spec
writes examples/*/grid-cell.png as a side effect — it's meant to be
invoked only via npm run generate:screenshots.
Added testIgnore gated on GENERATE_SCREENSHOTS env var (Playwright's
testIgnore is stronger than explicit CLI file args, so a plain ignore
would break generate:screenshots). Passed the env var through the
docker invocation in generate:screenshots.
Before: npx playwright test --list → 82 tests in 3 files
After: npx playwright test --list → 65 tests in 2 files
GENERATE_SCREENSHOTS=1 ... --list → 17 tests in 1 file (still works)
Bug 2: examples/pdf-server/server.test.ts (448 LOC, 34 tests) was
never run — root script was 'bun test src'. Changed to 'bun test src
examples'. Only one .test. file exists in examples/ so no noise.
Before: npm test → 87 pass across 3 files
After: npm test → 121 pass across 4 files
* Replace platform-specific optionalDependencies with bun devDependency
Fixes#222. The bun meta-package handles platform detection internally.
Rollup resolves its own platform binaries transitively. Removes ~400MB
of bloat for SDK consumers. Simplifies setup-bun.mjs accordingly.
* Remove setup-bun.mjs, simplify prepare script
No longer needed since the bun npm package handles binary
installation and PATH registration automatically.
* chore: bump ext-apps to 1.1.2
Changes since 1.1.1:
- feat: add ui/download-file method for host-mediated file downloads (#475)
- pdf-server: robust path validation + folder/file root support (#497)
- ci: auto-fix prettier formatting in pre-commit hook and CI (#498)
* fix: sync local SDK build into node_modules for examples
npm workspaces hoists example dependencies to the root node_modules,
but installs the published registry copy of @modelcontextprotocol/ext-apps
instead of linking to the local source. This causes type-check failures
when examples use features not yet published to npm.
Add scripts/link-self.mjs which copies the freshly-built dist/ and
package.json into the hoisted node_modules copy after each SDK build,
ensuring examples always type-check against the latest local types.
See: https://github.com/npm/feedback/discussions/774
* Revert "fix: sync local SDK build into node_modules for examples"
This reverts commit e3387e8434f3def030f5a223a70632092c929119.
npm workspaces hoists example dependencies to the root node_modules,
but installs the published registry copy of @modelcontextprotocol/ext-apps
instead of linking to the local source. This causes type-check failures
when examples use features not yet published to npm.
Add scripts/link-self.mjs which copies the freshly-built dist/ and
package.json into the hoisted node_modules copy after each SDK build,
ensuring examples always type-check against the latest local types.
See: https://github.com/npm/feedback/discussions/774
Bug fixes / improvements since 1.1.0:
- fix: add audio/video support for basic-host (#460)
- fix(pdf-server): remove page-loading overlay (#493)
- pdf-server: remove domain allowlist, require HTTPS only (#487)
- Set audioSession.type to playback in sheet music app (#489)
- Add MCPB packaging and Claude Code plugin for pdf-server (#491)
* chore: bump ext-apps to 1.1.0
Features:
- registerAppResource now returns the registered resource (#370)
- Accept UIResourceMeta in both resources/list and resources/read (#410)
- callServerTool throws helpful error when called with a string (#449)
- Add double-connect guard to prevent protocol message handling errors (#450)
Bug fixes:
- Only ignore messages that lack jsonrpc 2.0 in message-transport (#448)
- Align basic-host dark mode styles (#438)
Spec:
- Change Host <> Sandbox communication protocol to SHOULD (#435)
- Clarify UIResourceMeta in both list and read responses (#410)
* fix(debug-server): add missing npm package config (main, bin, types, exports)
Align debug-server package.json with all other server examples:
- main: dist/server.js (was server.ts)
- types: dist/server.d.ts
- bin: mcp-server-debug -> dist/index.js
- exports with types
- files: only dist (remove source server.ts)
v0.4.0 includes the typography fixes from upstream PR
JulianWowra/typedoc-github-theme#7, so the local `customCss` override
(`scripts/typedoc-github-theme-fixes.css`) added in 0bbbfee is no
longer needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: bump ext-apps to 1.0.1
* chore: update examples to depend on ext-apps ^1.0.1
* fix: revert examples to ext-apps ^1.0.0 and fix cheerio version
- Revert ext-apps dependency to ^1.0.0 (works with 1.0.1 once published)
- Fix accidental cheerio bump in wiki-explorer-server
- Remove broken override attempt
* fix: allow compatible semver ranges in version check
The check-versions script now accepts any compatible semver range,
not just exact version matches. For example, ^1.0.0 is allowed when
root version is 1.0.1, since semver compatibility is maintained.
* style: fix indentation in package.json
* fix(examples): use npm reference for ext-apps dependency
Replace local path '../..' with '^1.0.0' npm reference in all example
packages. The local path was accidentally published to npm, causing
npm install to hang when installing server-* packages.
Bump versions to 1.0.1 for all public packages to fix the published
versions.
Fixes npm install hanging issue in dependent projects like
example-remote-server.
Note: npm workspaces automatically resolves the dependency to the
local package during development, so no overrides are needed.
* fix: update zod to 4.x in transcript-server and fix update-lock:docker script
- Update transcript-server to use zod ^4.1.13 for compatibility
- Fix update-lock:docker script to properly clean workspace node_modules
- Regenerate package-lock.json with clean npmjs.org URLs
* chore: add stable spec release 2026-01-26
- Use git mv to copy specification from draft to specification/2026-01-26/apps.mdx (preserves history)
- Update status from 'Draft' to 'Stable (2026-01-26)'
- Add specification version table to README
- Update Resources section with links to both stable and draft specs
* chore: bump version to 1.0.0
- Update main package version from 0.4.2 to 1.0.0
- Update all example package versions to 1.0.0
- Regenerate package-lock.json
* prettier
* chore: align protocol version with spec release 2026-01-26
- Add 'Protocol Version: 2026-01-26' to spec header
- Update LATEST_PROTOCOL_VERSION from '2025-11-21' to '2026-01-26'
- Update spec examples to use '2026-01-26' protocol version
- Add '2025-11-21' to SUPPORTED_PROTOCOL_VERSIONS for backwards compatibility
* chore: update spec references to stable 2026-01-26
- Update typedoc.config.mjs navigation link
- Update docs/overview.md spec links (10 occurrences)
- Update plugins/mcp-apps/skills/create-mcp-app/SKILL.md spec link
- Update src/spec.types.ts @see links
- Update AGENTS.md spec path
- Regenerate src/generated/schema.ts with updated links
* chore: simplify versioning - first stable release
- Remove backwards compatibility version (2025-11-21) - this is the first stable release
- Remove redundant 'Protocol Version' header - spec version IS the protocol version
* chore: add history reference comment to stable spec
* Adding a simple (bad) pdf icon for directory (#330)
* chore: bump version to 0.4.2
- Update package version from 0.4.1 to 0.4.2
- Pin @types/node to 22.10.0 for dev compatibility
- Override seroval to ^1.4.1 to fix security vulnerabilities
- Use '*' for workspace SDK dependency (works with unpublished versions)
* fix(e2e): update Map Server display name to CesiumJS Map Server (#324)
* 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>
* feat(server): add getUiCapability helper for capability negotiation (#313)
* 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: update playwright docker image to v1.58.0
* fix: use -i instead of -it for docker commands (no TTY needed)
* fix: Python server dependency resolution and Docker host validation (#333)
* 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(basic-host): Add theme toggle and MCP style variables (#336)
* 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
* [MCP Apps] Add appCapabilities.availableDisplayModes documentation to spec (#331)
* Add appCapabilities.availableDisplayModes documentation to spec
Document the availableDisplayModes field in McpUiAppCapabilities that allows
apps to declare which display modes they support. This enables hosts to
compute the intersection of host and app capabilities and only offer
appropriate display mode controls.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Address PR review feedback
- Change "Guest UI" to "View" terminology
- Add "View" prefix to availableDisplayModes heading for disambiguation
- Remove intersection logic - host only checks its own supported modes
- Remove assumption that apps must support inline mode
- Simplify host behavior to honor/reject based on its own capabilities
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add appCapabilities.availableDisplayModes to types
- Add `availableDisplayModes` field to `McpUiAppCapabilities` so apps can
declare which display modes they support
- Change `HostContext.availableDisplayModes` type from `string[]` to
`McpUiDisplayMode[]` for type safety
- Regenerate schemas
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Address Olivier's feedback - consolidate display mode docs
- Remove separate "App Capabilities" section for availableDisplayModes
- Add display mode requirements to existing ui/request-display-mode section:
- Host MUST NOT switch View to mode not in appCapabilities.availableDisplayModes
- Host MAY decline requests from Views that didn't declare modes
- View MUST declare supported modes during initialization
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Restore McpUiAppCapabilities docs and fix display mode clause
- Restore McpUiAppCapabilities interface documentation with availableDisplayModes
- Restore "View MUST check if the requested mode is in availableDisplayModes
from host context" clause that was accidentally removed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Create unified Display Modes section
Consolidate all display mode documentation into a single section:
- Display mode types (inline, fullscreen, pip)
- Declaring support from View (appCapabilities.availableDisplayModes)
- Declaring support from Host (HostContext.availableDisplayModes)
- Requesting changes (ui/request-display-mode)
- Notifying changes (ui/notifications/host-context-changed)
- All MUST/SHOULD requirements for View and Host behavior
The ui/request-display-mode in Requests section now references
the Display Modes section for behavior details.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Remove mode coercion clause from display modes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Regenerate schemas with correct version
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat(say-server): add light/dark theme support (#338)
- Add importmap entry for main SDK exports (applyDocumentTheme, etc.)
- Import and apply host theme and styles on context changes
- Apply initial host context theme/styles when app connects
- Update CSS to use [data-theme="dark"] selector for host-provided themes
- Keep @media prefers-color-scheme as fallback for standalone mode
- Add color-scheme meta tag for native element theming
* fix: followup app -> view terminology (#339)
* chore: husky env fix, version pins, update-lock:docker script (#341)
* fix(husky): load Node.js env for GUI apps + add update-lock:docker script
Cherry-picked non-e2e changes from ochafik/fix-e2e-flaky-tests:
- Load nvm/fnm/volta/homebrew paths in pre-commit for GitHub Desktop
- Add update-lock:docker script to regenerate lockfile with public registry
* pin package versions for dev compatibility
- solid-js: 1.9.10
- caniuse-lite: 1.0.30001763
- cheerio: 1.1.2
- electron-to-chromium: 1.5.267
- @playwright/test: 1.57.0
- playwright: 1.57.0
- playwright-core: 1.57.0
* regen
* fix: pin @types/node to existing version and regenerate lockfile
- Fix @types/node 20.19.28 -> 20.19.27 (typo, version didn't exist)
- Regenerate package-lock.json to resolve versions available on both
public npm and Anthropic artifactory registries
* fix(basic-server-solid): bump solid-js 1.9.10 -> 1.9.11 to fix seroval vulnerabilities
* fix: pin seroval to 1.4.1 for dev compatibility
* Refactor server startup functions
Rename `startServer` to `startStreamableHTTPServer` and add a new
`startStdioServer` helper to make the transport type explicit. Remove
the `ServerOptions` interface in favor of reading `PORT` directly from
the environment inside the function (defaulting to `3001`).
Also update Python examples to default to port `3001` for consistency.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Support full-file inclusion in synced code snippets
Previously, the script only supported extracting regions from `.ts/.tsx`
files using the `#regionName` syntax. Now it also supports including
entire files without a region specifier, enabling sync of any file type
(JSON, YAML, shell scripts, etc.) into documentation.
Changes:
- Make `#regionName` optional in the `source=""` attribute
- Accept any fence language (not just `ts`/`tsx`)
- Simplify cache to flat map with composite keys
- Add validation error for region extraction on non-TypeScript files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Rewrite Quickstart guide with type-checked code examples
Rewrites the Quickstart tutorial to provide a more focused, step-by-step
introduction to building MCP Apps. The guide now uses synced code fences
that pull from `examples/quickstart/`, ensuring all code shown in the
documentation is type-checked and tested.
Key improvements:
- Clearer project setup instructions with explicit commands
- Streamlined explanations of the tool + resource registration pattern
- Added screenshot showing the completed app
- E2E test coverage validates the example works end-to-end
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add MCP Apps Overview document
Adds `docs/overview.md` covering the core concepts: architecture,
lifecycle, UI resources, bidirectional communication, theming, display
modes, and security. Includes mermaid flowchart and sequence diagrams.
Also adds the `@boneskull/typedoc-plugin-mermaid` TypeDoc plugin for
mermaid diagram support. However, the plugin handles HTML entities from
TypeDoc incorrectly, so `scripts/typedoc-plugin-fix-mermaid-entities.mjs`
decodes HTML entities before the plugin processes them.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add Agent Skills installation guide
Add `docs/agent-skills.md` with installation instructions for multiple AI
coding agents including Claude Code, VS Code/Copilot, Gemini CLI, Cline,
and Goose. The guide provides three installation methods: Claude Code
plugin, Vercel Skills CLI (`npx skills add`), and manual installation.
Update `README.md` to link to the new guide and reframe the plugin
section around the broader "Agent Skills" concept.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Polish OpenAI migration reference for readability
Add framing prose to the migration guide to improve navigation:
- Expanded intro describing document purpose and how to use it
- Added note about features marked "Not yet implemented"
- Added brief transition sentences before Server-Side and Client-Side sections
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix mermaid diagram arrowheads not rendering
The `@boneskull/typedoc-plugin-mermaid` creates both dark and light theme
variants of each diagram, each with identical marker IDs (e.g., `#arrowhead`).
When mermaid renders SVGs at runtime, lines reference `url(#arrowhead)`, but
the browser resolves this to the first match in document order — the hidden
dark-theme SVG — causing arrows to be invisible.
The fix removes dark-theme `<div class="mermaid dark">` elements at build time,
leaving only one SVG per diagram with unique marker IDs. A CSS filter
(`filter: invert(1) hue-rotate(180deg)`) handles dark mode styling instead.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(docs): improve OpenAI migration guide accuracy (#349)
- Add missing setOpenInAppUrl API to 'Not Yet in MCP Apps' section
- Clarify Event Handling table: specify exact OpenAI properties
(toolInput/toolOutput) instead of vague 'window.openai.*'
- Improve notes to distinguish sync property reads vs callbacks
* Add Testing MCP Apps guide
Document how to test MCP Apps using `basic-host` and MCP Apps-compatible
hosts like Claude.ai and VS Code Copilot. Cover debugging features for
`basic-host`, and using `cloudflared` to expose local servers for remote
hosts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix `onhostcontextchanged` handler invocation in examples
`App.onhostcontextchanged` is a setter-only property with no getter.
TypeScript doesn't prevent reading from setter-only properties, so
`app.onhostcontextchanged?.(ctx)` compiles but silently returns
`undefined` at runtime.
Extract the handler into a named `handleHostContextChanged()` function
and call it directly after `connect()`, matching the pattern used in
`basic-server-vanillajs` and other examples.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Expand Agent Skills guide
Add intro explaining what Agent Skills are and link to the two skill
files (`create-mcp-app`, `migrate-oai-app`). Reorganize headings and add
"Invoke a Skill" and "Test Your App" sections. Update `README.md` link
text and add tip to quickstart suggesting agent skills as an alternative.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(e2e): improve test stability and developer experience (#337)
* fix(e2e): add masks for dynamic content and increase timeouts for slow servers
- Add HOST_MASKS for Tool Input/Result panels with dynamic timestamps
- Add say-server to SLOW_SERVERS (10s) for TTS model download
- Add say-server to EXTRA_WAIT_MS (30s) in generate-grid-screenshots
* feat: add update-lock:docker script to regenerate lockfile with public registry
* pin package versions for dev compatibility
* feat(basic-host): add ?theme=hide query param to hide theme toggle in screenshots
- Add hideThemeToggle param to getQueryParams()
- Conditionally render ThemeToggle based on ?theme=hide
- Update e2e tests to use ?theme=hide for consistent screenshots
* update screenshots
* update screenshots
* fix(husky): load Node.js environment for GUI apps like GitHub Desktop
* fix(e2e): increase map-server wait time to 15s for tile loading
* fix(e2e): increase waitForAppLoad timeout to 30s for nested iframe loading
* ci: add workflow to update e2e snapshots
* ci: trigger snapshot update on push to this branch
* chore: update e2e snapshots [skip ci]
* ci: trigger CI after snapshot update
* style: fix prettier formatting in update-snapshots workflow
* fix: pin seroval, seroval-plugins, and solid-js for dev compatibility
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* Improve README structure and clarity
Add "Why MCP Apps?" section to explain the motivation upfront. Reorganize
the "How It Works" section to lead with tool definition. Rename "Overview"
to "Using the SDK" and add "For" prefix to audience headings.
Restructure the Examples section with clearer subsections for running
examples with `basic-host` vs MCP clients using stdio transport. Move the
`qr` server note outside the collapsed details block.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add Codex and Goose to documentation
Add Codex to the list of agents supporting skills in `agent-skills.md`.
Add Goose to the list of supported clients in `testing-mcp-apps.md` and
rename "VS Code Copilot" to "VS Code (Insiders)" for accuracy.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: regenerate lockfile with public registry, use ^0.4.2 for ext-apps deps
* fix: update quickstart example to use workspace reference
* chore: remove internal registry references from lockfile
* feat(ci): add /update-snapshots comment trigger for PRs
- Comment '/update-snapshots' on any PR to update E2E snapshots
- Adds rocket reaction to acknowledge the command
- Comments back with result (updated or no changes needed)
- Removes hardcoded branch trigger
- Keeps workflow_dispatch for manual runs
* docs: document /update-snapshots PR comment trigger
* fix: pin @hono/node-server to 1.19.7 for dev compatibility
SDK 1.25.3 requires @hono/node-server@^1.19.9 which doesn't exist
on the public npm registry (latest is 1.19.7).
* fix: pin @modelcontextprotocol/sdk to 1.25.2
SDK 1.25.3 has broken dependency on @hono/node-server@^1.19.9
which doesn't exist on public npm registry.
* fix: restore flexible SDK peerDep range (^1.24.0)
devDependencies stays pinned to 1.25.2 for our builds,
but peerDependencies should allow users flexibility.
* fix: pin @types/node to avoid unpublished versions
- Pin quickstart @types/node to 22.19.5 (latest public 22.x)
- Add @types/node override to root package.json
- Regenerate lockfile with public registry only
---------
Co-authored-by: Tobin South <tobin.south@gmail.com>
Co-authored-by: Liad Yosef <liady@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: martinalong <martinalong10@gmail.com>
Co-authored-by: Ido Salomon <idosalomon@gmail.com>
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* fix(e2e): add masks for dynamic content and increase timeouts for slow servers
- Add HOST_MASKS for Tool Input/Result panels with dynamic timestamps
- Add say-server to SLOW_SERVERS (10s) for TTS model download
- Add say-server to EXTRA_WAIT_MS (30s) in generate-grid-screenshots
* feat: add update-lock:docker script to regenerate lockfile with public registry
* pin package versions for dev compatibility
* feat(basic-host): add ?theme=hide query param to hide theme toggle in screenshots
- Add hideThemeToggle param to getQueryParams()
- Conditionally render ThemeToggle based on ?theme=hide
- Update e2e tests to use ?theme=hide for consistent screenshots
* update screenshots
* update screenshots
* fix(husky): load Node.js environment for GUI apps like GitHub Desktop
* fix(e2e): increase map-server wait time to 15s for tile loading
* fix(e2e): increase waitForAppLoad timeout to 30s for nested iframe loading
* ci: add workflow to update e2e snapshots
* ci: trigger snapshot update on push to this branch
* chore: update e2e snapshots [skip ci]
* ci: trigger CI after snapshot update
* style: fix prettier formatting in update-snapshots workflow
* fix: pin seroval, seroval-plugins, and solid-js for artifactory compatibility
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Adds `docs/overview.md` covering the core concepts: architecture,
lifecycle, UI resources, bidirectional communication, theming, display
modes, and security. Includes mermaid flowchart and sequence diagrams.
Also adds the `@boneskull/typedoc-plugin-mermaid` TypeDoc plugin for
mermaid diagram support. However, the plugin handles HTML entities from
TypeDoc incorrectly, so `scripts/typedoc-plugin-fix-mermaid-entities.mjs`
decodes HTML entities before the plugin processes them.
Co-Authored-By: Claude Opus 4.5 <noreply@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>
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>
- Replace requirements.txt with inline script dependencies in server.py
- Add package.json with npm scripts for run-all.ts integration
- Update CI workflow to install uv via astral-sh/setup-uv@v5
- Update Docker commands to install uv for e2e tests
- Add Playwright golden screenshot for qr-server
- Update README with uv installation and usage instructions
* feat(pdf-server): Interactive PDF viewer example
PDF viewer with PDF.js featuring:
- Chunked binary loading with progress bar
- Text extraction for AI context
- arXiv paper support (fetch by ID)
- Page navigation with keyboard shortcuts
- Zoom controls (including Ctrl+0 reset)
- Fullscreen mode support
- Horizontal swipe for page changes (disabled when zoomed)
- Page persistence in localStorage
- Text selection via PDF.js TextLayer
- Clickable title link to source URL
- Rounded corners and subtle border styling
* chore: Add pdf-server to screenshot generation list
* refactor(pdf-server): Simplify and generalize PDF loading
- Accept any HTTP(s) URLs instead of ArXiv-only
- Use HTTP Range requests for chunked binary loading
- Remove ArXiv-specific code (arxiv.ts, metadata fetching)
- Remove CLAUDE.md index generation
- Flatten hierarchical folder structure to simple entries list
- Remove dead code: getPdfSummary, httpFileSizes
- Simplify base64 encoding using Buffer
- Simplify chunk extraction using slice()
- Consolidate DEFAULT_PDF_URL constant
The server now works with any PDF URL, not just arXiv papers.
HTTP Range requests stream chunks on-demand when supported.
* feat(pdf-server): Include title and selection in model context
- Add pdfTitle to updateModelContext structuredContent
- Include selection position (text, start, end) when text is selected
- Add debounced selectionchange listener to update context on selection
* fix(pdf-server): Restore default URL in view_pdf schema
The UI needs the default value in the schema to show it properly.
* refactor(pdf-server): Further simplifications
- Remove hard-coded test paths from main()
- Remove unused resources: pdfs://metadata/{pdfId}, pdfs://content/{pdfId}
- Remove unused metadata fields: subject, creator, producer, creationDate, modDate
- Remove unused entry fields: relativePath, estimatedTextSize
- Remove filterEntriesByFolder and folder filter from list_pdfs
- Remove redundant output schema validation (trust typed returns)
- Simplify scanDirectory and createLocalEntry signatures
Total: 1836 → 1666 lines (-170 lines, -9%)
* refactor(pdf-server): Major simplification for didactic focus
Simplified the example to focus on key MCP Apps SDK patterns:
- Chunked data through size-limited tool calls
- Model context updates (page text + selection)
- Display modes (fullscreen vs inline)
- External links (openLink)
Changes:
- Remove local file support (HTTP URLs only)
- Restrict dynamic URLs to arxiv.org for security
- Simplify types: url instead of sourcePath/sourceType
- Simplify indexer: 168 → 44 lines
- Simplify loader: 318 → 171 lines
- Simplify server: 337 → 233 lines
- Fix selection text normalization
- Rewrite README with didactic focus
Total: 1836 → 1236 lines (-33%)
* feat(pdf-server): Add file:// URL support for local files
- Local paths are converted to file:// URLs on startup
- file:// URLs must be in the initial list (strict validation)
- Dynamic URLs still restricted to arxiv.org only
- Updated README with local file examples
* fix(pdf-server): Improve selection detection with logging
- Add logging to selectionchange handler to verify it fires
- Add fallback matching without spaces (TextLayer spans may lack spaces)
- Log selection detection success/failure for debugging
The issue: PDF.js TextLayer renders text as positioned spans without
space characters between them. When selecting across spans:
- pageText has spaces (items joined with ' ')
- sel.toString() may not have spaces
- indexOf fails to match
The fix tries exact match first, then falls back to spaceless matching.
* feat(pdf-server): Format model context as markdown with front matter
Model context now looks like:
```markdown
---
url: https://arxiv.org/pdf/...
page: 5/144
---
Page text with <pdf-selection>selected text</pdf-selection> inline.
```
This is cleaner for the model to parse and includes the source URL.
* refactor(pdf-server): Extract smart truncation helpers
Added two well-designed helpers:
formatPageContent(text, maxLength, selection?)
- Centers truncation window around selection if present
- Adds <truncated-content/> markers at elision points
- Wraps selection in <pdf-selection> tags
- Allocates 60% context before, 40% after for readability
findSelectionInText(pageText, selectedText)
- Tries exact match first
- Falls back to spaceless match for TextLayer quirks
- Returns { start, end } or undefined
Example output with selection:
```
<truncated-content/>
...context before... <pdf-selection>selected text</pdf-selection> ...context after...
<truncated-content/>
```
* fix(pdf-server): Truncate inside selection tags when selection too long
When selection is too large for the budget:
<truncated-content/><pdf-selection><truncated-content/>start...end<truncated-content/></pdf-selection><truncated-content/>
This keeps the selection structure intact while showing beginning and end.
* refactor(pdf-server): Remove unused read_pdf_text, use Attention paper as default
- Remove read_pdf_text tool (viewer extracts text client-side with pdfjs)
- Remove PdfTextChunk and ReadPdfTextInput types
- Remove loadPdfTextChunk from pdf-loader
- Change default PDF to 'Attention Is All You Need' (1706.03762)
- Update README with modest language
* refactor(pdf-server): Simplify to use URL as ID, rename view_pdf to display_pdf
Major simplifications:
- Use URL directly as identifier (no hashing)
- Remove displayName - show elided URL with full URL as tooltip
- Rename view_pdf to display_pdf with better description
- Update all references from pdfId to url
- Simplify storage key and model context
The tool description now explains it displays an interactive viewer in the chat.
* feat(pdf-server): Normalize arxiv URLs to PDF format
arxiv.org/abs/... -> arxiv.org/pdf/...
Applied both at startup and when loading dynamic URLs.
* docs(pdf-server): Add prompt engineering to display_pdf description
* fix(pdf-server): Sharp rendering on retina displays
Account for devicePixelRatio when rendering canvas:
- Scale canvas dimensions by dpr
- Scale context by dpr
- Keep CSS size at logical pixels
* fix(pdf-server): Normalize arxiv URLs in read_pdf_bytes too
* add to e2e spec
* add to e2e spec
* add to e2e spec
* add to e2e spec
* regen
* chore: regenerate package-lock.json and fix hono vulnerability
* docs: add pdf-server screenshot to READMEs
* regen
* ci: add missing examples to pkg-pr-new publish
* ci: add pdf-server to npm publish examples
* Update README.md
* pdf-server: improve tool response text for better model context
* revert unrelated screenshot changes
* pdf-server: dynamically add arxiv URLs in read_pdf_bytes
Fixes 'PDF not found' error when server restarts between display_pdf
(which adds the entry) and read_pdf_bytes (which previously only looked
up existing entries). Now read_pdf_bytes mirrors display_pdf's logic
and dynamically adds arxiv URLs to the index.
* feat: add script to generate 300x300 grid-cell.png screenshots for examples
- Add generate-grid-screenshots.spec.ts Playwright test to capture screenshots
- Add npm run generate:screenshots command (Docker-based for Santa compatibility)
- Add sharp dependency for image resizing with centered-fill mode
- Generate grid-cell.png for 14 example servers (only React for basic-server-* series)
The screenshots are 300x300 PNG images cropped with centered fill mode,
suitable for use in a grid layout showcasing the examples.
* docs: add example gallery grid to README
Add a 3-column visual grid showcasing 14 example MCP Apps with:
- Thumbnail screenshots (300x300 grid-cell.png)
- Clickable links to example directories
- Hover tooltips with brief descriptions
Organized by visual impact: 3D/WebGL examples first, then
visualizations, charts, monitoring, and starter templates.
* fix: use aspect-fit instead of crop for screenshots
Change from fit: 'cover' (crops) to fit: 'contain' (letterbox)
so the full app content is visible without cropping.
* feat: improve screenshot generation
- Constrain viewport to 500px width for consistent rendering
- Wait 5 seconds for full app load (tiles, animations, data)
- Screenshot just the inner iframe (no extra whitespace)
- Save both screenshot.png (full-size) and grid-cell.png (300x300 thumbnail)
- Use contain mode to preserve aspect ratio
* fix: use cover mode with top alignment for grid thumbnails
No letterboxing - crops to fill 300x300, aligned to top so headers
and important content are always visible.
* feat: improve screenshot gallery
- Remove integration-server from gallery (it's for E2E testing only)
- Add 30s extra wait for Map and Video servers to load fully
- Improve Three.js default scene: isometric rotation + better lighting
- Update README: Starter Templates row with links to all framework variants
(React, Vue, Svelte, Preact, Solid, Vanilla JS)
- Regenerate all screenshots with updated settings
* fix: improve README gallery layout
- Fix uneven column widths by using minimal separator
- Move Starter Templates to separate 2-cell table with description
- Add screenshot.png to top of each example README (13 examples)
- Shorten tooltips for cleaner table
* revert to document.write again; cesiumjs doesn't like srcdoc, period.
* fix: map-server screenshot now renders properly
- Merged ochafik/post-fixes which reverts sandbox from srcdoc to document.write
(CesiumJS doesn't work with srcdoc iframes)
- Fixed map-server name in screenshot test ('Map Server' not 'CesiumJS Map Server')
- Simplified screenshot generation script (removed complex debugging code)
- Increased map-server wait time to 45s for reliable tile loading
- Regenerated all 13 screenshots
* fix: remove redundant screenshots from READMEs
Remove the simple \ line from READMEs that
already had nicer HTML table screenshots. Keep it only for examples
that didn't have existing screenshots.
* docs: move gallery to Examples section
- Move screenshot gallery from top of README to Examples section
- Remove redundant list of basic examples (now shown visually in gallery)
- Clean up duplicate run instructions
* fix: remove empty header row from starter templates table
* fix: remove empty header rows from both tables
* fix: add prettier-ignore to prevent table header expansion
* feat: use custom screenshot for video-resource-server
- Use better screenshot from PR #253 comment showing actual video playback
- Skip video-resource-server in screenshot generation script
- Add SKIP_SERVERS set for manually maintained screenshots
* fix: revert unrelated map-server name change
* fix: use correct server name 'CesiumJS Map Server' in screenshot test
* chore: release 0.4.0
* chore: add new examples to npm publish workflow
Add map-server, shadertoy-server, and transcript-server to the
publish-examples matrix.
* fix: ensure lib is built before examples:build
Add preexamples:build hook to automatically run `npm run build` before
`examples:build`. This ensures examples always type-check against the
latest library code, catching breaking changes during development.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: add version consistency check for examples
Add scripts/check-versions.mjs to verify that example package.json files
reference the correct version of @modelcontextprotocol/ext-apps.
- Allows "../.." (local dev) or "^{root-version}" as valid dependencies
- Runs in CI before npm install to catch mismatches early
- Available locally via `npm run check:versions`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: regenerate package-lock.json for cross-platform compatibility
---------
Co-authored-by: Claude <noreply@anthropic.com>
* chore: bump version to 0.3.0
Breaking changes:
- `viewport` replaced with `containerDimensions` in host context
New examples:
- video-resource-server
- sheet-music-server
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(video-resource-server): add missing server-utils and fix import path
The video-resource-server was importing from a non-existent
../shared/server-utils.js path. Added the server-utils.ts file
and fixed the import to use ./src/server-utils.js like other examples.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: update ext-apps version refs to 0.3.0
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat: publish example servers to npm
Make example MCP App servers publishable to npm under the
@modelcontextprotocol scope:
- server-basic-react
- server-basic-vanillajs
- server-budget-allocator
- server-cohort-heatmap
- server-customer-segmentation
- server-scenario-modeler
- server-system-monitor
- server-threejs
- server-wiki-explorer
Changes:
- Remove `private: true` from example package.json files
- Add proper npm metadata (description, repository, license, files)
- Update ext-apps dependency from relative to ^0.2.2
- Copy server-utils.ts into each package for standalone use
- Add publish-examples job to npm-publish.yml workflow
The examples will be published automatically when a GitHub release
is created, after the main SDK package is published.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: publish examples with pkg-pr-new for PR testing
* feat: export createServer from example servers
* style: format integration-server/server.ts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: update e2e snapshots for basic-server examples
Update golden screenshots for basic-react and basic-vanillajs after
the tool output was simplified from JSON to plain text in #182.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* merge
* refactor: update sheet-music-server and video-resource-server to new publishing pattern
- Move server-utils.ts from src/ to root level
- Add npm publishing metadata (scoped name, repository, license, files)
- Change ext-apps dependency from local to versioned ^0.2.2
- Update server.ts to handle stdio mode inline
* update package-lock
* fix: update package-lock.json for renamed server packages
* feat: add NASA public domain video to video-resource-server
Added 'nasa-earth' option - NASA ISS Earth observations (6.4MB).
Source: archive.org/details/NASA-Ultra-High-Definition (public domain)
* fix: add default videoId for video-resource-server
* fix: use existing bunny-1mb as default video, remove nasa-earth
* refactor: update new framework examples to publishing pattern
Add publishing metadata for:
- @modelcontextprotocol/server-basic-preact
- @modelcontextprotocol/server-basic-solid
- @modelcontextprotocol/server-basic-svelte
- @modelcontextprotocol/server-basic-vue
Changes:
- Move server-utils.ts from src/ to root
- Add npm publishing metadata
- Update ext-apps dep to versioned ^0.2.2
- Add stdio mode support in main()
* fix: add missing @rollup/rollup-win32-arm64-msvc to optionalDependencies
This fixes the Windows ARM64 CI build failure caused by npm's optional
dependency bug. The package.json was missing this platform-specific
rollup binding.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Olivier Chafik <ochafik@anthropic.com>
Allows running `npm start` as a shorthand for `npm run examples:start`,
providing a conventional entry point to launch the example servers.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat: make generated Zod schemas version-agnostic (v3.25+/v4)
- Change generated schema imports from `zod/v4` to standard `zod`
- Replace v4-only `z.looseObject()` with `z.object().passthrough()`
- Works with both Zod v3.25+ and v4, matching MCP TS SDK approach
- Bump version to 0.2.2
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: regenerate package-lock.json in Docker
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix: widen @oven/bun-* version range to improve install compatibility
Lower the minimum version of @oven/bun-* optional dependencies from
^1.3.4 to ^1.2.21. This is the lowest common version available across
all platform-specific packages, improving compatibility for contributors
who may not have access to the latest package versions.
The caret range (^) still allows npm to install newer versions when
available.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: bump version to 0.2.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat: make MCP SDK a peer dependency
- Move @modelcontextprotocol/sdk from dependencies to peerDependencies (^1.20.0)
- Add to devDependencies for local development (^1.24.3)
- Externalize SDK from all build entry points (app, app-bridge, react, server)
Benefits:
- Consumers control their SDK version
- Deduplication when consumer already has SDK
- Follows pattern of react/zod peer deps
* fix: require SDK ^1.24.0 for Zod 4 compatibility
Earlier SDK versions have Zod type incompatibilities that cause build errors.
* chore: update examples to SDK ^1.24.0 to match peer dep
* 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>
Move react and react-dom from dependencies to peerDependencies with
support for React 17, 18, and 19. This allows consumers to use their
preferred React version instead of forcing v19.
- Added peerDependencies for react/react-dom (^17 || ^18 || ^19)
- Marked react dependencies as optional in peerDependenciesMeta
- Moved react/react-dom to devDependencies for local development
- React is already externalized in the build (build.bun.ts)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: Windows compatibility for npm scripts and cross-platform CI
Fixes#142 - Windows PowerShell install bug
Changes:
- Replace single quotes with escaped double quotes in generate:schemas
(cmd.exe passes single quotes literally, breaking prettier glob matching)
- Simplify prettier scripts: remove redundant --ignore-path flags
(prettier auto-loads .gitignore and .prettierignore by default)
- Remove $(pwd) from prettier scripts (bash-only syntax)
- Add cross-platform CI matrix: Linux x64, Windows x64, macOS ARM64, macOS x64
- Use shell: bash for grep commands in CI (not available in Windows cmd.exe)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: remove bun npm package from all workspaces
The bun npm package tries to install platform-specific binaries which
fails on Windows CI. Since bun is installed via oven-sh/setup-bun action
in CI (and developers install it globally), we don't need the npm package.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: skip examples:build on Windows (uses Unix-only INPUT=... syntax)
The examples use `INPUT=mcp-app.html vite build` which is bash syntax
for setting environment variables. This doesn't work on Windows cmd.exe.
Since examples aren't published to npm, we can skip building them on Windows.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: force LF line endings for cross-platform prettier consistency
Git on Windows auto-converts line endings to CRLF, causing prettier to
report formatting issues. Force LF for all text files.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* ci: add test for git-based npm install (cross-platform)
This verifies that `npm install git+https://...` works on all platforms,
which triggers the prepare script and requires bun to be available.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* ci: add Linux ARM64 and Windows ARM64 to CI matrix
- Added ubuntu-24.04-arm (Linux ARM64)
- Added windows-11-arm (Windows ARM64)
Note: WSL is not available on GitHub-hosted runners (requires nested
virtualization which isn't supported).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* ci: disable Windows ARM64 (Bun lacks stable ARM64 binaries)
The oven-sh/setup-bun action fails with 404 when trying to download
Bun for Windows ARM64. Re-enable when Bun adds proper support.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* ci: add Windows WSL build test
Uses Vampire/setup-wsl action to install Ubuntu-24.04 in WSL and run
the full build/test cycle. This tests the Linux-in-Windows scenario
that was reported in issue #142.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* ci: fix WSL build - install unzip for Bun installer
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* ci: add setup-bun to publish.yml workflow
The pkg-pr-new publish workflow was missing bun setup, causing
"bun: not found" errors during npm ci (which triggers prepare script).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* ci: enable Windows ARM64 with x64-baseline Bun (via emulation)
Windows ARM64 can run x64 binaries via emulation. Use bun-download-url
to force x64-baseline build since native ARM64 Bun isn't available yet.
Reference: https://github.com/oven-sh/bun/issues/9824🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* ci: remove macOS x64 (macos-13 runner retired)
The macos-13 based runner images are now retired.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* docs: add Bun installation instructions per platform
Documents that Bun is required for development, with platform-specific
install commands in collapsible sections.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* docs: note Bun requirement in README examples section
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: add bun as optional dependency (no global install required)
- Add @oven/bun-* platform packages as optionalDependencies
- Create postinstall script to set up bun binary from optional deps
- Handle Windows ARM64 by downloading x64-baseline for emulation
- Remove setup-bun from CI workflows (npm install handles it now)
- Remove manual Bun install instructions from docs
This alternative approach eliminates the need for global Bun installation
or setup-bun action in CI. npm install automatically installs the
platform-appropriate bun binary.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: add debug logging to setup-bun script
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: force stdout flush in setup-bun for CI debugging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: add more debugging to setup-bun
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: remove accidental test artifacts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: run setup-bun in prepare script (before build)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: use cross-env for Windows-compatible example builds
- Add cross-env to devDependencies
- Update all example package.json scripts to use cross-env for INPUT and NODE_ENV
- Enable examples:build on Windows in CI (no longer Unix-only)
- Add examples:build to WSL CI job
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: remove unused imports in setup-bun.mjs
Address github-code-quality bot comments.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: use run-bun.mjs wrapper for prepare hook compatibility
During npm install's prepare hook, node_modules/.bin is not in PATH,
so calling 'bun' directly fails. The new run-bun.mjs wrapper finds
bun at node_modules/.bin/bun and runs it with the correct path.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* ci: restore setup-bun action for build jobs
- Add setup-bun action to build and test-git-install jobs
- Disable Windows ARM64 (Bun doesn't support this platform)
- Add bun installation to WSL build
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: remove bun devDep, add libc detection for Linux ARM64
- Remove 'bun' from devDependencies (its postinstall fails on Windows ARM64)
- Add libc detection (glibc vs musl) to setup-bun.mjs
- Only try compatible binaries based on detected libc
- Re-enable Windows ARM64 in CI (now uses x64 emulation fallback)
- Remove setup-bun action from CI (no longer needed)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* ci: simplify WSL build - let setup-bun.mjs handle bun installation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
- Remove platform-specific browser channel (was using Chrome on macOS,
Chromium in CI) - now uses default Chromium everywhere
- Add Docker-based test scripts for CI-identical local testing:
- `npm run test:e2e:docker` - run tests in Docker
- `npm run test:e2e:docker:update` - regenerate golden screenshots
- Regenerate golden screenshots using Docker/Linux environment
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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>
* Add Playwright E2E tests with screenshot golden testing
- Add E2E tests for all 8 MCP server examples
- Screenshot golden images for visual regression testing
- CI workflow for running E2E tests
- npm scripts: test:e2e, test:e2e:update, test:e2e:ui
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add default demo code for Three.js example
When no code is provided, show a rotating green cube demo.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add E2E testing documentation to CONTRIBUTING.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Update Three.js golden screenshot with 3D cube
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add explicit permissions to CI workflow
Set minimal read-only permissions for security best practices.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix test.setTimeout() to be inside describe blocks
Playwright requires setTimeout to be called within a test or describe block.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Simplify E2E tests - remove excessive timeouts
- Remove explicit setTimeout calls (default 30s is sufficient)
- Replace waitForTimeout(5000/6000) with proper waitForAppLoad()
- Wait for inner iframe visibility instead of fixed delays
- Keep only 500ms stabilization for screenshot animations
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Auto-generate missing snapshots in CI
Use updateSnapshots: 'missing' in CI to handle cross-platform
screenshot differences (macOS vs Linux).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Use platform-agnostic golden screenshots
- Remove -chromium-darwin suffix from snapshot filenames
- Configure snapshotPathTemplate for cross-platform compatibility
- Increase tolerance to 5% for rendering differences between platforms
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Refactor tests to use forEach instead of for-of loop
May help with Playwright test discovery issues in CI.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Use npm ci and list reporter in CI
- Use npm ci for exact package versions
- Use --reporter=list instead of html to avoid potential re-evaluation issues
- Only upload test-results on failure
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Exclude e2e tests from bun test
Run bun test only on src/ directory to avoid running Playwright tests
with Bun's test runner.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix prettier formatting
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add interaction tests for basic server apps
Test that clicking buttons in the MCP App triggers the corresponding
host callbacks:
- Send Message → host logs "Message from MCP App"
- Send Log → host logs "Log message from MCP App"
- Open Link → host logs "Open link request"
Tests both React and Vanilla JS implementations.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Mask dynamic content in E2E screenshot tests
Add Playwright mask option to handle servers with dynamic/random content:
- basic-react/vanillajs: mask server time display
- system-monitor: mask CPU chart, memory stats, uptime
- cohort-heatmap: mask heatmap grid (random data)
- customer-segmentation: mask scatter chart (random data)
This addresses PR feedback about handling examples with non-deterministic
output. Masking replaces the previous 10% tolerance with proper exclusion
of dynamic elements, allowing tighter 1% tolerance for the rest of the UI.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add wiki-explorer to E2E tests with default URL param
- Add default URL "https://en.wikipedia.org/wiki/Model_Context_Protocol" to
wiki-explorer-server's get-first-degree-links tool inputSchema
- Update basic-host to automatically populate input field with tool defaults
extracted from inputSchema.properties
- Add wiki-explorer-server to E2E test suite with dynamic masking for the
force-directed graph
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Use .default() for threejs tool schema instead of .optional()
This exposes the default code and height values in the JSON Schema,
allowing basic-host to auto-populate the input field with defaults.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Enable parallel E2E tests with timeouts and canvas masking
- Enable fullyParallel with 4 workers locally (2 in CI)
- Add 30s timeout per test
- Mask threejs canvas for stable screenshots
- Update snapshots to reflect default values in input fields
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add pre-commit check for private registry URLs in package-lock.json
Same check as in CI to catch issues before push.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Increase screenshot diff tolerance to 6% for cross-platform rendering
Font rendering differs between macOS and Linux, causing ~5% pixel differences.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Revert pre-commit artifactory check (moved to separate PR #133)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Format threejs server.ts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Update CONTRIBUTING.md to reflect platform-agnostic screenshots
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(e2e): use factory pattern for MCP servers to support parallel connections
McpServer only supports one transport at a time. When multiple browser
contexts connected in parallel, calling server.connect(transport) for
each session overwrote the previous transport's callbacks, causing
connection corruption and test timeouts.
Changes:
- server-utils.ts: accept factory function instead of single instance
- All 9 example servers: wrap server creation in createServer() function
- playwright.config.ts: re-enable parallel execution (4 workers)
- servers.spec.ts: add toBeEnabled wait for server connection
- Update screenshot baselines for basic-vanillajs and cohort-heatmap
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix: prettify generated files on the fly
- Add prettier --write to generate:schemas script to format generated
files immediately after generation
- Remove redundant prettier:fix from CI schema verification step
(now that generation includes formatting)
This fixes the release CI failure where generated files weren't
formatted. Previously, PR CI masked this by running prettier:fix
before the final prettier check, while release CI ran the check
directly on freshly-generated (unformatted) files.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* format
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add ts-to-zod schema generation from spec.types.ts
Add automated Zod schema generation using ts-to-zod:
- New npm script `generate:schemas` to regenerate schemas from spec.types.ts
- Post-processing script for Zod v4 compatibility and MCP SDK type imports
- src/spec.types.ts: Pure TypeScript interface definitions (source of truth)
- src/schemas.generated.ts: Auto-generated Zod schemas
- src/schemas.ts: Re-exports with PascalCase naming for backwards compatibility
The generated schemas provide a simpler alternative to the hand-written schemas
in types.ts, useful for lighter validation or reference implementations.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: types.ts now re-exports from spec.types.ts and schemas.generated.ts
- types.ts imports and re-exports types from spec.types.ts (source of truth)
- types.ts imports and re-exports schemas from schemas.generated.ts
- Added compile-time VerifySchemaMatches checks to flag mismatches between
interfaces and generated schemas
- Removed redundant schemas.ts (types.ts now handles all re-exports)
- Applied prettier formatting to schemas.generated.ts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: use ts-to-zod as library with integration tests
Replace CLI-based schema generation with library API:
- scripts/generate-schemas.ts: New script using ts-to-zod library API
- Detailed documentation of why each post-processing step is needed
- Generates integration tests via getIntegrationTestFile()
- Better error reporting and control
- src/schemas.generated.test.ts: Auto-generated integration tests
- Compile-time verification that schemas match TypeScript types
- Uses expectType<> pattern for bidirectional type checking
- Removed scripts/postprocess-schemas.ts (merged into generate-schemas.ts)
- Fixed McpUiResourceTeardownResult to include index signature for MCP SDK
Protocol compatibility (detected by the new integration tests)
Post-processing rationale (documented in generate-schemas.ts):
1. zod → zod/v4: Explicit v4 subpath for version clarity
2. z.any() → MCP SDK schemas: External types need real validation
3. z.record().and() → z.looseObject(): Index signatures need Zod v4 idiom
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: regenerate schemas during build + CI check
- build script now runs generate:schemas before bun build
- CI workflow verifies generated schemas are up-to-date
(fails if spec.types.ts changed but schemas weren't regenerated)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: generate PascalCase schemas, move verification to tests
- Add getSchemaName option to generate PascalCase schema names directly
(McpUiOpenLinkRequestSchema instead of mcpUiOpenLinkRequestSchema)
- Remove redundant compile-time verification from types.ts
(already handled by generated test file's bidirectional expectType checks)
- Simplify types.ts from 235 to 57 lines (just re-exports)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: add missing csp field, simplify schema generation
- Add missing csp field to McpUiSandboxResourceReadyNotification (regression from merge)
- Simplify generate-schemas.ts - remove complex .describe() conversion
- Document that ts-to-zod supports @description JSDoc tags for .describe()
- Improve z.looseObject() replacement with brace-counting for nested objects
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: add @description JSDoc tags for .describe() on schemas
Added @description tags to all interfaces and fields in spec.types.ts.
ts-to-zod now generates .describe() calls on all schema fields, making
descriptions available at runtime for introspection and JSON Schema generation.
Example:
/** @description URL to open in the host's browser */
url: string;
Generates:
url: z.string().describe("URL to open in the host's browser")
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: generate JSON Schema from Zod schemas
Added JSON Schema generation to the schema generation pipeline:
- Uses Zod v4's built-in toJSONSchema() to convert schemas
- Generates src/schema.json with all message types in $defs
- Includes descriptions from @description JSDoc tags
- Added export "./schema.json" to package.json
- Updated CI to verify schema.json is up-to-date
Use cases:
- Language-agnostic validation (Python, Go, Rust)
- Documentation generation (Redoc, Swagger UI)
- Code generation (quicktype)
- IDE autocomplete for JSON/YAML
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: rename schema.json to schema.generated.json
Renamed to match other generated files naming convention.
Export path unchanged: ./schema.json -> ./dist/src/schema.generated.json
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: rename schemas.generated.* to schema.generated.* (singular)
Consistent singular naming for all generated files:
- schema.generated.ts
- schema.generated.test.ts
- schema.generated.json
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: rename schemas.generated.* to schema.generated.* (singular)
Consistent singular naming for all generated files:
- schema.generated.ts
- schema.generated.test.ts
- schema.generated.json
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: move generated files to src/generated/ with simpler names
Moved:
- src/schema.generated.ts → src/generated/schema.ts
- src/schema.generated.test.ts → src/generated/schema.test.ts
- src/schema.generated.json → src/generated/schema.json
Benefits:
- Cleaner organization (generated files isolated)
- Simpler names without .generated suffix
- Easier to gitignore if desired later
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: add missing type exports for backwards compatibility
Added missing exports that existed in main:
- McpUiTheme, McpUiThemeSchema
- McpUiDisplayMode, McpUiDisplayModeSchema
- McpUiResourceCsp, McpUiResourceCspSchema
- McpUiResourceMeta, McpUiResourceMetaSchema
Also fixed theme/displayMode to match original values:
- theme: 'light' | 'dark' (removed 'system')
- displayMode: 'inline' | 'fullscreen' | 'pip' (removed 'carousel')
Verified: all 47 exports from main are preserved with compatible types.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: stage generated files after prettier in pre-commit hook
The pre-commit hook runs build (which generates schemas) then prettier
(which formats them). The formatted generated files weren't being staged,
causing CI to fail with 'Generated schemas are out of date'.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* update generated files
* fix: run prettier after regenerating schemas in CI verification
CI was comparing unformatted generated output against formatted committed
files, causing false 'out of date' failures.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>