Skip to content

Instantly share code, notes, and snippets.

@krubenok
Created July 29, 2026 19:04
Show Gist options
  • Select an option

  • Save krubenok/0d601526e4222ba98cb42360f536ed04 to your computer and use it in GitHub Desktop.

Select an option

Save krubenok/0d601526e4222ba98cb42360f536ed04 to your computer and use it in GitHub Desktop.
End-to-end test guide for MCP App-rendered elicitations with MCP 2026-07-28 and MRTR

End-to-end test: MCP App-rendered elicitations

This guide exercises the public, server-agnostic reference implementation for rendering a standard MCP form elicitation in an MCP App. It covers:

  • MCP core protocol revision 2026-07-28
  • multi-round-trip requests (MRTR)
  • capability negotiation through core elicitation.form plus the existing io.modelcontextprotocol/ui extension
  • resolution through a standard ElicitResult
  • native-form fallback when App rendering or negotiation is unavailable

No second MCP extension or product-specific server is involved.

Reference versions

  • Inspector reference PR: krubenok/inspector#1
  • Inspector branch: agent/app-rendered-elicitations-reference
  • Known-good Inspector commit: 3b524cd1202ed8dbb4687399a7abace7e1c1d6ab
  • MCP Apps amendment: modelcontextprotocol/ext-apps#733
  • Pinned ext-apps commit: 89ab2bcbf066ca21f1bd38cb115949f857950b7a

The reference branch pins the ext-apps commit directly, so no private registry or unpublished package is required.

Prerequisites

  • Git
  • Node.js >=22.19.0
  • npm
  • Ports 3102 and 6274 available on localhost

1. Clone and build the reference implementation

git clone \
  --branch agent/app-rendered-elicitations-reference \
  --single-branch \
  https://github.com/krubenok/inspector.git \
  inspector-app-elicitation-demo

cd inspector-app-elicitation-demo
npm install
npm run build:web
npm run build:launcher

To reproduce the exact version tested when this guide was written:

git checkout 3b524cd1202ed8dbb4687399a7abace7e1c1d6ab
npm install
npm run build:web
npm run build:launcher

2. Start the generic MCP server fixture

In terminal 1, from the repository root:

cd clients/web
npm run test-servers:build
node ../../test-servers/build/server-composable.js \
  --config ../../test-servers/configs/modern-app-elicitation-http.json

Expected output includes:

Composable server listening at http://127.0.0.1:3102/mcp

The fixture contains:

  • mrtr_confirm, a tool that returns input_required on its first call
  • a complete native boolean schema
  • opaque requestState
  • _meta.ui.resourceUri
  • a self-contained text/html;profile=mcp-app resource with Accept, Decline, and Cancel

3. Start MCP Inspector

In terminal 2, from the repository root:

mkdir -p .demo-state/storage

MCP_CATALOG_PATH="$PWD/.demo-state/mcp.json" \
MCP_STORAGE_DIR="$PWD/.demo-state/storage" \
MCP_INSPECTOR_API_TOKEN=local-token \
MCP_AUTO_OPEN_ENABLED=false \
npm run web

Open:

http://localhost:6274/?MCP_INSPECTOR_API_TOKEN=local-token

The isolated .demo-state directory keeps this walkthrough from modifying an existing Inspector catalog.

4. Add and connect to the fixture

  1. Open Servers.
  2. Select Add Servers, then add a server manually.
  3. Name it apps-elicitation-demo.
  4. Select Streamable HTTP and enter http://localhost:3102/mcp.
  5. Open the server's Settings.
  6. Under Options, set Protocol Era to Modern (2026-07-28, sessionless).
  7. Close settings, then disconnect and reconnect the server.

Verify:

  • the server card says MCP 2026-07-28
  • the Protocol sidebar says Modern
  • the first negotiation request is server/discover, not legacy initialize

5. Exercise the MCP App elicitation

  1. Open Tools.
  2. Select mrtr_confirm.
  3. Enter an action, for example publish demo.
  4. Select Execute Tool.
  5. Wait for the App Elicitation Request modal.
  6. Select Accept.

The final result should be:

MRTR complete — confirmation for "publish demo":
{"action":"accept","content":{"confirm":true}}

The Protocol sidebar should group the exchange as an MRTR conversation that moves from Awaiting input to Complete.

Repeat the call with Decline and Cancel if you want to verify all three standard elicitation actions. Decline and cancel do not include accepted content.

What this proves

On the happy path:

  1. The client advertises core elicitation.form and extensions["io.modelcontextprotocol/ui"].elicitation.
  2. The server advertises the matching nested MCP Apps capability.
  3. The tool returns input_required with a complete native form and a valid absolute ui:// resource URI.
  4. Inspector loads the resource in the existing MCP Apps sandbox.
  5. The App and host negotiate the first-class App bridge elicitation capability.
  6. The App returns a standard elicitation result.
  7. Inspector validates that result and retries the same tools/call with:
    • unchanged arguments
    • a new JSON-RPC request id
    • the echoed opaque requestState
    • inputResponses.confirm
  8. The server completes the tool call.

The MCP Apps bridge still negotiates its own 2026-01-26 bridge protocol version. That is independent of the MCP core protocol revision 2026-07-28.

Expected fallback behavior

Inspector must retain and show the complete native form instead of the App when any of these conditions is not met:

  • either peer omits the nested MCP Apps elicitation capability
  • the client does not support core elicitation.form
  • _meta.ui.resourceUri is missing or is not a valid absolute ui:// URI
  • the resource cannot be loaded
  • the App or host omits its bridge elicitation capability
  • App initialization, bridge negotiation, or result validation fails

This is why the request always carries a complete native form: the App is an enhanced renderer for the standard elicitation, not a separate elicitation protocol.

Troubleshooting

The ext-apps package has no dist output

If npm reports that dependency build scripts were blocked:

npm approve-scripts @modelcontextprotocol/ext-apps
npm install

Then rerun the web and launcher builds.

Inspector still shows MCP 2025-11-25

Changing Protocol Era does not renegotiate an active connection. Disconnect and reconnect after selecting Modern (2026-07-28, sessionless).

The native form appears instead of the App

Check the Protocol sidebar and server settings first. Confirm that both peers advertised extensions["io.modelcontextprotocol/ui"].elicitation, that the client also advertised core elicitation.form, and that the request contains a valid _meta.ui.resourceUri.

A port is already in use

Stop the existing process using port 3102 or 6274, or update the fixture config and corresponding Inspector URL.

Related proposals and implementations

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment