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)
Use the Audio Session API to declare audio as media playback so the
platform handles it correctly: background audio, lock screen controls,
Dynamic Island integration, and bypassing the iOS silent switch.
* Add MCPB packaging and Claude Code plugin for pdf-server
Two distribution paths for the pdf-server:
1. **MCPB bundle** (Claude Desktop MCP Directory):
- manifest.json: v0.3 manifest with tools, compatibility, privacy
- .mcpbignore: excludes source/tests from bundle
- icon.png: 64x64 PDF document icon
2. **Claude Code plugin** (plugin/):
- .mcp.json: declares local stdio server via npx
- commands: /pdf-research:read, /pdf-research:summarize
- skills: pdf-reading skill for document navigation
- Tested end-to-end: MCP server connects, all tools available
The plugin uses a local stdio MCP server pattern — the first known
instance in a knowledge-work plugin (all existing plugins use remote
HTTP connectors).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Run prettier:fix to satisfy CI formatting checks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add basic-server-preact, basic-server-solid, basic-server-svelte,
basic-server-vue, and debug-server to the publish workflows so they
are included in pkg-pr-new and npm deployments.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Replace the hardcoded list of allowed remote origins with a simple
HTTPS protocol check. Any HTTPS URL is now accepted for remote PDFs.
Local file allowlisting remains unchanged.
* fix(pdf-server): remove page-loading overlay
The overlay had multiple issues:
- Hardcoded white background broke dark mode
- Could get stuck visible, breaking sizing/layout
- Added little value since previous page stays visible during render
and the 150ms delay meant most renders completed before it showed
* prettier:fix
* 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)
* lazy PDF loading w/ PDFDataRangeTransport
* lint
* feat: lazy PDF loading via range transport + eager background preloading
Replace full-file download with PDFDataRangeTransport so PDF.js fetches
byte ranges on demand. First page renders immediately; remaining pages
load in background for search.
**Range transport (server + client)**
- server.ts: add read_pdf_bytes tool returning base64 chunks with offset
- mcp-app.ts: AppRangeTransport feeds PDF.js via fetchRange/fetchChunk
with parallel sub-requests for large ranges, Promise-based dedup of
concurrent requests, and a persistent range cache
**Background preloader**
- Sequential page 1→N text extraction, pauses during interactive
navigation (preloadPaused flag set in goToPage, cleared in renderPage)
- Debounced live search refresh (500ms) as pages load
- Search UI shows '(loading…)' suffix until all pages processed
**Loading indicators**
- SVG pie in toolbar: fills as pages load, fades on completion,
turns red on errors with tooltip listing failed pages
- Debounced page-loading overlay (150ms) for uncached page navigation
**Cleanup**
- Remove old full-file chunked download and progress bar
- Remove extractAllPageText (replaced by preloader)
- Remove verbose debug logs (Coverage, RangeReq, cache hit)
Add padding: 0 !important to .main.fullscreen so that
safe area insets applied via inline styles are overridden,
making the PDF viewer truly fullscreen edge-to-edge.
Also add .build directories to .prettierignore to fix
pre-commit hook failures from Swift build artifacts.
When the client advertises roots capability, the server queries roots/list
on initialization and subscribes to roots/list_changed notifications.
Any file:// roots pointing to existing directories are added to an
allowedLocalDirs set, enabling access to all PDFs under those directories
without needing to enumerate them via CLI args.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix: revert unrelated changes from bad rebase
Restores files that were accidentally modified alongside the MCP roots
feature: README, pdf-server UI (search feature), threejs example,
SDK guards (app.ts, app-bridge.ts), typedoc theme, media assets,
and e2e snapshots.
Move the agent skills section to the top of the README so readers
immediately see how to install and start building. Keep Claude Code
install commands front and center with a brief pointer to the agent
skills guide for other agents. Specification section moves below
Examples.
* Add PDF search feature to pdf-server
Adds full-text search functionality to the PDF viewer:
- Search button in toolbar (Ctrl/Cmd+F to open)
- Search bar with input, prev/next navigation, match count
- Text extraction and caching across all pages
- Highlight overlays using DOM Range API
- Case-insensitive search across entire document
- Keyboard shortcuts: Ctrl+F (open), Enter (next), Shift+Enter (prev), Escape (close)
Changes:
- mcp-app.html: Add search button, search bar, highlight layer
- src/mcp-app.css: Add search/highlight styles and PDF.js text layer rules
- src/mcp-app.ts: Add search state, functions, event listeners
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* update screenshots
* Add fullscreen button to threejs-server
* Fix prettier formatting
* Move search bar below toolbar, right-aligned
* Make search bar compact and right-aligned
* Float search bar over page content
* Ctrl/Cmd+F toggles search; pass through to browser when empty
* Hide search nav controls until query is entered
* Skip scroll when search highlight is already visible
* Fix search bar right-edge alignment with container border
* Prevent browser find when our search is open with text
* Cmd+F when search input is focused passes through to browser find
* Fix prettier formatting in README
* Remove unrelated formatting and threejs changes from PR
* prettier
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: guard against double-connect in App and AppBridge (#429)
Calling connect() twice on the same transport instance caused the MCP
SDK's Protocol class to chain onmessage handlers, so each incoming
message was processed twice. This made incoming responses get consumed
by the first processing (resolving the handler) and then trigger a
spurious "Received a response for an unknown message ID" error on the
second processing pass, since the handler was already removed from the
response map.
Add an explicit guard in both App.connect() and AppBridge.connect() that
throws if the instance is already connected. This converts the silent
message-corruption into a clear, actionable error and prevents
downstream confusion.
Adds three regression tests:
- AppBridge.connect() throws when already connected
- App.connect() throws when already connected
- Demonstrates the double-processing root cause and verifies it is fixed
Fixes#429https://claude.ai/code/session_01XU3FW1TpjBkyRbkBUH5gqR
* test: replace redundant regression test with cleaner same-transport guard check
The previous third test in "double-connect guard" never actually attempted
a double-connect — it created fresh instances and verified normal operation,
which every other test already covers. The stray bridge.onupdatemodelcontext
and bridgeTransport.close() at the top were leftover noise.
Replace it with a focused test that verifies the guard fires even when
the caller passes the *same* transport object (not just a different one),
which is the exact scenario described in #429.
https://claude.ai/code/session_01XU3FW1TpjBkyRbkBUH5gqR
---------
Co-authored-by: Claude <noreply@anthropic.com>
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>
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".