Users frequently call callServerTool("tool_name", args) instead of the
correct callServerTool({ name: "tool_name", arguments: args }), resulting
in a silent/confusing failure. Detect this and throw immediately with
a message that shows the correct call shape.
Also fixes the incorrect example in examples/pdf-server/README.md that
demonstrated this same wrong usage pattern.
Fixes#386https://claude.ai/code/session_01GqAyN4Ux7svWoU2HqsSLZF
Co-authored-by: Claude <noreply@anthropic.com>
In ChatGPT, we have our own sandbox <> host communication protocol that doesn't match the names of the protocol enforced by the "MUST" in the spec.
This changes that by marking the specific messages sent back and forth as a "SHOULD".
Tighten the parse-failure handler: silently ignore postMessage frames
where event.data?.jsonrpc !== "2.0" (i.e. not JSON-RPC at all — null,
undefined, a primitive, or an object from the host environment that
doesn't carry the jsonrpc field). Messages that do carry jsonrpc: "2.0"
but are otherwise malformed still surface via onerror so genuine protocol
errors aren't swallowed.
https://claude.ai/code/session_01DaJpUtSJf4hA7tnu3nJz8s
Co-authored-by: Claude <noreply@anthropic.com>
The skill name spec requires lowercase letters, numbers, and hyphens
only. Change `name` from "Migrate from OpenAI App" to `migrate-oai-app`.
Companion to #443, which does the same for the `create-mcp-app` skill.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
As per the spec (https://agentskills.io/specification) `name` should be:
"Max 64 characters. *Lowercase letters*, numbers, and *hyphens* only. Must not start or end with a hyphen."
Backport the `.tsd-typography` CSS fixes from upstream PR
JulianWowra/typedoc-github-theme#7 so document pages render with
GitHub-accurate heading spacing, list bullets, line-height, and code
block overflow. The override file and `customCss` config can be removed
once the PR is merged and the dependency is updated.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Clarify spec and SDK: accept UIResourceMeta in both resources/list and resources/read
The spec defines UIResource with _meta.ui, implicitly as an extension of the Resource type (resources/list), but examples and practice place _meta.ui on TextResourceContents (resources/read). The registerAppResource helper accepts _meta.ui in its config (which ends up in resources/list), but examples only return said _meta.ui from resources/read — and current hosts might be just ignoring it.
This change:
- Adds a 'Metadata Location' subsection to the draft spec explicitly stating that _meta.ui is valid on both the resource listing entry AND the content item, with content-item taking precedence.
- Updates the spec example to show _meta on the resource declaration (resources/list).
- Updates the CSP construction example to reference both locations.
- Clarifies McpUiAppResourceConfig JSDoc: _meta here appears in resources/list and serves as a listing-level fallback for when content items omit _meta.ui.
- Fixes the map-server example comment that incorrectly stated _meta must only be on the content item.
* Add McpUiReadResourceResult type for UI metadata in resources/read
* basic-host: support UIResourceMeta fallback from resources/list
---------
Co-authored-by: Claude <noreply@anthropic.com>
The term "external" is misleading for MCP Apps because developers
typically interpret it as "third-party." However, MCP App HTML runs in
a sandboxed iframe with no same-origin server, so *all* origins must be
declared—including where your own bundled JS/CSS is served from. Using
"network" instead avoids this confusion and aligns with the detailed
explanations in `patterns.md` and `spec.types.ts`.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Single quotes in `concurrently` commands work on Unix shells but not on
Windows Command Shell (`cmd.exe`), causing the `INPUT` environment
variable to not be set and npm scripts to fail with errors like:
'cross-env' is not recognized as an internal or external command
Error: INPUT environment variable is not set
Replace single quotes with escaped double quotes (`\"`) in npm scripts
in all example `package.json` files.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a new section to the patterns guide explaining how to configure
Content Security Policy and CORS for MCP Apps that make network requests:
- CSP via `_meta.ui.csp` controls browser-side permissions (`connectDomains`,
`resourceDomains`)
- CORS via `_meta.ui.domain` provides a stable origin for API servers to
allowlist
Includes a type-checked example showing `computeAppDomainForClaude()` helper
that hashes an MCP server URL to create a stable `*.claudemcpcontent.com`
subdomain. Also adds `@see` links to `McpUiResourceMeta` and `McpUiResourceCsp`
in `registerAppResource` JSDoc.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(pdf-server): handle HTTP 200 fallback in remote range requests
When a remote server ignores the Range header and returns HTTP 200
with the full body, readPdfRange previously passed the entire file
(potentially 10MB+) through as a single chunk. This bypassed the
512KB limit because:
1. The error check `!response.ok && status !== 206` short-circuits
on 200 (ok is true), so the full body is read via arrayBuffer()
2. No Content-Range header on a 200 response leaves totalBytes at 0
3. hasMore becomes `offset + fullSize < 0` = false, so the client
stops after one oversized message
Fix: detect HTTP 200, cache the full body in memory (to avoid
re-downloading on every subsequent chunk request), then slice to the
requested range. The 512KB per-message limit is now enforced for all
remote URLs regardless of Range request support.
* Add session-based PDF caching with timeout cleanup and size limits
- Add dual timeout strategy for cache cleanup:
- 10s inactivity timeout (resets on each access)
- 60s max lifetime (absolute timeout from creation)
- Add 50MB max size limit with both Content-Length and actual size checks
- Add unit tests for caching behavior including:
- Cache on HTTP 200 response (no range support)
- No cache on HTTP 206 response (range supported)
- Slice cached data for subsequent range requests
- Reject PDFs exceeding size limits
- Export getCacheSize() and clearCache() for testing
* refactor(pdf-server): make PDF cache session-local via factory pattern
- Replace module-level global cache with createPdfCache() factory
- Each server instance now gets its own isolated cache
- Export PdfCache interface for type-safe usage
- Update tests to use per-test cache instances
- Add test verifying cache isolation between sessions
---------
Co-authored-by: Claude <noreply@anthropic.com>
Update `mcp-app.css`, `mcp-app.module.css`, and Svelte/Vue component
styles across all `basic-server-*` examples (and `integration-server`)
to use CSS variables instead of hardcoded values:
- Remove component-local color variables (`--color-primary`, etc.)
- Add derived spacing variables to `global.css` based on `--spacing-unit`
- Replace hardcoded spacing with `--spacing-xs/sm/md/lg` variables
- Add app-defined accent color variables (`--color-accent`,
`--color-text-on-accent`) to `global.css` for brand customization
- Use app accent colors for button styling
- Update button hover to use `color-mix()` for theme-adaptive lightening
- Change focus-visible to use `--color-ring-primary` outline
This makes the templates more instructive for users and AI coding agents
building new MCP Apps by showing how to consume host-provided variables
semantically, define app-specific accent colors, and create adaptive
styling that integrates with host themes.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move the inline example from the `getUiCapability()` JSDoc to
`index.examples.ts` for type checking, following the pattern used
by other examples in the codebase.
The example now uses the correct MCP SDK API:
- `server.server.oninitialized` callback for post-initialization hook
- `server.server.getClientCapabilities()` to retrieve capabilities
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update `global.css` in all `basic-server-*` examples (and `integration-server`
for consistency) to better serve as templates for AI coding agents scaffolding
new MCP Apps.
Changes:
- Use CSS custom properties (`--font-sans`, `--color-text-primary`, etc.) with
sensible fallbacks, enabling host design system integration
- Add `color-scheme: light dark` and `light-dark()` fallbacks for theme support
- Include comprehensive typography: h1-h6, body text, `code`/`pre`/`kbd`, `b`/`strong`
- Move `#server-time` styles from global CSS to component stylesheets (classes
instead of IDs for better CSS practices)
Updates E2E test selectors in `DYNAMIC_MASKS` to match the new class-based
selectors.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* docs: fix basic-host setup instructions in quickstart
Add missing root-level npm install and build steps before running
the basic-host example. Without these steps, the example fails because
it imports from dist/src/ which doesn't exist until the root package
is built.
Fixes setup failure when following quickstart tutorial.
* Update quickstart.md
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
---------
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
Clarifies when to use `localStorage` vs server-side storage for view state:
- Scope section intro to "recoverable" view state (easy to recreate)
- Add guidance for state representing user effort (bookmarks, annotations,
custom configurations) to use app-only tools instead
- Note that `viewUUID` should also be passed to app-only tools for scoping
- Clarify that example links are specifically for `localStorage` approach
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document how to serve binary content (e.g., video) via MCP resources
as base64-encoded blobs. Includes server-side registration using the
`blob` field and client-side fetching with conversion to data URIs.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Documents the recommended approach for real-time dashboards that need to
poll server tools at regular intervals. Includes both Vanilla JS and
React examples with proper cleanup handling via `app.onteardown` and
`useEffect` cleanup functions respectively.
Also updates the "Tools that are private to Apps" section to mention
polling as a use case for app-only visibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Convert italic `_See example..._` text to `> [!NOTE]` callouts for better
visual prominence, and expand cross-references to include additional
relevant examples for each pattern.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The two-tool architecture previously had both tools returning identical
`SystemStats` data. This refactors them to properly separate concerns:
- `get-system-info` (Model-visible): Returns static system configuration
(hostname, platform, CPU model/count, total memory) sent once via
`ontoolresult`
- `poll-system-stats` (App-only): Returns dynamic metrics (per-core CPU
timing, memory usage, uptime) polled every 2 seconds
Moves `formatBytes()` and `formatUptime()` utilities to the client since
the server now returns raw values for client-side formatting.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rename "host styling" section to "host context" and add safe area
insets handling
- Replace abstract `renderLoadingUI`/`renderFinalUI` example with
concrete code preview pattern for `ontoolinputpartial`
- Rename callback parameter `params` → `ctx` for clarity across all
`onhostcontextchanged` handlers
- Add CSS snippet for fullscreen border-radius handling
- Expand display mode example to show `availableDisplayModes` check
- Fix minor typos and wording consistency
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>