Commit graph

345 commits

Author SHA1 Message Date
Olivier Chafik
94c5dff983
docs(qr-server): clarify that repo clone is required 2026-01-16 14:03:46 +00:00
Olivier Chafik
cce8d5c7a3
docs: add MCP client configuration to example READMEs
Add stdio transport configuration snippets near the top of each example
README to help users quickly set up the servers in their MCP clients.

- Node.js examples use npx with the published npm packages
- Python qr-server uses uv with local path
- Removed Claude Desktop-specific references from qr-server
2026-01-16 14:00:57 +00:00
Olivier Chafik
8c3b1daf7e
chore: bump version to 0.4.1 (#282) v0.4.1 2026-01-15 16:11:53 +00:00
Anton Pidkuiko
be8d725974
Merge pull request #272 from modelcontextprotocol/uv-qr-server
feat(qr-server): migrate to uv with PEP 723 inline dependencies
2026-01-15 14:29:33 +00:00
Olivier Chafik
0936d52d0a
feat(shadertoy): show fullscreen button only on widget hover, add min-height (#281) 2026-01-15 14:15:17 +00:00
Olivier Chafik
b78cd74c1b
feat(shadertoy): add fullscreen support + ditch insets for max visual effect (#278)
* feat(shadertoy): add fullscreen support

Add fullscreen toggle button that appears when the host supports fullscreen
display mode. Uses the same pattern as pdf-server:
- Check availableDisplayModes in host context
- Show/hide button based on capability
- Toggle between inline and fullscreen via requestDisplayMode()
- Update UI state on host context changes

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

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

* fix(shadertoy): button visibility after exiting fullscreen + Escape key

- Only update button visibility when availableDisplayModes is present
  in context (partial updates don't include all fields)
- Add Escape key handler to exit fullscreen mode

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

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 13:01:55 +00:00
Olivier Chafik
89a684546b
fix(examples): resolve DIST_DIR path for npm package execution (#277)
* fix(examples): resolve DIST_DIR path for npm package execution

When servers are compiled to dist/server.js and published to npm,
`import.meta.dirname` already points to dist/, so joining with "dist"
results in dist/dist/ which doesn't exist.

This fix detects whether we're running from TypeScript source or
compiled JavaScript and adjusts the path accordingly:
- From source (server.ts): use dist/ subdirectory
- From compiled (dist/server.js): use current directory

Fixes ENOENT errors like:
"ENOENT: no such file or directory, open '.../dist/dist/mcp-app.html'"

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

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

* fix(pdf-server): mark pdfjs-dist as external in bundle

The pdf.worker.mjs file wasn't being found when running from npm
because bun bundled pdfjs-dist but didn't include the worker file.

By marking pdfjs-dist as external, it uses the installed package
from node_modules at runtime where the worker is available.

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

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 12:23:13 +00:00
Olivier Chafik
847427aeef
pdf-server: fix scrolling gap in inline mode (#280)
* map-server: fix async/await in ontoolresult, remove unused getViewStorageKey

* pdf-server: fix scrolling gap in inline mode

- Set html/body background to match .main background color
  This hides any gap between .main and iframe border
- Change .main from height:100% to min-height:100%
  Ensures .main fills container properly
2026-01-15 12:22:58 +00:00
Olivier Chafik
b94982cc35
fix[examples/transcript]: fix transitional deltas (#275)
* fix transcript deltas

* Update mcp-app.css
2026-01-15 12:06:02 +00:00
Anton Pidkuiko MacBook
489d28b6da
fix: increase webServer timeout for uv dependency download
uv needs extra time on first run to download Python dependencies
2026-01-15 11:53:27 +00:00
Copilot
c73d36343b
fix: change unknown source message log from error to debug level (#239)
* Initial plan

* Change console.error to console.debug for unknown message sources

Co-authored-by: liady <7003853+liady@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: liady <7003853+liady@users.noreply.github.com>
2026-01-15 11:51:27 +00:00
Anton Pidkuiko
dbc7a41550
Merge pull request #274 from matteo8p/use-tool-type-from-official-sdk
Use `Tool` as the input type in `getToolUiResourceUri`
2026-01-15 11:45:46 +00:00
Anton Pidkuiko MacBook
656a0292ae
feat: add QR Code to README gallery + rename to QR Code Server
- Add grid-cell.png screenshot for README gallery
- Rename 'QR Server' to 'QR Code Server' everywhere
- Add QR Code (Python) entry to examples table in README
2026-01-15 11:36:21 +00:00
Jerome
65a62a9fae
feat: compile example servers to JavaScript for npm consumption (#259)
* feat: compile example servers to JavaScript for npm consumption

Add TypeScript compilation for server code so the example packages can be
imported and used by consumers without requiring TypeScript compilation.

Changes:
- Add tsconfig.server.json to each example for compiling server code
- Update package.json exports to point to compiled dist/server/server.js
- Add types field pointing to dist/server/server.d.ts
- Update build scripts to include server compilation step
- Fix .ts import extensions to .js in customer-segmentation-server

This enables importing the createServer function from published packages:
  import { createServer } from '@modelcontextprotocol/server-basic-react';

* fix: add type assertion for Nominatim API response

* chore: regenerate schemas

* refactor: split server examples into library and binary entry points

- server.ts: exports createServer() only (library entry point)
- main.ts: entry point with main() that runs the server (binary)
- package.json: adds bin field for npx support, uses inline bun build
- tsconfig.server.json: emitDeclarationOnly, outputs to dist/

This allows:
1. Importing the server as a library: import { createServer } from '@modelcontextprotocol/server-basic-react'
2. Running with npx: npx @modelcontextprotocol/server-basic-react [--stdio]

Added migration script at scripts/migrate-server-examples.ts

* refactor: migrate remaining server examples to library/binary structure

Apply the same refactoring to all 13 remaining server examples:
- scenario-modeler-server, shadertoy-server, map-server
- cohort-heatmap-server, customer-segmentation-server, video-resource-server
- system-monitor-server, budget-allocator-server, sheet-music-server
- threejs-server, integration-server, transcript-server, wiki-explorer-server

Each now has:
- server.ts: exports createServer() (library)
- main.ts: runs the server (binary with shebang)
- bin field in package.json for npx support

* chore: remove unused server-utils.ts from video-resource-server/src

* update

* fix(build): make Windows-compatible by removing chmod and fixing bun externals

- Remove 'chmod +x dist/index.js' which doesn't exist on Windows
- Add '--external ./server.js' to prevent bun from treating the import as a second entry point

* fix(build): use .ts import for bun compatibility

- Change import from './server.js' to './server.ts' in main.ts files
- Remove --external flag since bun should inline everything
- Fixes Windows build where bun couldn't resolve .js to .ts properly

* fix(build): use --external for Windows bun compatibility

Bun on Windows incorrectly treats imported .ts files as entry points.
Use --external './server.js' to work around this, creating a runtime
dependency between index.js and server.js.

* style: fix prettier formatting in pdf-server/main.ts

* fix(build): remove quotes from --external for Windows cmd.exe compatibility

* fix(build): use glob pattern for --external to work on all platforms

The literal path --external ./server.js was not matching the import.
Using glob pattern --external "./server*" correctly externalizes the server module.

* fix(build): use */server.js pattern for --external

The "./server*" pattern was not matching on Windows.
Using "*/server.js" matches any path ending in /server.js which works cross-platform.

* fix(build): use *server.js pattern without slash for Windows compatibility

* update package-lock

* chore: regenerate package-lock.json for cross-platform compatibility

* fix(build): use ./server.js instead of glob pattern for Windows compatibility

* fix(build): use double quotes for banner to fix Windows cmd.exe compatibility

---------

Co-authored-by: Olivier Chafik <ochafik@anthropic.com>
2026-01-14 23:46:17 +00:00
Olivier Chafik
75cbf8612c
feat(basic-host): URL params, fullscreen mode, unified layout (#266)
* basic-host: handle containerDimensions

* feat(basic-host): Unified tool call layout with shared collapsible panels

* snapshots

* format
2026-01-14 22:09:41 +00:00
Olivier Chafik
75ecd62384
fix(examples): improve updateModelContext with structured YAML frontmatter (#271)
* map-server: fix async/await in ontoolresult, remove unused getViewStorageKey

* fix(map-server): improve updateModelContext and fix initialization

- Use structured YAML frontmatter format for model context (like pdf-server)
- Add tool name, altitude, and cleaner data format
- Fix initialization deadlock: app.connect() was inside ontoolresult handler
  which could never fire until connected
- Fix view state persistence: widgetUUID now properly extracted from
  ontoolresult and used to restore persisted camera position
- Server now includes widgetUUID in tool result _meta for widget identification

* fix(pdf-server): use widgetUUID for page persistence

- Add widgetUUID to tool result _meta for widget identification
- Use widgetUUID instead of generated key (pdfUrl+toolId) for localStorage
- Enables reliable page restoration when revisiting PDF widgets

* fix(transcript-server): use structured YAML frontmatter for model context

- Add tool name, listening status, and unsent entry count in frontmatter
- Consistent format with pdf-server and map-server

* update names

* drop bogus altitude

* Update mcp-app.ts
2026-01-14 22:08:09 +00:00
Matthew Wang
5bb0c6b4c7 Use as the input type in 2026-01-14 13:07:08 -08:00
Anton Pidkuiko MacBook
2ee15420a0
fix: add default text value for QR code generation
Without a default, the test would fail since text is required.
Uses modelcontextprotocol.io as the default URL.
2026-01-14 20:41:19 +00:00
Anton Pidkuiko MacBook
0927445025
feat(qr-server): migrate to uv with PEP 723 inline dependencies
- 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
2026-01-14 20:27:35 +00:00
Olivier Chafik
db1b48552b
examples[pdf]: limit context length (#270)
* 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.

* cap length of context update in pdf-server

* format
2026-01-14 15:26:25 +00:00
Olivier Chafik
96daa46a1d
examples: add PDF viewer w/ chunked data loading, full-screen, model context updates, private tool (#267)
* 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.
2026-01-14 14:25:24 +00:00
Jonathan Hefner
63b05b4fdd
Merge pull request #252 from jonathanhefner/update-examples-for-skill
Improve consistency and organization of examples for AI learning
2026-01-13 20:55:40 -06:00
Jonathan Hefner
4140565b77 Improve consistency and organization of examples for AI learning
- Add `.gitignore` files to all 19 examples (`node_modules/`, `dist/`)
- Replace custom `log` objects with standard `console` methods
- Add `ontoolcancelled` handler to all `basic-server-*` examples
- Add host styling integration (`applyDocumentTheme`, `applyHostFonts`,
  `applyHostStyleVariables`) to non-React `basic-server-*` examples
- Add section headers for better code organization in feature examples
- Update READMEs with Build System section explaining single-file
  bundling

These changes make examples more consistent and easier to adapt.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 20:48:02 -06:00
Jonathan Hefner
6166242136
Add Claude Code plugin with "Create MCP App" skill (#256)
Add a Claude Code plugin (`plugins/mcp-apps/`) for distribution via the
plugin marketplace. The plugin provides the "Create MCP App" skill that
guides the agent through building MCP Apps with interactive UIs.

The skill includes:
- Instructions to clone SDK repo for reference templates
- Framework selection guidance (React, Vanilla JS, Vue, Svelte, etc.)
- Tool visibility configuration (`_meta.ui.visibility`)
- Host styling integration patterns
- Testing workflow using `basic-host`
- Common mistakes to avoid

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 00:50:18 +00:00
Ido Salomon
969b905c10
disambiguate resource in csp sample (#257)
* disambiguate resource in csp sample

Clarified comment on CSP extraction from resource metadata.

* Update specification/draft/apps.mdx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-14 00:49:40 +00:00
adam jones
aa6775485d
chore: update licensing to Apache 2.0 for new contributions (#251) 2026-01-14 00:42:13 +00:00
Jonathan Hefner
d48e35d88a
Improve JSDoc comments with cross-references and clarifications (#254)
Key improvements:
- Add `{@link}` cross-references throughout the codebase to make API
  documentation navigable and help AI models understand relationships
- Use `{@link module!Export}` syntax for cross-module references
- Add backticks for inline code formatting (`ResizeObserver`, `App`, etc)
- Fix `PostMessageTransport` examples to show required two-argument form
- Clarify `onteardown` callback return type requirement
- Document React hooks cleanup behavior and Strict Mode considerations
- Add tool visibility example for `registerAppTool`
- Add CSP example for `registerAppResource`
- Fix notification direction documentation in `spec.types.ts`

TypeDoc config migrated from `typedoc.json` to `typedoc.config.mjs` to:
- Support custom `@description` block tag
- Add `intentionallyNotExported` for internal types
- Include `src/server/index.ts` entry point

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 00:41:17 +00:00
Jonathan Hefner
978d8e6fff
Merge pull request #263 from jonathanhefner/oai-migration-doc-server-side-section
Add "Server-Side" section to OpenAI migration guide
2026-01-13 17:49:28 -06:00
dependabot[bot]
631090f41e
build(deps): bump hono in the npm_and_yarn group across 1 directory (#268)
Bumps the npm_and_yarn group with 1 update in the / directory: [hono](https://github.com/honojs/hono).


Updates `hono` from 4.11.3 to 4.11.4
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](https://github.com/honojs/hono/compare/v4.11.3...v4.11.4)

---
updated-dependencies:
- dependency-name: hono
  dependency-version: 4.11.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 23:47:06 +00:00
Jonathan Hefner
b231396d2b Add "Server-Side" section to OpenAI migration guide
Add "Server-Side" migration documentation covering:
- Tool metadata mapping (`_meta["openai/..."]` → `_meta.ui.*`)
- Resource metadata (CSP, permissions, domain, border preferences)
- Resource MIME type (`text/html+skybridge` → `text/html;profile=mcp-app`)
- Before/after code examples using `registerAppTool()` and
  `registerAppResource()`
- Key differences summary including not-yet-implemented features

Reorganize existing client-side content under updated heading structure.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 15:18:05 -06:00
Olivier Chafik
152b953ae6
docs: how to migrate from openai apps (#260)
* Create migrate_from_openai_apps.md

* Update AGENTS.md

* Update docs/migrate_from_openai_apps.md

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

* address PR review comments

- Remove AGENTS.md reference to migration guide
- Add note that OpenAITransport is not yet available (PR #172)
- Remove unnecessary note about return type ordering

---------

Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
2026-01-13 15:23:26 +00:00
Olivier Chafik
574a768e09
feat: add example gallery with auto-generated screenshots (#253)
* 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 \![Screenshot](screenshot.png) 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
2026-01-13 15:12:18 +00:00
Olivier Chafik
8fa2961ffc
basic-host: filter app-only tools, prioritize UI tools (#262)
* basic-host: filter non-ui tools

* basic-host: filter app-only tools, prioritize UI tools

- Filter out tools with visibility: ['app'] from host tool list
- Sort tools to show UI-enabled tools first, then alphabetically
- Add local isToolVisibleToModel helper in basic-host
2026-01-13 15:05:12 +00:00
Olivier Chafik
bd892b6ce4
revert to document.write again; cesiumjs doesn't like srcdoc, period. (#258)
* revert to document.write again; cesiumjs doesn't like srcdoc, period.

* Update server.ts
2026-01-13 02:32:07 +00:00
Olivier Chafik
231f23fd72
chore: release 0.4.0 (#249) v0.4.0
* 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.
2026-01-12 22:40:24 +00:00
Olivier Chafik
ba550f1aeb
fix: follow-up to PR #234 (remove accidental file, revert from document.write to equiv. srcdoc) (#248)
* chore: remove tamper-detection.ts (not meant to be submitted)

Follow-up to PR #234. This file was accidentally included.

* revert to srcdoc

Follow-up to PR #234 per domfarolino's review feedback.

* regen

* regen
2026-01-12 22:19:31 +00:00
Olivier Chafik
9a9ecf27d4
feat(examples): add --watch to bun serve commands for auto-restart, and have npm start hit dev mode of all examples (#246)
* feat(examples): add --watch to bun serve commands for auto-restart on file changes

* Update package.json

* regen
2026-01-12 22:17:12 +00:00
Olivier Chafik
6bb63c3bae
examples: add transcript-server example with live speech transcription (#240)
* feat: add transcript-server example with live speech transcription

- New example: transcript-server with Web Speech API transcription
  - Start/stop recording with timer display
  - Live transcript with interim results
  - Send button to send transcript as ui/message to host
  - Copy button to copy full transcript
  - Sent messages marked with divider, greyed out
  - Experimental ui/update-model-context for live context updates
  - Transparent background, respects host theme

- Enable microphone and clipboard in basic-host sandbox iframes
  - Add allow="microphone; clipboard-write" to both outer and inner iframes
  - Required for Web Speech API, audio capture, and clipboard access

- Add alert popup in basic-host for ui/message from apps

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

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

* style: format transcript-server files

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

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

* test: add e2e test and golden for transcript-server

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

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

* refactor: use @types/dom-speech-recognition instead of hand-rolled types

Removes ~50 lines of manually defined Web Speech API types in favor of
the community-maintained type package.

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

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

* fix: add newlines between transcript chunks when copying to clipboard

* refactor: unify transcript formatting with timestamps

- Add formatEntry() helper that includes [timestamp] prefix
- Add formatEntries() helper that joins entries with newlines
- Use same format for clipboard copy, send message, and model context
- DRY up duplicate code in send button handler

* fix: log model context update failures instead of silently swallowing

* fix: log model context updates for debugging

* refactor: pass permissions through loadSandboxProxy like csp

- Add permissions parameter to loadSandboxProxy in implementation.ts
- Build iframe allow attribute from permissions instead of hardcoding
- Update sandbox.ts to not hardcode allow attribute (set via notification)
- Add microphone + clipboardWrite permissions to transcript-server resource
- Update README to reflect permission configuration via resource _meta.ui

* fix(transcript-server): auto-expand instead of scroll

- Remove min-height: 100vh and overflow-y: auto
- Let content grow naturally with autoResize (default)
- Remove unnecessary scrollTop calls

* test: remove transcript timer mask (no longer dynamic)

* refactor: pass permissions through loadSandboxProxy like csp

* docs: document updateModelContext for transitional speech

* test: update e2e screenshots

* refactor: use app.updateModelContext() instead of raw request

* package-lock.json

* src/generated/schema.json

* test: update e2e screenshots from CI

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 21:27:31 +00:00
Olivier Chafik
53142efd2d
refactor(map): use app.updateModelContext() instead of adhoc request (#245)
* feat(map): add keyboard shortcuts for fullscreen control

- Escape: exit fullscreen when in fullscreen mode
- Ctrl/Cmd+Enter: toggle fullscreen from any mode

* feat(map): persist view state to localStorage

- Save camera position/orientation on moveEnd (debounced 500ms)
- Restore persisted view when no explicit tool input is received
- Key by toolInfo.id (tool invocation ID) - localStorage is per-conversation
- Tool input (explicit bbox) takes precedence over persisted state

* refactor(map): use app.updateModelContext() instead of adhoc request
2026-01-12 20:47:07 +00:00
Anton Pidkuiko
9fcee5b5a6
Merge pull request #247 from modelcontextprotocol/fix/qr-server-sdk-version
fix(qr-server): Update SDK to 0.3.1 with app-with-deps bundle
2026-01-12 20:41:02 +00:00
Anton Pidkuiko MacBook
6b6c5ce63f
fix(qr-server): Update SDK to 0.3.1 with app-with-deps bundle
- Use app-with-deps export for CDN imports (includes all dependencies)
- Fixes widget crash on Claude Desktop/Nest
2026-01-12 20:09:10 +00:00
Jonathan Hefner
b6fc151094
Add {AGENTS,CLAUDE}.md for AI assistant guidance (#218)
Provides context about this repository including:

- Common commands for building, testing, and running examples
- SDK entry points and their purposes
- Communication flow between Guest UI, Host, and MCP Server
- Key source files and their responsibilities
- Protocol lifecycle from initialization to teardown
- Type generation workflow

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 19:54:24 +00:00
Olivier Chafik
741b1d3925
feat(basic-host): improve host UI with collapsible panels and SDK types (#244)
* refactor(basic-host): use SDK types for ModelContext and AppMessage

- Import McpUiUpdateModelContextRequest and McpUiMessageRequest from SDK
- Replace custom ModelContext with McpUiUpdateModelContextRequest['params']
- Replace custom AppMessage with McpUiMessageRequest['params']
- Pass full message params instead of extracting text
- Format messages by extracting text from content blocks in display

* feat(basic-host): handle non-text content blocks in display

- Add formatContentBlock helper for text, image, audio, resource types
- Show placeholders like <image: image/png> for non-text content
- Apply to both messages and model context display

* test: update shadertoy screenshot

* test: update screenshots from CI (linux x64)
2026-01-12 19:42:11 +00:00
Jonathan Hefner
e29523c113
Merge pull request #217 from jonathanhefner/examples-replace-resource_uri_meta_key
Replace deprecated `RESOURCE_URI_META_KEY` with `_meta.ui.resourceUri`
2026-01-12 13:07:44 -06:00
Jonathan Hefner
94bc708963 Replace deprecated RESOURCE_URI_META_KEY with _meta.ui.resourceUri
Update all example servers to use the new recommended metadata format
for associating UI resources with tools. The old `RESOURCE_URI_META_KEY`
constant is deprecated in favor of the nested `_meta.ui.resourceUri`
structure.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 13:00:11 -06:00
Jonathan Hefner
7f1c9c0dde
Merge pull request #155 from jonathanhefner/update-quickstart-guide
Update quickstart guide
2026-01-12 12:58:53 -06:00
Jonathan Hefner
093faa9a0d
Merge pull request #209 from jonathanhefner/readme-how-it-works
Add "How It Works" section to README
2026-01-12 12:58:41 -06:00
Jonathan Hefner
dadbb6ac3d
Merge pull request #212 from jonathanhefner/video-resource-server-safeareainsets
Support `safeAreaInsets` + type-checking in video-resource-server
2026-01-12 12:58:28 -06:00
Jonathan Hefner
6d2d4b22b6
Merge pull request #227 from jonathanhefner/system-monitor-refresh-stats-tool
Add missing `refresh-stats` tool to `system-monitor-server`
2026-01-12 12:58:03 -06:00
Jonathan Hefner
6e4eb32d1e
Merge pull request #228 from jonathanhefner/restore-182
Restore educational comments in `basic-server-*` examples
2026-01-12 12:57:47 -06:00