---
phase: 21-book-mcp-apps-refresh
plan: 02
type: execute
wave: 2
depends_on:
  - 21-01
files_modified:
  - pmcp-book/src/ch12-5-mcp-apps.md
autonomous: true
requirements:
  - BKAP-03
  - BKAP-04

must_haves:
  truths:
    - "Reader understands the UIAdapter trait and how ChatGptAdapter, McpAppsAdapter, and McpUiAdapter each transform the same HTML for different hosts"
    - "Reader understands the MIME type differences: text/html+skybridge (ChatGPT), text/html+mcp (MCP Apps), text/html (MCP-UI)"
    - "Reader understands window.openai vs postMessage bridge injection and why widgets use window.mcpBridge as the universal API"
    - "Reader can follow the chess example architecture: stateless game state, WidgetDir for widget files, ChatGptAdapter for bridge injection"
    - "Reader can follow the map example architecture: geographic data tools, Leaflet.js widget, WidgetDir + ChatGptAdapter"
    - "Reader can follow the dataviz example architecture: SQLite query tools, Chart.js dashboard widget, WidgetDir + ChatGptAdapter"
  artifacts:
    - path: "pmcp-book/src/ch12-5-mcp-apps.md"
      provides: "Complete chapter with adapter pattern and example walkthroughs appended"
      min_lines: 800
      contains: "ChatGptAdapter"
  key_links:
    - from: "pmcp-book/src/ch12-5-mcp-apps.md"
      to: "src/server/mcp_apps/adapter.rs"
      via: "Documented adapter trait and implementations match actual Rust source"
      pattern: "UIAdapter|ChatGptAdapter|McpAppsAdapter|McpUiAdapter"
    - from: "pmcp-book/src/ch12-5-mcp-apps.md"
      to: "examples/mcp-apps-chess/src/main.rs"
      via: "Chess example walkthrough references actual source structure"
      pattern: "chess_new_game|chess_move|chess_valid_moves"
    - from: "pmcp-book/src/ch12-5-mcp-apps.md"
      to: "examples/mcp-apps-map/src/main.rs"
      via: "Map example walkthrough references actual source structure"
      pattern: "search_cities|get_city_details|get_nearby"
    - from: "pmcp-book/src/ch12-5-mcp-apps.md"
      to: "examples/mcp-apps-dataviz/src/main.rs"
      via: "Dataviz example walkthrough references actual source structure"
      pattern: "execute_query|list_tables|describe_table"
---

<objective>
Complete Ch 12.5 by appending the multi-platform adapter pattern explanation and architecture walkthroughs of the chess, map, and dataviz examples.

Purpose: Readers need to understand how the adapter pattern enables write-once widgets that work across ChatGPT Apps, MCP Apps, and MCP-UI hosts. They also need concrete architecture walkthroughs of the shipped examples so they can understand real-world MCP Apps patterns and build their own.

Output: `pmcp-book/src/ch12-5-mcp-apps.md` completed with adapter pattern, example walkthroughs, best practices, and summary sections.
</objective>

<execution_context>
@./.claude/get-shit-done/workflows/execute-plan.md
@./.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/21-book-mcp-apps-refresh/21-01-SUMMARY.md

Source code to extract documentation from (READ THESE during execution):
- `src/server/mcp_apps/adapter.rs` — UIAdapter trait (host_type, mime_type, transform, inject_bridge, required_csp), ChatGptAdapter (widget_meta, window.openai bridge), McpAppsAdapter (postMessage bridge), McpUiAdapter (McpUiFormat: Html/Url/RemoteDom)
- `src/server/mcp_apps/mod.rs` — Architecture diagram showing UIResource -> adapters -> MIME types
- `src/server/mcp_apps/builder.rs` — MultiPlatformResource, UIResourceBuilder
- `examples/mcp-apps-chess/src/main.rs` — Chess server: GameState, tool handlers (chess_new_game, chess_move, chess_valid_moves), ChessResources with WidgetDir + ChatGptAdapter, StreamableHttpServer setup
- `examples/mcp-apps-chess/widgets/board.html` — Chess board widget HTML
- `examples/mcp-apps-map/src/main.rs` — Map server: City data types, tool handlers (search_cities, get_city_details, get_nearby_cities), MapResources with WidgetDir + ChatGptAdapter
- `examples/mcp-apps-map/widgets/map.html` — Map widget HTML (Leaflet.js)
- `examples/mcp-apps-dataviz/src/main.rs` — Dataviz server: SQL tools (execute_query, list_tables, describe_table), DataVizResources with WidgetDir + ChatGptAdapter, Chinook SQLite database
- `examples/mcp-apps-dataviz/widgets/dashboard.html` — Dashboard widget HTML (Chart.js)
- `src/types/mcp_apps.rs` — ExtendedUIMimeType, HostType, WidgetMeta, WidgetCSP types (if exists, check with grep)
</context>

