---
phase: 41-chatgpt-mcp-apps-upgraded-version
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
  - crates/mcp-preview/assets/widget-runtime.mjs
  - crates/mcp-preview/assets/index.html
  - src/server/mcp_apps/adapter.rs
autonomous: true
requirements: [P41-04]

must_haves:
  truths:
    - "Widget sends ui/initialize (not ui/ready) for handshake"
    - "Host sends ui/notifications/tool-input and ui/notifications/tool-result to widget"
    - "Widget sends ui/message (not ui/sendMessage) and ui/open-link (not ui/openLink)"
    - "Host sends ui/resource-teardown (not ui/teardown) to widget"
    - "AppBridge host accepts both old and new method names from widgets for backward compat"
    - "Server-injected bridge script in adapter.rs sends ui/initialize (not ui/ready)"
  artifacts:
    - path: "crates/mcp-preview/assets/widget-runtime.mjs"
      provides: "Updated App class with correct protocol method names"
      contains: "ui/notifications/tool-input"
    - path: "crates/mcp-preview/assets/index.html"
      provides: "Updated AppBridge with correct notification method names"
      contains: "ui/notifications/tool-input"
    - path: "src/server/mcp_apps/adapter.rs"
      provides: "Server-injected bridge script with ui/initialize"
      contains: "ui/initialize"
  key_links:
    - from: "crates/mcp-preview/assets/widget-runtime.mjs"
      to: "crates/mcp-preview/assets/index.html"
      via: "postMessage JSON-RPC bridge"
      pattern: "ui/initialize"
    - from: "src/server/mcp_apps/adapter.rs"
      to: "crates/mcp-preview/assets/index.html"
      via: "inject_bridge() script sends ui/initialize which host handles"
      pattern: "ui/initialize"
---

<objective>
Update the bridge protocol method names in widget-runtime.mjs (App class, widget side), index.html (AppBridge class, host side), and the server-injected bridge script in adapter.rs to match the official ChatGPT MCP Apps protocol.

Purpose: The current bridge uses non-standard method names (ui/toolInput, ui/sendMessage, ui/ready, etc.) that differ from the official spec (ui/notifications/tool-input, ui/message, ui/initialize, etc.).
Output: Bridge protocol aligned with ChatGPT's actual implementation across all three locations.
</objective>

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

<context>
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/41-chatgpt-mcp-apps-upgraded-version/41-RESEARCH.md

@crates/mcp-preview/assets/widget-runtime.mjs
@crates/mcp-preview/assets/index.html
@src/server/mcp_apps/adapter.rs
</context>

<tasks>

<task type="auto">
  <name>Task 1: Update widget-runtime.mjs and adapter.rs bridge script method names</name>
  <files>crates/mcp-preview/assets/widget-runtime.mjs, src/server/mcp_apps/adapter.rs</files>
  <action>
**Part A: Update widget-runtime.mjs App class**

**Outgoing methods (Widget -> Host):**
1. `ui/initialize` -- already correct, keep as-is
2. `ui/sendMessage` -> `ui/message` (the `sendMessage()` method body)
3. `ui/openLink` -> `ui/open-link` (the `openLink()` method body)
4. `ui/log` -- keep as-is (SDK extension, not part of ChatGPT protocol)

**Incoming notification handler (_handleNotification cases):**
1. `case "ui/toolInput":` -> `case "ui/notifications/tool-input":`
2. `case "ui/toolResult":` -> `case "ui/notifications/tool-result":`
3. `case "ui/toolCancelled":` -> `case "ui/notifications/tool-cancelled":`
4. `case "ui/hostContextChanged":` -> keep as-is (SDK extension) OR add `case "ui/notifications/context-changed":` as alias
5. `case "ui/teardown":` -> `case "ui/resource-teardown":`

**Backward compatibility:** Also keep OLD case labels as fallbacks. Use fall-through:
```javascript
case "ui/notifications/tool-input":
case "ui/toolInput":  // backward compat
    this._onToolInput(params);
    break;
```

**Part B: Update adapter.rs inject_bridge() script**

