Migrate JSDoc and markdown documentation from `{@includeCode ./file#region}`
tags to inline code fences with `source="./file#region"` attributes.
Code examples are now visible directly in source files while remaining
type-checked via their `.examples.ts` source files.
Add `scripts/sync-snippets.ts` to extract code from `//#region` blocks
and sync it into labeled fences. Run with `npm run sync:snippets`.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Update spec: drop Intents reference, rename Notify to Log
- Remove "intent" from the list of MCP-UI message types in the rationale
section (Intents concept is being dropped)
- Rename "Notify" to "Log" in the lifecycle diagram to better reflect
that notifications/message is for debugging/telemetry logging, not
for sending messages to the chat (which is now ui/message)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* spec: remove Intents reference from rationale
Remove 'intent' from the list of MCP-UI message types - Intents concept was dropped in earlier discussions.
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat(examples): add debug-server example
A comprehensive debug/development server for testing MCP Apps SDK features:
- Vanilla TypeScript UI with collapsible panels
- Message visualization (sent, received, errors)
- Server tool calling interface
- Multiple tool endpoints for testing
* refactor(debug-server): convert to React
- Replace vanilla TypeScript with React components
- Add comprehensive Host Styles panel showing all CSS variables grouped by category
- Use React hooks (useApp, useHostStyles, useAutoResize)
- Cleaner state management with useReducer for event log
- Collapsible sections for better organization
- CSS modules for scoped styling
* fix(debug-server): correct server name in main.ts
* Revert "refactor(debug-server): convert to React"
This reverts commit 5d22d2daa9a98ba412892447202ef10fbdb62f5b.
* fix(debug-server): update default values for multipleBlocks and includeMeta
* fix(debug-server): correct serve script and server name
- serve script now runs main.ts instead of server.ts
- Updated server name to 'Debug Server'
- Fixed npx command in comment
* fix: increase maxHeight to 6000px and add tools capability to debug app
- basic-host: Increase maxHeight from 600 to 6000px
- debug-server: Add tools capability to enable oncalltool/onlisttools handlers
* fix(debug-server): use consistent callback names for event tracking
Event types now match callback names (ontoolinput, ontoolresult, etc.)
so the Callback Status panel shows correct counts and payloads.
* feat(debug-server): add Update (Image) button for model context
* feat(debug-server): add expandable event log entries
- Click on any event log row to expand/collapse
- Arrow indicator rotates when expanded
- Full JSON payload shown indented in pre block
- Max height with scroll for large payloads
* style(debug-server): format long line in fullPayload function
* test(debug-server): add to E2E tests and screenshot specs
* chore: regenerate package-lock.json for cross-platform compatibility
* update dep
* fix(map-server): simplify location update message format
* fix(say-server): pass host to streamable_http_app for non-localhost deployments
* refactor(pdf-server): simplify to stateless range-query architecture
- Remove caching/indexing in favor of direct HTTP Range requests
- Use HEAD requests to get file size (no full download)
- Use Range requests to proxy byte chunks (no caching)
- Local files: fs.read with offset/length
- Remote files: HTTP Range header
- Zero memory footprint (no PDF caching)
- Truly stateless (no session management needed)
- Single server.ts (~350 lines) + main.ts CLI entry point
- Instant startup (no preloading)
- Security: whitelist local files, allowed origins
Removed files:
- src/pdf-indexer.ts
- src/pdf-loader.ts
- src/types.ts
* feat(pdf-server): add dark mode support
- Add CSS variables with light-dark() function for automatic theme switching
- Sync theme with host via applyDocumentTheme()
- Apply host CSS variables via applyHostStyleVariables()
* feat(pdf-server): add list_pdfs tool back
Lists local files and allowed remote origins.
Also moves CHUNK_SIZE to module level constant.
* feat(pdf-server): improve tool descriptions and increase context limit
- display_pdf: list all allowed domains in description
- Increase MAX_MODEL_CONTEXT_LENGTH to 15000
- Move CHUNK_SIZE to module level constant
* chore(say-server): remove deployment docs from repo
Keep server.py fix for non-localhost deployments.
Deployment docs kept locally but not in repo.
* refactor(pdf-server): simplify updateModelContext format
- Add widget ID for multi-widget disambiguation
- Use concise header: 'PDF viewer (id) | title | Current Page: X/Y'
- Add 'Page content:' prefix before text
- Keep selection markers (<pdf-selection>...</pdf-selection>)
* refactor: rename widgetUUID to viewUUID for consistency
Aligns with main's standardization on 'view' terminology (PR #325).
Also dynamically generate allowed domains in display_pdf description.
* viewUUID
* fix(map-server): fix syntax error in location update message
* fix(pdf-server): restore package.json, improve server docs
- Restore --external pdfjs-dist in build
- Rewrite server.ts header for newcomers (list tools, not implementation details)
- Minimize main.ts diff
* chore(pdf-server): remove unused addAllowedOrigin/addAllowedLocalFile
* docs(pdf-server): update README for new architecture
* docs(pdf-server): restore full README, add theming section, remove get_pdf_info
* rm
* fix(pdf-server): restore createMcpExpressApp and error handling
- Use createMcpExpressApp for DNS rebinding protection
- Restore error callback in app.listen()
* fix(say-server): pass host to streamable_http_app for non-localhost deployments
* chore(say-server): remove deployment docs from repo
* widgetId->tool id
* fix(map-server): add null check for center in location update
chore(pdf-server): dedupe and sort allowed origins
* fix(map-server): use transparent background for rounded corners
* prettier
* docs: standardize UI terminology to use "view" consistently
Replaces "widget" and "Guest UI" terminology with "view" across
the codebase as decided in the community survey.
This change updates:
- Specification document
- SDK source code and JSDoc comments
- Example servers and documentation
- Plugin documentation and skills
Closes#71
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add explicit backtick-wrapped display text to all `{@link}` tags for
monospace rendering in TypeDoc output. This improves readability by:
- Using monospace font for code references (types, methods, functions)
- Stripping module prefixes from display text (e.g., `app!App.connect`
displays as `App.connect`)
Updated files across the SDK including `App`, `AppBridge`,
`PostMessageTransport`, React hooks, server helpers, types, and
documentation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Configure TypeDoc to use the GitHub-styled theme for better visual
consistency with the project's GitHub presence. Also reorganize the
config options and enable group navigation for improved documentation
structure.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(qr-server): embed widget HTML for self-contained usage
Embed the widget HTML directly in server.py following the same pattern
as the say-server. This allows the QR server to be run without any
local file dependencies using `uv run <url>`.
The get_widget_html() function prefers the built version from dist/
for local development but falls back to the embedded HTML for unbundled
usage.
* refactor(qr-server): remove widget.html and simplify embedded HTML
Address PR review feedback:
- Remove separate widget.html file (no longer needed)
- Remove get_widget_html() function and dist/mcp-app.html reference
- Inline EMBEDDED_WIDGET_HTML directly in widget() resource
- Remove unused Path import
The server is now fully self-contained in a single file.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Update the spec to clarify that:
- ui.domain format and validation rules are host-dependent
- Servers must consult host-specific documentation for expected format
- Common patterns: hash-based subdomains, URL-derived subdomains
- Updated examples to reflect realistic host-controlled domains
This addresses the gap between the spec's previous implied flexibility
(arbitrary domains like weather-widget.example.com) and real-world
constraints where hosts must control sandbox domains for security.
Each pattern section now includes a "See examples/..." link pointing
to a working implementation in the repository. This helps readers
quickly find real code demonstrating each pattern.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add new pattern showing how to combine `updateModelContext()` with
`sendMessage()` when data exceeds message size limits. The example
demonstrates offloading a large transcript to model context first,
then sending a brief trigger message.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Documents `updateModelContext` for keeping the model informed about user
interactions. The example shows a shopping cart use case with YAML frontmatter
for structured, parseable context.
Also refines the `updateModelContext` JSDoc to clarify the difference from
`sendMessage` and removes the `structuredContent` example.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add `IntersectionObserver` pattern for pausing expensive operations
(animations, WebGL, polling) when widgets scroll out of view.
- Add `visibilityBasedPause` example to `patterns.tsx` with play/pause
callbacks and `onteardown` cleanup
- Document pattern in `patterns.md` with link to MDN docs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replaces the TODO stub with complete server-side and client-side examples
based on the `pdf-server` implementation pattern:
- Server: shows returning `widgetUUID` via `CallToolResult._meta`
- Client: shows receiving UUID via `ontoolresult`, using it as localStorage
key with generic `saveState<T>()` / `loadState<T>()` helpers
Also clarifies the distinction between widget state persistence (UI state
surviving page reloads) and `updateModelContext()` (model-visible state).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds JSDoc example `App_updateModelContext_reportError` showing how to
report runtime errors (e.g., microphone permission denied) back to the
model using `updateModelContext`.
Updates patterns.md with clearer framing:
- Server-side (tool handler): return `{ isError: true, ... }`
- Client-side (app): use `updateModelContext` for runtime errors
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Expand `App_ontoolinputpartial_progressiveRendering` example in
`app.examples.ts` to show full state management pattern with
`toolInputs` and `toolInputsPartial` variables
- Add healed JSON caveat to `ontoolinputpartial` JSDoc in `app.ts`
- Update `patterns.md` to reference the expanded example and document
the streaming preview pattern
- Remove empty `lowerPerceivedLatency` placeholder from `patterns.tsx`
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add `App_onhostcontextchanged_respondToDisplayMode` example showing how to
listen for display mode changes and update UI with `classList.toggle()`.
Update `App_requestDisplayMode_fullscreen` to `App_requestDisplayMode_toggle`
to show the common toggle pattern checking `availableDisplayModes` first.
Refactor full examples (pdf-server, shadertoy-server) to use
`classList.toggle(class, condition)` instead of add/remove branches.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Merge the separate "Support native host styling using CSS variables" and
"Reacting to light/dark theme changes" sections into a single "Matching
host styling (CSS variables, theme, and fonts)" pattern. This provides
clearer guidance by covering all three concerns together.
- Rename `docs/patterns.ts` to `docs/patterns.tsx` for JSX support
- Add `hostStylingVanillaJs` and `hostStylingReact` consolidated examples
- Enhance `applyHostFonts_fromHostContext` to apply initial fonts after
`connect()`, not just on context change
- Add CSS usage examples to `applyHostStyleVariables()` JSDoc
- Update font example to use `var(--font-sans, system-ui, sans-serif)`
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reference existing JSDoc examples instead of maintaining a separate one in
`docs/patterns.ts`:
- Vanilla JS: `applyDocumentTheme_fromHostContext` from `styles.examples.ts`
- React: `useDocumentTheme_conditionalRender` for reactive theme reading
Expand `applyDocumentTheme_fromHostContext` example to show both the
`onhostcontextchanged` handler and initial theme application after `connect()`.
Note in the docs that `useHostStyles()` applies theme automatically, so React
apps don't need additional setup unless they want to read the theme reactively
for conditional rendering.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
References existing type-checked examples instead of a stub:
- Vanilla JS: `applyHostStyleVariables_fromHostContext` from `src/styles.examples.ts`
- React: `useHostStyles_basicUsage` from `src/react/useHostStyles.examples.tsx`
Expanded `applyHostStyleVariables_fromHostContext` to show the full pattern:
using CSS variables in styles, applying on `onhostcontextchanged`, and
applying initial styles after `connect()`.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document the `_meta.ui.visibility: ["app"]` feature in `docs/patterns.md`
by referencing the existing type-checked example from
`src/server/index.examples.ts#registerAppTool_toolVisibility`.
- Fix typo: `["apps"]` → `["app"]` (singular)
- Remove placeholder function from `docs/patterns.ts`
- Expand description to explain use cases
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduces a patterns documentation page for common MCP Apps recipes.
The skeleton includes TODO sections for: perceived latency, iframe/MCP Apps
coexistence, authenticated calls, private tools, theme changes, fullscreen,
host styling, data persistence, OpenAI migration, and error handling.
- Add `docs/patterns.md` to `projectDocuments` in `typedoc.config.mjs`
- Add `docs/patterns.ts` companion file with region-delimited code stubs
- Include `docs/**/*.ts` in `tsconfig.json` for type-checking
- Document the standalone docs pattern in `CLAUDE.md`
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After commit 65a62a9f, the server startup code was moved from server.ts
to main.ts, but the serve:http script was not updated accordingly.
This caused 9 example servers to fail to start when running npm start:
- budget-allocator-server
- cohort-heatmap-server
- customer-segmentation-server
- integration-server
- map-server
- scenario-modeler-server
- system-monitor-server
- threejs-server
- wiki-explorer-server
The server.ts file now only exports createServer(), while main.ts
contains the actual server startup logic.
This enables users to install the `mcp-apps` plugin via:
/plugin marketplace add modelcontextprotocol/ext-apps
/plugin install mcp-apps@modelcontextprotocol-ext-apps
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Follow-up to the examples extraction: pass dependencies as function
parameters instead of using global stub declarations, rename region
names to match method names (e.g., `AppBridge_guestCapabilities_*` →
`AppBridge_getAppCapabilities_*`), and simplify examples using optional
chaining.
Also clarifies `RESOURCE_URI_META_KEY` documentation to indicate it's
for tool definition metadata (from `tools/list`), not tool result
metadata, and removes the redundant `setNotificationHandler` example
in favor of the simpler event setter approach.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract inline code examples from JSDoc comments into companion
`.examples.ts`/`.examples.tsx` files. Examples are now:
- Type-checked by wrapping them in functions
- Referenced via `{@includeCode ./file.examples.ts#regionName}` tags
- Organized using `//#region` and `//#endregion` markers
This keeps the main source files cleaner while ensuring examples
compile correctly. Updated TypeDoc config with `exampleTag: false`
to support title text on `@example` tags.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Relative directory links like `](examples/map-server)` caused TypeDoc
warnings ("relative path is not a file") and resulted in broken links
in the generated API documentation. Converted all 20 example directory
links to full GitHub URLs while keeping image paths relative.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add screenshot reference
- Remove GPU prerequisite (not needed, wasn't requested)
- Use GitHub raw URLs instead of local file paths
- Simplify Docker section
- Fix Claude Desktop config to use remote URL
* Add say-server: streaming TTS MCP App with karaoke UI
- Streaming TTS MCP App with real-time word highlighting
- React widget with pause/resume controls
- Debounced model context updates
- Self-contained server.py for standalone uv run
Co-authored-by: Claude <noreply@anthropic.com>
* Update server.py
* fix(say-server): fix React/Zod version conflicts in widget
- Pin Zod to v3.25.1 via esm.sh deps param (fixes .custom() error)
- Add external=react,react-dom to prevent duplicate React instances
- Update React from 19.1.0 to 19.2.0
- Import React for Babel's classic JSX transform
- Consolidate imports: only use @modelcontextprotocol/ext-apps/react
- Use Babel from unpkg.com instead of esm.sh
- Simplify resource decorator with meta= parameter
- Update CSP to allow both esm.sh and unpkg.com
* fix(say-server): show play button when paused, restart when finished
* feat(say-server): add fullscreen button, remove inline scroll
- Add fullscreen toggle button (appears on hover when available)
- Remove max-height/scroll in inline mode for cleaner display
- Enable scrolling only in fullscreen mode
- Track displayMode and fullscreenAvailable state
- Handle onHostContextChanged to detect fullscreen support
* fix(say-server): fix fullscreen button visibility and prevent multiple audio streams
- Check initial host context for fullscreen availability (not just updates)
- Add audioOperationInProgressRef guard to prevent concurrent audio operations
- Prevents race conditions from rapid clicks/double-clicks
* fix(qr-server): use meta parameter instead of manual handler patching
Simplified CSP metadata handling to match say-server's approach:
- Use meta parameter on @mcp.resource decorator directly
- Removed custom _read_resource_with_meta handler and handler replacement
* fix(say-server): simplify controls to prevent multiple audio streams
- Remove onClick from text display (was conflicting with double-click)
- Always show overlay button (with pause icon when playing)
- Lower opacity (0.3) when playing, full on hover
- Button shows: ▶️ (play), ⏸️ (pause), 🔄 (restart)
- Double-click text to restart still works
- Eliminates click/dblclick race condition
* fix(say-server): only show pause button on hover
- Play/restart buttons visible normally
- Pause button hidden until hover (doesn't block karaoke text)
* fix(say-server): fix partial input handling and session management
- Add promise lock to initTTSQueue to prevent concurrent initialization
- Reset queueIdRef and lastTextRef in ontoolresult for next tool call
- Close existing AudioContext when starting new session
- Reset all playback state (chunks, timings, position) on new session
- Fixes: text deltas not sent when new tool call has shorter text
* fix(say-server): detect new sessions by text comparison, not queueIdRef reset
- Don't reset queueIdRef in ontoolresult - audio should keep playing
- Detect new sessions in ontoolinputpartial/ontoolinput by checking if
new text starts with lastTextRef (continuation) or not (new session)
- Only reset and create new queue when genuinely new session detected
- Fixes: pause/play was creating new streams because queueIdRef was reset
* feat(say-server): add theming, floating button, and keyboard shortcuts
Theming:
- Use CSS variables (--font-sans, --color-text-primary/secondary) with fallbacks
- Apply host fonts via applyHostFonts() on connect and context changes
- Apply host style variables via applyHostStyleVariables()
- Apply document theme via applyDocumentTheme()
Floating button:
- Button follows cursor position (below current line being spoken)
- Uses invisible cursor marker element for accurate positioning
- Shows ⏸️ when playing, ▶️ when paused, 🔄 when finished
- Low opacity when playing, full on hover
Keyboard shortcuts:
- Space: toggle play/pause
- Enter: toggle fullscreen (when available)
UI changes:
- Large overlay only shown for initial play (idle state)
- Floating button used during playback for less intrusive controls
* docs(say-server): add TODO items for future improvements
* fix(say-server): simplify to fixed play button at top right
- Remove floating cursor-following button (was too complex)
- Fixed play button at top-right corner
- Low opacity when playing, full on hover
- Keep theming and keyboard shortcuts (Space/Enter)
- Add say-server to E2E tests
* test(e2e): add say-server to tests but skip in CI
Say-server requires Pocket TTS model (~500MB) and GPU support,
which isn't available in the Docker CI environment. Skip it for now.
* test(e2e): add say-server and qr-server to screenshot generation
- Remove say-server from SKIP_SERVERS (widget works without TTS model)
- Add say-server masks for play buttons
- Add both say-server and qr-server to grid screenshot generator
* fix(say-server): restore working play/pause overlay, keep theming and keyboard shortcuts
Reverted to working commit 413beca and carefully reapplied:
- CSS variables for theming (--font-sans, --color-text-primary/secondary)
- Dark mode support via @media (prefers-color-scheme)
- Host theming via applyHostStyleVariables/applyHostFonts/applyDocumentTheme
- Keyboard shortcuts: Space = play/pause, Enter = fullscreen
Preserved working behavior:
- Play overlay visible when not playing, hover to show when playing
- Pause on click works correctly
- Karaoke highlighting works
* fix(say-server): minimal CSS-only theming, no JS changes from working version
Only CSS changes from working commit 413beca:
- Added CSS variables for theming foundation
- No JavaScript changes (reverted theming calls and keyboard shortcuts)
This isolates whether the issue is CSS or JS related.
* feat(say-server): add autoPlay param and Reset button
- Add autoPlay parameter (default: true) with Pydantic Field description
- Description visible in MCP tool schema: 'browsers may block autoplay'
- Add Reset button next to Fullscreen button (bottom right)
- Both buttons share controlBtn base styles, shown on hover
- Widget reads autoPlay from tool input params
* fix(say-server): update FastMCP API for new SDK version
Python SDK refactored transport params from constructor to run():
- Remove port, stateless_http from FastMCP() constructor
- Pass stateless_http=True to streamable_http_app() instead
* debug(say-server): add console logs to trace audio stream issue
Logging added to:
- togglePlayPause (all branches)
- initTTSQueue (entry and AudioContext creation)
- restartPlayback (entry)
- ontoolinputpartial/ontoolinput (entry and new session detection)
Open browser DevTools console and reproduce the issue - logs will show what's being called.
* feat(say-server): add play/pause buttons in top-left and bottom-right corners
- Top left: playPauseTopBtn for quick access
- Bottom right: playPauseBtn alongside reset and fullscreen
- Both show on hover with same styling as other control buttons
- Icons: ▶️ (play), ⏸️ (pause), 🔄 (restart when finished)
* fix(say-server): simplify UI and fix pause/resume audio duplication
- Remove central play overlay, use single toolbar in top-right
- Fix audio duplication on pause/resume (only defer to pendingChunks for initial autoplay)
- Remove double-click to restart (use toolbar restart button)
- Sync displayMode when host changes it externally
- Click on text to play/pause
* feat(say-server): add voice selection support
- Add list_voices tool to show available voices
- Add voice parameter to say tool (predefined names, HuggingFace URLs, or local paths)
- Predefined voices: alba, marius, javert, jean, cosette, eponine, azelma, fantine
- Update README with voice documentation
* docs(say-server): improve tool description for better LLM triggering
- Add English-only constraint prominently in first line and note
- List common trigger patterns (say, speak, read aloud, etc.)
- Update text parameter description to mention English
- Keep description concise for quick LLM scanning
* feat(say-server): add speak lock for multi-widget coordination
When multiple TTS widgets exist, only one plays at a time:
- Widget announces to localStorage when starting playback
- Playing widgets poll localStorage every 200ms
- If another widget starts, previous one pauses automatically
- Lock is cleared on pause/finish/teardown
Uses _meta.widgetUUID in tool result for widget identification.
* update package.json of say
* feat(say-server): add screenshots and update README gallery
- Add say-server to demo gallery with 300x300 grid-cell.png
- Fix qr-server grid-cell.png dimensions (was 672x668, now 300x300)
- Add golden snapshot for say-server E2E tests
- Add full screenshot and grid-cell thumbnail for say-server
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* style(say-server): apply prettier formatting
- Add blank lines in README for better readability
- Add trailing newline to package.json
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat(say-server): add Escape key to exit fullscreen and update docs
- Add onKeyDown handler to main element for Escape key
- Update README with full list of MCP App features:
- Model context updates
- Native theming
- Fullscreen mode
- Multi-widget speak lock
- Update server.py docstring with feature documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(say-server): add queue timeout to prevent infinite polling
The TTS queue could hang forever if:
- The LLM stops generating mid-stream (no end signal)
- User cancels before tool completes
- Network interruption prevents end_tts_queue call
Changes:
- Add last_activity timestamp to track queue activity
- Add 30-second timeout (QUEUE_TIMEOUT_SECONDS)
- Poll with 5-second timeout, checking for stale queues
- Mark stale queues as "error" so widget stops polling
- Return error message in poll_tts_audio response
- Add error logging in widget polling loop
This prevents tool calls from running forever when queues are abandoned.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* debug(say-server): add logging to track queue lifecycle
Add console logging to debug why end_tts_queue might not be called:
Widget-side:
- Log queueId in ontoolinputpartial, ontoolinput, ontoolresult
- Log when new session is detected (queue reset)
- Log when initTTSQueue fails
- Log when end_tts_queue is called/not called
Server-side:
- Log when end_tts_queue is called
- Log warnings for unknown queues
- Log info for already-ended queues
This will help identify if the issue is:
- User interruption (ontoolresult never called)
- Session reset (queueId becomes null)
- Host bug (callback dropped)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* perf(say-server): add initial delay before polling
Add 150ms delay before first poll to give TTS model time to generate
the first audio chunk. This reduces unnecessary polling and server load.
Current backoff after that:
- 30ms if chunks received (keep streaming fast)
- 80ms if no chunks (wait longer for generation)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(say-server): use adaptive polling instead of fixed initial delay
Previous approach: Always wait 150ms before first poll
Problem: Even when chunks are ready, we wait unnecessarily
New approach: Adaptive polling
- Start polling immediately (no initial delay)
- 20ms backoff when receiving chunks (fast streaming)
- Exponential backoff when no chunks: 50ms → 100ms → 150ms max
- Reset backoff when chunks start flowing
This reduces latency when TTS is fast while being polite when it's slow.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat(say-server): add speaker icon to server info
Uses SVG data URI for a speaker with sound waves icon.
* docs(say-server): add comprehensive third-party licensing information
- Expand License section in README with component attribution table
- Add voice collection license matrix with commercial use indicators
- Add warning about non-commercial expresso/ears voice collections
- Clarify NON-COMMERCIAL restriction in list_voices() output
- Use consistent CC-BY formatting (hyphenated)
* Update last activity to prevent timeout during active polling
* feat(say-server): add info button, SVG icons, and UI fixes
- Replace emoji play/pause buttons with neutral white SVG icons
- Add (i) info button in bottom-right with attribution popup
- Use app.openLink() API for external links in popup
- Add dynamic padding to fit popup when shown
- Make create_tts_queue async to fix AnyIO event loop error
- Add better error logging for TTS queue initialization
- Update README with openLink feature documentation
- Remove unnecessary HuggingFace login prerequisites
* docs(say-server): document multi-widget speak lock mechanism
* prettier:fix
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat(shadertoy): add proper mouse/touch interaction support
- Fix iMouse uniform to match official Shadertoy specification:
- iMouse.xy only updates while button/touch is held down
- iMouse.zw uses positive values when down, negative when released
- Enables proper click detection via iMouse.z > 0
- Add touch event support for mobile devices:
- touchstart/touchmove/touchend/touchcancel handlers
- Same behavior as mouse events
- Update tool description with mouse interaction documentation
- Update README with:
- Mouse & Touch Interaction feature
- Improved Julia Set example with click detection
- iMouse specification table and usage examples
The iMouse uniform is a core Shadertoy feature used by popular shaders
like Star Nest, raymarching examples, and particle systems.
* style: fix Prettier formatting in shadertoy README
* update qr-server w/ python sdk fix
* feat(qr-server): use Python SDK meta parameter for resource CSP metadata
- Update qr-server to use the new meta parameter on @mcp.resource decorator
instead of manually overriding the read_resource handler
- Add ui.resourceUri to tool meta alongside legacy ui/resourceUri for forward compatibility
- Simplify server.py by removing the custom _read_resource_with_meta handler
- Add qr-server to grid screenshot generation tests
- Update grid-cell.png screenshot
This leverages the Python SDK's native support for resource metadata,
eliminating the need for low-level handler manipulation.
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>