<tasks>

<task type="auto">
  <name>Task 1: Write multi-platform adapter pattern section</name>
  <files>pmcp-book/src/ch12-5-mcp-apps.md</files>
  <action>
Read the following source files to extract accurate details:
- `src/server/mcp_apps/adapter.rs` for UIAdapter trait definition (all methods), ChatGptAdapter (bridge script with window.openai + window.mcpBridge), McpAppsAdapter (postMessage bridge), McpUiAdapter (McpUiFormat enum, Remote DOM)
- `src/server/mcp_apps/mod.rs` for the architecture diagram text (UIResource -> adapters -> MIME types)
- `src/server/mcp_apps/builder.rs` for MultiPlatformResource builder

Also read the `types/mcp_apps.rs` or search for ExtendedUIMimeType, HostType, WidgetMeta, WidgetCSP definitions.

Remove the `<!-- CONTINUED IN PLAN 21-02 -->` comment and append these sections:

**6. Multi-Platform Adapter Pattern** (## Multi-Platform Adapter Pattern)
- **The Problem** (### The Problem): Different MCP hosts use different communication mechanisms:
  - ChatGPT Apps: `window.openai` API, `text/html+skybridge` MIME type
  - MCP Apps (SEP-1865): `postMessage` JSON-RPC, `text/html+mcp` MIME type
  - MCP-UI (community): `postMessage`, `text/html`, also supports URL references and Remote DOM
- **Architecture Overview** (### Architecture Overview):
  - ASCII diagram from mod.rs showing: UIResource (Core) -> ChatGptAdapter / McpAppsAdapter / McpUiAdapter -> platform-specific MIME types and bridge scripts
  - Key insight: widget authors write ONE HTML file using `window.mcpBridge`; the adapter injects the correct bridge script for the target platform
- **The UIAdapter Trait** (### The UIAdapter Trait):
  - `host_type()` -> HostType (ChatGpt, Generic, Nanobot)
  - `mime_type()` -> ExtendedUIMimeType
  - `transform(uri, name, html)` -> TransformedResource (contains uri, name, mime_type, content, metadata)
  - `inject_bridge(html)` -> String (injects platform-specific bridge script)
  - `required_csp()` -> Option<WidgetCSP>
- **ChatGptAdapter** (### ChatGptAdapter):
  - Injects `window.openai` bridge wrapping `window.mcpBridge` API
  - Uses `text/html+skybridge` MIME type
  - `WidgetMeta` for ChatGPT-specific metadata (prefers_border, description)
  - Code example: `ChatGptAdapter::new().with_widget_meta(WidgetMeta::new().prefers_border(true))`
  - Bridge capabilities: callTool, setState/getState, toolInput/toolOutput, sendMessage, requestDisplayMode, theme/locale/displayMode
- **McpAppsAdapter** (### McpAppsAdapter):
  - Injects postMessage JSON-RPC bridge
  - Uses `text/html+mcp` MIME type
  - Optional CSP configuration
  - Code example: `McpAppsAdapter::new().with_csp(csp)`
  - Bridge capabilities: callTool, readResource, getPrompt, notify
- **McpUiAdapter** (### McpUiAdapter):
  - Three output formats: Html (postMessage bridge), Url (CDN reference), RemoteDom (non-iframe)
  - Uses `text/html` for HTML format
  - Code example: `McpUiAdapter::new().with_format(McpUiFormat::Html)`
  - Bridge capabilities: callTool, readResource, getPrompt, sendIntent, notify, openLink
- **Choosing an Adapter** (### Choosing an Adapter):
  - Table comparing: Adapter | Host | MIME Type | Bridge API | Best For
  - Currently all shipped examples use ChatGptAdapter because it's the most mature host
  - Use McpAppsAdapter for generic MCP hosts that support the SEP-1865 extension
  - Use McpUiAdapter for MCP-UI community hosts

IMPORTANT: Extract the exact bridge script APIs from adapter.rs. Do not invent methods. The ChatGptAdapter bridge has many more methods (uploadFile, getFileDownloadUrl, requestDisplayMode, etc.) than the MCP Apps bridge — document this difference.
  </action>
  <verify>
    <automated>grep -cE "(UIAdapter|ChatGptAdapter|McpAppsAdapter|McpUiAdapter|text/html\+skybridge|text/html\+mcp|WidgetMeta)" pmcp-book/src/ch12-5-mcp-apps.md</automated>
    Should return 15+ matches confirming all adapter types documented.
  </verify>
  <done>
    Ch 12.5 includes complete adapter pattern documentation covering UIAdapter trait, all three adapters (ChatGpt, McpApps, McpUi), their MIME types, bridge APIs, and selection guidance. All details match adapter.rs source.
  </done>
</task>

<task type="auto">
  <name>Task 2: Write example walkthroughs and chapter conclusion</name>
  <files>pmcp-book/src/ch12-5-mcp-apps.md</files>
  <action>
Read the following source files to extract architecture details:
- `examples/mcp-apps-chess/src/main.rs` — full file for chess architecture
- `examples/mcp-apps-chess/widgets/board.html` — first ~50 lines for widget structure
- `examples/mcp-apps-map/src/main.rs` — full file for map architecture
- `examples/mcp-apps-map/widgets/map.html` — first ~50 lines for widget structure
- `examples/mcp-apps-dataviz/src/main.rs` — full file for dataviz architecture
- `examples/mcp-apps-dataviz/widgets/dashboard.html` — first ~50 lines for widget structure

Append these sections to the chapter:

**7. Example Walkthroughs** (## Example Walkthroughs)

Brief intro: three shipped examples demonstrate different MCP Apps patterns. Each follows the same structure: tool handlers + WidgetDir + ChatGptAdapter + StreamableHttpServer.

**7.1. Chess: Stateless Game Widget** (### Chess: Stateless Game Widget)
- Architecture overview:
  - Stateless design: widget holds ALL game state, each tool call includes full GameState
  - Server validates and processes moves without storing state (no sessions needed)
- Tools: `chess_new_game` (returns initial state), `chess_move` (validates + applies move), `chess_valid_moves` (returns valid destinations for a piece)
- Widget: `widgets/board.html` renders an interactive chess board, calls tools via mcpBridge
- Key code patterns:
  - GameState struct sent with every request (client-side state ownership)
  - `tool_typed_sync_with_description` for synchronous tool registration
  - StreamableHttpServer with stateless config (no session_id_generator)
- Running: `cd examples/mcp-apps-chess && cargo run` then connect via `cargo pmcp connect` or preview
- Show the architecture as: Widget (board.html) -> mcpBridge.callTool("chess_move", {state, move}) -> Server -> validates -> returns new state -> Widget updates board

**7.2. Map: Geographic Data Explorer** (### Map: Geographic Data Explorer)
- Architecture overview:
  - City database with geographic coordinates, categories, and search
  - Haversine distance calculation for nearby city search
  - Leaflet.js map widget with interactive markers
- Tools: `search_cities` (query + category filter + map_state context), `get_city_details` (by city ID), `get_nearby_cities` (center + radius)
- Widget: `widgets/map.html` renders Leaflet.js map with city markers and popups
- Key code patterns:
  - MapState sent with queries for context-aware responses
  - Category enum filtering
  - Tool inputs include current view state for smart defaults
- Running: `cd examples/mcp-apps-map && cargo run` on port 3001

**7.3. Dataviz: SQL Dashboard** (### Dataviz: SQL Dashboard)
- Architecture overview:
  - Chinook SQLite database as real-world data source
  - SQL query execution with structured JSON results
  - Chart.js dashboard widget with bar, line, pie charts + sortable data table
- Tools: `execute_query` (arbitrary SQL), `list_tables` (enumerate tables), `describe_table` (column metadata)
- Widget: `widgets/dashboard.html` renders interactive charts and data tables from query results
- Key code patterns:
  - rusqlite for SQLite access
  - SQL injection prevention via table name validation
  - Structured error responses (not panics)
- Prerequisites: download Chinook.db
- Running: `cd examples/mcp-apps-dataviz && cargo run` on port 3002

**7.4. Common Architecture Pattern** (### Common Architecture Pattern)
- All three examples share the SAME structure:
  1. Define tool input types with `#[derive(Deserialize, JsonSchema)]`
  2. Write synchronous tool handlers returning `Result<Value>`
  3. Create a ResourceHandler struct with `ChatGptAdapter` + `WidgetDir`
  4. Implement `ResourceHandler::read()` (widget_dir.read_widget -> adapter.transform) and `list()` (widget_dir.discover -> map to ResourceInfo)
  5. Build server with `ServerBuilder::new().tool_typed_sync_with_description(...).resources(...).build()`
  6. Run with `StreamableHttpServer` for HTTP access
- This pattern is the recommended way to build MCP Apps

**8. Best Practices** (## Best Practices)
- Keep widgets as single self-contained HTML files (external CDN libs are fine)
- Use `window.mcpBridge.callTool()` as the universal bridge API (works on all platforms)
- Design stateless tools when possible (widget owns state, server validates)
- Use hot-reload during development (just refresh browser)
- Test with `cargo pmcp preview` before deploying
- Use `cargo pmcp app build` to produce distribution artifacts

**9. Summary** (## Summary)
- Key takeaways as bulleted list (matching other chapters):
  - WidgetDir: file-based widget authoring with hot-reload
  - cargo pmcp app: scaffold, preview, build workflow
  - Adapter pattern: write once, deploy to ChatGPT/MCP Apps/MCP-UI
  - window.mcpBridge: universal bridge API for widget-server communication
  - Three examples (chess, map, dataviz) demonstrate real-world patterns
- Next steps pointing to examples/ for more details and Ch 13/14/15 for production/testing

IMPORTANT: Extract architecture details from the actual source code. Tool names, port numbers, struct names, and patterns must match the real examples. Do NOT copy large blocks of code into the chapter — use focused excerpts (10-30 lines) that illustrate key patterns, with file references for full source.
  </action>
  <verify>
    <automated>wc -l pmcp-book/src/ch12-5-mcp-apps.md | awk '{if ($1 >= 800) print "PASS: "$1" lines"; else print "FAIL: only "$1" lines, need 800+"; exit ($1 < 800)}'</automated>
    Also verify key content:
    Run: grep -cE "(chess_new_game|chess_move|search_cities|get_nearby|execute_query|list_tables|Leaflet|Chart\.js|Chinook|StreamableHttpServer)" pmcp-book/src/ch12-5-mcp-apps.md
    Should return 10+ matches confirming all examples covered.
  </verify>
  <done>
    Ch 12.5 is complete with adapter pattern, all three example walkthroughs (chess, map, dataviz), common architecture pattern, best practices, and summary. All details match actual source code. The chapter covers all four BKAP requirements.
  </done>
</task>

</tasks>

<verification>
1. `pmcp-book/src/ch12-5-mcp-apps.md` is complete (>800 lines, no continuation comments)
2. Chapter covers BKAP-03: UIAdapter trait, ChatGptAdapter, McpAppsAdapter, McpUiAdapter with MIME types and bridge APIs
3. Chapter covers BKAP-04: Chess, map, dataviz example walkthroughs with architecture explanations
4. Adapter trait methods match `src/server/mcp_apps/adapter.rs`
5. Bridge APIs match the injected JavaScript in adapter.rs
6. Example tool names match actual main.rs files (chess_new_game, search_cities, execute_query, etc.)
7. Port numbers match examples (3000, 3001, 3002)
8. Common architecture pattern accurately reflects the shared structure of all three examples
9. No UIResourceBuilder/inline HTML remnants from the old chapter
10. `mdbook build pmcp-book` succeeds (no broken links or syntax errors)
</verification>

<success_criteria>
- Ch 12.5 is a comprehensive, production-quality chapter covering the full MCP Apps developer experience
- Adapter pattern is explained so readers understand write-once deployment to multiple hosts
- Example walkthroughs give readers concrete architecture understanding they can follow and extend
- Every tool name, type, port number, and code pattern matches the actual source code
- Writing style matches the existing book conventions
</success_criteria>

<output>
After completion, create `.planning/phases/21-book-mcp-apps-refresh/21-02-SUMMARY.md`
</output>
