Commit graph ext-apps/src
Author SHA1 Message Date
Olivier Chafik
8b09f4278c
fix: proper CSP handling in basic-host sandboxing (HTTP headers, worker-src, document.write) (#234)
* fix: Move CSP to HTTP headers + add worker-src, frameDomains, baseUriDomains, permissions

Security improvements:
- CSP is now set via HTTP headers in serve.ts instead of meta tags
  (meta tag CSP can be tampered with by same-origin content)
- CSP passed as query param to sandbox.html for header-based enforcement

New CSP/permissions features (borrowed from PR #158):
- frameDomains: control frame-src directive for nested iframes
- baseUriDomains: control base-uri directive
- permissions: camera, microphone, geolocation via iframe allow attribute

WebGL fix:
- Use document.write() instead of srcdoc for inner iframe content
  (srcdoc creates opaque origin that breaks WebGL canvas updates)
- Add worker-src directive with blob: support (critical for WebGL apps
  like CesiumJS/Three.js that use workers for tile decoding, terrain
  processing, image processing)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: Remove permissions support (defer to PR #158)

Keep this PR focused on CSP security fixes only.
Permissions (camera, microphone, geolocation) will be
handled in #158.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* cleanup McpUiResourceCsp type usage / duplicate defs

* fix: guard against CSP injection in domain parameters

Validate CSP domain entries to reject characters that could:
- Break out of CSP directives (semicolons, newlines)
- Inject CSP keywords like 'unsafe-eval' (quotes)
- Inject multiple sources in one entry (spaces)

This prevents injection attacks where malicious domains could
override the security policy.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 14:32:48 +00:00
Olivier Chafik
2730f796f7
make registerAppTool more interchangeable w/ server.registerTool (#219) 2026-01-09 01:22:39 +00:00
Jerome
c25d464d18
feat: publish example servers to npm (#184)
* 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>
2026-01-08 20:08:50 +00:00
Olivier Chafik
97990b6b28
Make ui.resourceUri optional (for tools that just need visibility) (#210)
* Make ui.resourceUri optional (for tools that just need visibility)

* chore: regenerate schemas for optional resourceUri
2026-01-08 17:05:00 +00:00
Ido Salomon
773943cad1
feat: export method names as consts (#192)
* feat: export method names as consts

* rename

* fix

* format
2026-01-08 18:50:59 +02:00
Anton Pidkuiko
c475dc3c17
Merge pull request #216 from modelcontextprotocol/antonp/toolinfo-id-optional
fix: make toolInfo.id optional per spec
2026-01-08 13:24:34 +00:00
Anton Pidkuiko MacBook
4012136885
fix: make toolInfo.id optional per spec
The spec (apps.mdx) defines toolInfo.id as optional (id?: RequestId),
but the TypeScript types and generated schemas had it as required.

This allows hosts to pass just the tool definition without needing
a request ID, which is useful when the tool name is the primary
information needed by the widget.
2026-01-08 11:48:34 +00:00
Olivier Chafik
2411c71aa5
fix!: require eventSource in PostMessageTransport + add security tests (#208) 2026-01-07 20:57:50 +00:00
Olivier Chafik
c7ef5f009b
fix: Add missing origin parameter to PostMessageTransport default constructor, verify origins in example sandbox proxy (#207)
* fix(app): add source validation to default PostMessageTransport

App.connect() now passes window.parent as both eventTarget and eventSource,
enabling source validation by default. This ensures apps only accept
messages from their parent window, preventing potential cross-app
message spoofing attacks.

Previously, the default transport only specified the target but not the
source for validation, meaning apps would accept messages from ANY window.

* fix(sandbox): add origin validation for host messages

The sandbox proxy now validates that messages from the parent window
come from the expected host origin (derived from document.referrer).
This prevents malicious pages from sending spoofed messages to the sandbox.

Changes:
- Extract EXPECTED_HOST_ORIGIN from document.referrer
- Validate event.origin against expected origin for parent messages
- Use specific origin instead of '*' when sending to parent
- Reject and log messages from unexpected origins

This addresses the TODO comment that was previously in the code.

* validate messages from app come from same origin as sandbox proxy

* fix(basic-host): be resilient to individual server connection failures

Use Promise.allSettled instead of Promise.all when connecting to
servers, so that a single server failure doesn't crash the entire UI.
Failed connections are logged as warnings but the UI continues with
the servers that connected successfully.

Also fixes video-resource-server missing server-utils.ts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-07 14:20:49 +00:00
martinalong
dc226be962
Remove viewport 2025-12-31 21:36:29 -08:00
martinalong
e90c7945bc
Rebased schemas 2025-12-26 14:16:26 -08:00
martinalong
82e64d56bb
Separate viewport and containerDimensions 2025-12-26 14:15:54 -08:00
martinalong
c22e86233b
Allow undefined values 2025-12-26 14:15:54 -08:00
martinalong
06c0e08a17
Clarify documentation 2025-12-26 14:15:53 -08:00
martinalong
4e01a6c200
Make height/width optional as well 2025-12-26 14:15:53 -08:00
martinalong
87f6f3f27e
Update documentation and revert type change 2025-12-26 14:15:53 -08:00
martinalong
93b9da9e7a
Updating viewport type and documentation 2025-12-26 14:15:53 -08:00
Jonathan Hefner
4ff22d0097
Fix build errors in examples (#180)
* Update `package.json`

* Add TypeScript type checking to example build scripts

Add `tsc --noEmit &&` before `vite build` in all example `package.json`
files to catch type errors during builds. Previously, type errors
in `server.ts` files were not detected because Vite/Bun transpile
without type checking.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Make `_meta` optional in `McpUiAppResourceConfig`

The `_meta` and `ui` properties were required, causing TypeScript errors
when calling `registerAppResource()` without providing metadata.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix Zod type compatibility in `registerAppTool()`

Use `ZodRawShapeCompat | AnySchema` from SDK's `zod-compat` module
instead of raw `ZodRawShape` to resolve type errors when examples
pass `ZodObject` schemas to `registerAppTool()`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Remove unused imports in example apps

- `basic-server-react`: Remove unused `McpUiResourceTeardownResult`
- `customer-segmentation-server`: Remove unused `PostMessageTransport`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix CI git install test for fork PRs

Use `github.event.pull_request.head.repo.full_name` to correctly
reference the fork repository when testing git installs from PRs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 11:17:23 +00:00
Olivier Chafik
82ab3c894c
chore: bump to 0.2.2 + make Zod schemas version-agnostic (v3.25+/v4) (#178)
* 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>
2025-12-17 20:55:59 +00:00
Anton Pidkuiko
3e95d6421c
Merge pull request #174 from modelcontextprotocol/martinalong/mcp-apps/fix-style-variables
[MCP Apps] Add forgotten style variable
2025-12-17 17:49:42 +07:00
Anton Pidkuiko
242ec23856
Merge pull request #159 from modelcontextprotocol/martinalong/mcp-apps/custom-fonts
[MCP Apps] Add way to pass custom fonts
2025-12-17 17:45:54 +07:00
martinalong
9888c6a20b
Add forgotten style variable 2025-12-16 22:20:45 -08:00
Olivier Chafik
894f7936f5
chore: bump version to 0.2.0 (#170) 2025-12-16 22:23:50 +00:00
Olivier Chafik
2dd223b611
refactor: rename request methods to remove send prefix (#161)
* refactor: rename request methods to remove send prefix

Following the MCP TS SDK convention where request methods don't have
the "send" prefix (reserved for notifications):

- App.sendMessage() → App.message()
- App.sendOpenLink() → App.openLink()
- AppBridge.sendResourceTeardown() → AppBridge.resourceTeardown()

The old method names are kept as deprecated aliases for backwards
compatibility.

Updated all examples to use the new method names.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* test: add tests for deprecated method aliases

- Update existing tests to use new method names (message, openLink)
- Add tests verifying deprecated aliases are same reference as new methods
- Add tests verifying deprecated aliases still work functionally

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: rename message→sendMessage, resourceTeardown→teardownResource

- App.message() → App.sendMessage() (with deprecated message alias)
- AppBridge.resourceTeardown() → AppBridge.teardownResource() (with deprecated aliases)

This better follows the pattern where methods that send data have 'send' or action verb prefix.

* fix: update examples to use sendMessage instead of message

* fix: update basic-host to use teardownResource

* fix: update threejs-server to use sendMessage

* refactor: remove deprecated app.message alias

The app.message alias was removed since sendMessage is the correct name.
sendResourceTeardown already exists in AppBridge.

* refactor: remove resourceTeardown alias, keep only sendResourceTeardown

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-16 22:07:06 +00:00
Anton Pidkuiko
37aab03de0
docs: add tool visibility and restructure _meta.ui (#131)
* docs: add tool visibility and restructure _meta.ui

- Restructure tool metadata: `_meta["ui/resourceUri"]` → `_meta.ui.resourceUri`
- Add `visibility` array field: ["model"], ["apps"], or ["model", "apps"]
- Default ["model"] preserves standard MCP behavior
- ["apps"] enables widget-only tools hidden from agent
- Add McpUiToolMeta interface for type safety
- Add Design Decision #4 explaining approach vs OpenAI's two-field model

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* address PR review comments

- Change default visibility to ["model", "apps"]
- Add deprecation notice for flat ui/resourceUri format
- Add McpUiToolMeta and McpUiToolVisibility to spec.types.ts
- Improve tools/list and tools/call behavior wording

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore: regenerate schemas for McpUiToolMeta types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: tool visibility and nested _meta.ui format

- Rename visibility "apps" → "app" in McpUiToolVisibility type
- Add _meta.ui.resourceUri nested format (deprecate flat format)
- Add getToolUiResourceUri() utility with backward compatibility
- Add visibility demo to system-monitor-server:
  - get-system-stats: visibility ["model"] with resourceUri
  - refresh-stats: visibility ["app"] (app-only polling)
- Update all example servers to use new _meta.ui format
- Add 11 unit tests for getToolUiResourceUri()

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore: regenerate schemas with updated dependencies

* feat: export McpUiToolMeta type and add type annotations

- Export McpUiToolMeta and McpUiToolVisibility types from types.ts
- Export corresponding Zod schemas (McpUiToolMetaSchema, McpUiToolVisibilitySchema)
- Add `as McpUiToolMeta` type annotations to all example servers
- Update docs/quickstart.md with proper typing

Ensures type safety for `_meta.ui` tool metadata across the codebase.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: add server helpers and optional connect() transport

Add `src/server/` with convenience functions for registering MCP App tools
and resources:

- `registerAppTool(server, name, config, handler)`
- `registerAppResource(server, name, uri, config, callback)`

The `transport` parameter in `App.connect()` is now optional, defaulting to
`PostMessageTransport(window.parent)`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Update src/server/index.ts

Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>

* feat: update McpUiAppToolConfig to support both _meta.ui and flat formats

* refactor: simplify server helper imports

* docs: add deprecation notice and improve resourceUri documentation

* feat: add backward compat normalization in registerAppTool

- If _meta.ui.resourceUri is set, also set legacy flat key
- If legacy flat key is set, also set _meta.ui.resourceUri
- Preserves existing visibility when merging
- Does not overwrite if both formats already set

* refactor: avoid mutating config arg in registerAppTool

* style: format with prettier

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Olivier Chafik <ochafik@anthropic.com>
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
2025-12-16 21:47:40 +00:00
Olivier Chafik
bea0ae27f5
feat: add server helpers, make connect() to default to parent post transport (#165)
* 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>
2025-12-16 21:25:26 +00:00
martinalong
6397ec1511
Add way to pass fonts 2025-12-15 22:54:53 -08:00
martinalong
c516cf0894
Merge pull request #152 from modelcontextprotocol/martinalong/mcp-apps/display-mode-updates
[MCP Apps] Have apps request display mode instead
2025-12-15 16:12:45 -08:00
martinalong
8f591b69f2
Update naming of functions to reflect styles.variables nesting 2025-12-15 11:42:22 -08:00
martinalong
277a41b14c
Update e2e screenshots for basic server examples
Updated screenshots to reflect UI changes from styles addition.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-15 11:42:21 -08:00
martinalong
2f8d1ecce0
Update generated schemas with stricter datetime pattern
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-15 11:42:19 -08:00
martinalong
aa79cb7c5e
Finalized variable set 2025-12-15 11:42:19 -08:00
martinalong
445a5836cf
Make it styles.variables instead of styles 2025-12-15 11:42:18 -08:00
martinalong
2fa243ae8c
Updates example to use theme colors and adds border radius 2025-12-15 11:42:18 -08:00
martinalong
db2872643c
Make properties optional 2025-12-15 11:42:18 -08:00
martinalong
f276ec6df9
Regenerate schemas after npm install
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-15 11:42:17 -08:00
martinalong
a8b3bf0ccd
Add utility to set + read theme 2025-12-15 11:42:17 -08:00
martinalong
aa8968808a
Add utility for using styles 2025-12-15 11:42:17 -08:00
martinalong
9e97bf3dfc
Add styles prop to host context 2025-12-15 11:42:16 -08:00
martinalong
83860d7c31
Have apps request display mode instead 2025-12-14 19:00:56 -08:00
Olivier Chafik
54344552b7
api: optional Client in AppBridge (allow custom forwarding), better protocol types (AppRequest, AppNotification, AppResult) (#146)
* 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>
2025-12-13 21:07:13 +00:00
Frédéric Barthelet
e99517d75c Implement BYO zod v3 or v4
Following recommendations from https://zod.dev/library-authors
2025-12-12 11:29:02 +01:00
Olivier Chafik
0408a6e9c7
release: 0.1.1 (prettier fix to unlock release) (#138)
* 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>
2025-12-12 00:44:04 +01:00
Olivier Chafik
eaea3f9e07
feat: store and expose hostContext in App class (#139)
* feat: store and expose hostContext in App class

Fixes #129 - The App class now stores the initial hostContext received
during initialization and exposes it via getHostContext().

Changes:
- Add _hostContext private property to App class
- Store result.hostContext in connect() method
- Add getHostContext() getter method (parallel to getHostCapabilities())
- Update onhostcontextchanged setter to merge partial updates into
  stored context
- Add default notification handler to update context even when
  user hasn't set onhostcontextchanged

This enables apps to:
- Access toolInfo immediately after connection (only in initial context)
- Render with correct theme/locale without waiting for first notification
- Synchronously access viewport, timezone, and other initial state

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: use sendHostContextChange for partial update accumulation test

Address PR review feedback: The test was using setHostContext with full
context spreads which didn't clearly demonstrate partial update
accumulation. Now uses sendHostContextChange directly to send truly
partial updates (only theme, then only viewport), making it clear
the App correctly merges multiple partial notifications.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-12 00:39:58 +01:00
Olivier Chafik
70b393a7e6
feat: implement ui/notifications/tool-cancelled + add missing App.onteardown (#120)
* feat: implement ui/notifications/tool-cancelled throughout SDK

Wire the tool-cancelled notification that hosts MUST send when tool
execution is cancelled (user action, timeout, classifier intervention, etc.):

- Add McpUiToolCancelledNotification type in spec.types.ts
- Generate Zod schema via ts-to-zod
- Add AppBridge.sendToolCancelled() method for hosts
- Add App.ontoolcancelled setter for guest UIs
- Export type and schema from types.ts
- Add tests for notification with/without reason

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: add App.onteardown handler for graceful shutdown

Wire the guest UI side of ui/resource-teardown request:

- Add onteardown setter in App class for guest UIs to handle teardown
- Allow ui/resource-teardown in assertRequestHandlerCapability
- Import McpUiResourceTeardownRequest/Result types
- Add tests for sync and async cleanup handlers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(example): wire tool-cancelled and teardown in basic-host

Update basic-host example to properly use the new notifications:

- Send sendToolCancelled when tool call promise rejects
- Send sendResourceTeardown when React component unmounts
- Store appBridge ref for cleanup access

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(example): implement graceful teardown per spec recommendation

Address review feedback: the host now waits for guest's teardown
response before unmounting, following the spec: "Host SHOULD wait
for a response before tearing down the resource (to prevent data loss)."

Changes:
- Add close button to tool call panels
- Two-phase unmount: isDestroying state dims panel and disables events
- sendResourceTeardown() completes before component removal
- Non-app tool results close immediately

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(examples): add onteardown handlers to demo apps

Demonstrate graceful shutdown with simulated 500ms cleanup work.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-11 20:31:17 +01:00
Olivier Chafik
f06340b6d9
build: auto-generate Zod schemas from TypeScript types using ts-to-zod (#116)
* 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>
2025-12-10 01:05:49 +01:00
Andrew Harvard
4953cd320e
Add media-src to CSP for video and audio support (#109)
This adds the media-src directive to the Content Security Policy to enable
MCP Apps to play video and audio content.

Changes:
- Add media-src to the restrictive default CSP in the spec
- Add media-src to the CSP construction from metadata in the spec
- Update resourceDomains documentation in spec to include media
- Update resourceDomains JSDoc in src/types.ts to include media-src

Fixes modelcontextprotocol/ext-apps#106
2025-12-10 01:10:58 +02:00
Anton Pidkuiko
6a8f5031be
Fix mimeType, CSP settings and QR code example (#111)
- Fix RESOURCE_MIME_TYPE to match spec: "text/html;profile=mcp-app"
- Add CSP field to McpUiSandboxResourceReadyNotification type and schema
- Update basic-host to extract and pass CSP metadata from resources
- Update sandbox.ts to dynamically inject CSP meta tag into inner iframe
- Remove static CSP from sandbox.html (now dynamic based on resource metadata)
- Update QR server to use custom read_resource handler for _meta injection
- Update requirements.txt to require mcp[cli]>=1.23.3

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-09 20:26:34 +01:00
Olivier Chafik
3ac7c7935b
Add RESOURCE_MIME_TYPE constant (#108)
* Add RESOURCE_MIME_TYPE constant

* Update app-bridge.ts

* update syntax
2025-12-09 19:10:56 +01:00
Anton Pidkuiko
d97ae07849
Merge pull request #88 from modelcontextprotocol/ochafik/theme-layout-enums
types: add McpUiTheme, McpUiDisplayMode
2025-12-08 15:33:06 +00:00