In `src/server/mcp_apps/adapter.rs`, the `inject_bridge()` method contains a script string (around line 451) that sends `'ui/ready'`. Change this to `'ui/initialize'`:
```javascript
// Was: window.mcpBridge.notify('ui/ready', {});
window.mcpBridge.notify('ui/initialize', {});
```
Also update the comment above it from "Notify host that widget is ready" to "Notify host that widget is initializing".

This ensures widgets work with both old-style hosts and new ChatGPT-style hosts.
  </action>
  <verify>
    <automated>grep -q "ui/initialize" crates/mcp-preview/assets/widget-runtime.mjs && grep -q "ui/notifications/tool-input" crates/mcp-preview/assets/widget-runtime.mjs && grep -q "ui/initialize" src/server/mcp_apps/adapter.rs && ! grep -q "ui/ready" src/server/mcp_apps/adapter.rs && echo "PASS"</automated>
  </verify>
  <done>widget-runtime.mjs uses official method names as primary with old names as fallback; adapter.rs inject_bridge sends ui/initialize instead of ui/ready</done>
</task>

<task type="auto">
  <name>Task 2: Update index.html AppBridge host-side method names</name>
  <files>crates/mcp-preview/assets/index.html</files>
  <action>
Update the AppBridge class in index.html to use correct ChatGPT MCP Apps protocol method names.

**Outgoing notifications (Host -> Widget):**
1. `sendToolInput()` method: change `this._transport.notify("ui/toolInput", ...)` -> `this._transport.notify("ui/notifications/tool-input", ...)`
2. `sendToolResult()` method: change `this._transport.notify("ui/toolResult", ...)` -> `this._transport.notify("ui/notifications/tool-result", ...)`
3. `sendHostContextChanged()` method: change `this._transport.notify("ui/hostContextChanged", ...)` -> `this._transport.notify("ui/notifications/context-changed", ...)`
4. Teardown: change `this._transport.notify("ui/teardown")` -> `this._transport.notify("ui/resource-teardown")`

**Incoming request handler (_handleRequest cases):**
1. `case "ui/initialize":` -- already correct, keep
2. `case "ui/sendMessage":` -> add `case "ui/message":` as primary, keep old as fallback:
   ```javascript
   case "ui/message":
   case "ui/sendMessage":  // backward compat
   ```
3. `case "ui/openLink":` -> add `case "ui/open-link":` as primary, keep old as fallback:
   ```javascript
   case "ui/open-link":
   case "ui/openLink":  // backward compat
   ```

**Also update any other references** in index.html that mention the old method names in comments or string literals.

**After `ui/initialize` response**, send `ui/notifications/initialized` notification to the widget:
```javascript
case "ui/initialize":
    // ... existing capability negotiation ...
    // After responding, send initialized notification
    this._transport.notify("ui/notifications/initialized", {});
    break;
```
  </action>
  <verify>
    <automated>grep -q "ui/notifications/tool-input" crates/mcp-preview/assets/index.html && grep -q "ui/resource-teardown" crates/mcp-preview/assets/index.html && grep -q "ui/message" crates/mcp-preview/assets/index.html && cargo build -p mcp-preview && echo "PASS"</automated>
  </verify>
  <done>AppBridge sends notifications using official method names; accepts both old and new names from widgets; sends ui/notifications/initialized after handshake; mcp-preview builds</done>
</task>

</tasks>

<verification>
cargo build -p mcp-preview
cargo clippy -p mcp-preview -- -D warnings
cargo test --features full --lib server::mcp_apps::adapter::tests
</verification>

<success_criteria>
- widget-runtime.mjs App class uses `ui/notifications/tool-input`, `ui/notifications/tool-result`, `ui/message`, `ui/open-link`, `ui/resource-teardown`
- index.html AppBridge uses matching names for outgoing notifications
- adapter.rs inject_bridge sends `ui/initialize` (not `ui/ready`)
- Both sides accept old method names as fallback for backward compatibility
- AppBridge sends `ui/notifications/initialized` after handshake
- mcp-preview builds successfully
- No grep match for `ui/ready` in adapter.rs
</success_criteria>

<output>
After completion, create `.planning/phases/41-chatgpt-mcp-apps-upgraded-version/41-02-SUMMARY.md`
</output>
