Mirror of https://github.com/modelcontextprotocol/ext-apps — Official repo for spec & SDK of MCP Apps protocol - standard for UIs embedded AI chatbots, served by MCP servers
  • TypeScript 76.4%
  • MDX 19.3%
  • JavaScript 4.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Olivier Chafik 023f1fd233
fix: misc fixes for pdf-server, map-server, and say-server (#329)
* 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
2026-01-23 12:35:07 +00:00
.claude-plugin Add .claude-plugin/marketplace.json for plugin distribution 2026-01-20 11:38:14 -06:00
.github/workflows feat(qr-server): migrate to uv with PEP 723 inline dependencies 2026-01-14 20:27:35 +00:00
.husky Add pre-commit check for private registry URLs in package-lock.json (#133) 2025-12-16 13:41:50 +00:00
docs docs: standardize UI terminology to use "view" consistently (#325) 2026-01-23 04:36:52 +02:00
examples fix: misc fixes for pdf-server, map-server, and say-server (#329) 2026-01-23 12:35:07 +00:00
plugins/mcp-apps docs: standardize UI terminology to use "view" consistently (#325) 2026-01-23 04:36:52 +02:00
scripts fix: ensure lib is built before examples:build (#185) 2026-01-09 01:36:42 +00:00
specification/draft docs: standardize UI terminology to use "view" consistently (#325) 2026-01-23 04:36:52 +02:00
src docs: standardize UI terminology to use "view" consistently (#325) 2026-01-23 04:36:52 +02:00
tests/e2e docs: standardize UI terminology to use "view" consistently (#325) 2026-01-23 04:36:52 +02:00
.gitattributes fix: Windows compatibility - bun as optional dep, cross-env for examples (#145) 2025-12-16 14:07:38 +00:00
.gitignore feat(examples): add say-server - streaming Pocket TTS with karaoke highlighting (#304) 2026-01-20 00:41:50 +00:00
.prettierignore Add Claude Code plugin with "Create MCP App" skill (#256) 2026-01-14 00:50:18 +00:00
.prettierrc.json api: optional Client in AppBridge (allow custom forwarding), better protocol types (AppRequest, AppNotification, AppResult) (#146) 2025-12-13 21:07:13 +00:00
AGENTS.md docs: standardize UI terminology to use "view" consistently (#325) 2026-01-23 04:36:52 +02:00
build.bun.ts build app-with-deps (#221) 2026-01-09 01:26:31 +00:00
CLAUDE.md Add {AGENTS,CLAUDE}.md for AI assistant guidance (#218) 2026-01-12 19:54:24 +00:00
CONTRIBUTING.md tests: add Playwright E2E tests with screenshot golden testing (+ fix examples session handling) (#115) 2025-12-13 20:57:27 +00:00
LICENSE chore: update licensing to Apache 2.0 for new contributions (#251) 2026-01-14 00:42:13 +00:00
package-lock.json Use typedoc-github-theme for API documentation 2026-01-22 13:24:01 -06:00
package.json Use typedoc-github-theme for API documentation 2026-01-22 13:24:01 -06:00
playwright.config.ts add EXAMPLE=folder-name support for tests & basic-host (#292) 2026-01-19 20:16:37 +00:00
README.md Merge pull request #302 from jonathanhefner/checked-examples 2026-01-20 13:30:01 -06:00
RELEASES.md chore: release 0.3.0 (#204) 2026-01-09 00:55:45 +00:00
tsconfig.json Consolidate host styling patterns into unified documentation 2026-01-20 13:31:11 -06:00
typedoc.config.mjs Use typedoc-github-theme for API documentation 2026-01-22 13:24:01 -06:00

@modelcontextprotocol/ext-apps

npm version API Documentation

This repo contains the SDK and specification for MCP Apps Extension (SEP-1865).

MCP Apps are a proposed standard inspired by MCP-UI and OpenAI's Apps SDK to allow MCP Servers to display interactive UI elements in conversational MCP clients / chatbots.

How It Works

MCP Apps extend the Model Context Protocol to let servers deliver interactive UIs to MCP hosts. Here's how it works:

  1. Tool call — The LLM calls a tool on your server
  2. UI Resource — The tool's definition links to a predeclared ui:// resource containing its HTML interface
  3. Host renders — The host fetches the resource and displays it in a sandboxed iframe
  4. Bidirectional communication — The host passes tool data to the UI via notifications, and the UI can call other tools through the host

This enables dashboards, forms, visualizations, and other rich experiences inside chat interfaces.

Overview

This SDK serves two audiences:

App Developers

Build interactive UIs that run inside MCP-enabled chat clients.

  • SDK for Apps: @modelcontextprotocol/ext-apps — API Docs
  • React hooks: @modelcontextprotocol/ext-apps/react — API Docs

Host Developers

Embed and communicate with MCP Apps in your chat application.

  • SDK for Hosts: @modelcontextprotocol/ext-apps/app-bridge — API Docs

There's no supported host implementation in this repo (beyond the examples/basic-host example).

We have contributed a tentative implementation of hosting / iframing / sandboxing logic to the MCP-UI repository, and expect OSS clients may use it, while other clients might roll their own hosting logic.

Installation

npm install -S @modelcontextprotocol/ext-apps

Claude Code Plugin

A Claude Code plugin is available to help create MCP Apps. To install, run these commands inside Claude Code:

/plugin marketplace add modelcontextprotocol/ext-apps
/plugin install mcp-apps@modelcontextprotocol-ext-apps

Examples

Map Three.js ShaderToy
Map Three.js ShaderToy
Sheet Music Wiki Explorer Cohort Heatmap
Sheet Music Wiki Explorer Cohort Heatmap
Scenario Modeler Budget Allocator Customer Segmentation
Scenario Modeler Budget Allocator Customer Segmentation
System Monitor Transcript Video Resource
System Monitor Transcript Video Resource
PDF Server QR Code Say Demo
PDF Server QR Code (Python) Say Demo

Starter Templates

Basic The same app built with different frameworks — pick your favorite!

React · Vue · Svelte · Preact · Solid · Vanilla JS

The examples/ directory contains additional demo apps showcasing real-world use cases.

MCP client configuration for all examples

Add to your MCP client configuration (stdio transport):

{
  "mcpServers": {
    "basic-react": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-basic-react",
        "--stdio"
      ]
    },
    "basic-vanillajs": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-basic-vanillajs",
        "--stdio"
      ]
    },
    "basic-vue": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-basic-vue",
        "--stdio"
      ]
    },
    "basic-svelte": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-basic-svelte",
        "--stdio"
      ]
    },
    "basic-preact": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-basic-preact",
        "--stdio"
      ]
    },
    "basic-solid": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-basic-solid",
        "--stdio"
      ]
    },
    "budget-allocator": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-budget-allocator",
        "--stdio"
      ]
    },
    "cohort-heatmap": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-cohort-heatmap",
        "--stdio"
      ]
    },
    "customer-segmentation": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-customer-segmentation",
        "--stdio"
      ]
    },
    "map": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-map",
        "--stdio"
      ]
    },
    "pdf": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-pdf",
        "--stdio"
      ]
    },
    "scenario-modeler": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-scenario-modeler",
        "--stdio"
      ]
    },
    "shadertoy": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-shadertoy",
        "--stdio"
      ]
    },
    "sheet-music": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-sheet-music",
        "--stdio"
      ]
    },
    "system-monitor": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-system-monitor",
        "--stdio"
      ]
    },
    "threejs": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-threejs",
        "--stdio"
      ]
    },
    "transcript": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-transcript",
        "--stdio"
      ]
    },
    "video-resource": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-video-resource",
        "--stdio"
      ]
    },
    "wiki-explorer": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-wiki-explorer",
        "--stdio"
      ]
    },
    "qr": {
      "command": "uv",
      "args": [
        "run",
        "/path/to/ext-apps/examples/qr-server/server.py",
        "--stdio"
      ]
    },
    "say": {
      "command": "uv",
      "args": [
        "run",
        "--default-index",
        "https://pypi.org/simple",
        "https://raw.githubusercontent.com/modelcontextprotocol/ext-apps/refs/heads/main/examples/say-server/server.py",
        "--stdio"
      ]
    }
  }
}

Note: The qr server requires cloning the repository first. See qr-server README for details.

To run all examples locally in dev mode:

npm install
npm start

Then open http://localhost:8080/.

Resources