Loading skill
Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Comprehensive verification checklists for MCP Apps. Tests with basic-host reference, validates handler-before-connect, text fallback, resource URI linking, single-file bundling, host styling, CSP, and legacy pattern detection.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 60% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 154% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 75% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 95% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 92% | 0% |
Run comprehensive verification checklists for MCP Apps covering correctness, compatibility, and migration completeness.
MCP Apps have several critical invariants that must be verified before deployment. This skill provides systematic verification across multiple dimensions:
app.connect() callontoolinput, ontoolresult, onhostcontextchanged, onteardown) are registered BEFORE connectcontent array in return value{ type: 'text', text: '...' } entrystructuredContent without text fallbackresourceUri values from registerAppTool callsregisterAppResource callsresourceUri has a matching registered resourcedist/mcp-app.html (or equivalent) exists<script src>, <link href>, <img src> to relative paths)vite-plugin-singlefile is in dev dependenciesvar(--color-*, var(--font-*, var(--border-radius-* patternsvar(--color-background-primary, #ffffff) not just var(--color-background-primary)onhostcontextchanged handler exists and applies stylingregisterAppResourcewindow.openai.toolInput, window.openai.toolOutput, window.openaiopenai/text/html+skybridgetext/html;profile=mcp-app (should use RESOURCE_MIME_TYPE)_domains" or _domains: (should be camelCase)bash# Step 1: Build the project npm run build # Step 2: Verify single-file bundle ls -la dist/mcp-app.html # Should be a single file with all assets inlined # Step 3: Check for external references in bundle grep -E '<script src="|<link.*href="|<img src="(?!data:)' dist/mcp-app.html # Should return NOTHING (all assets inlined) # Step 4: Start server npm run serve & SERVER_PID=$! # Step 5: Test with basic-host cd /tmp/mcp-ext-apps/examples/basic-host SERVERS='["http://localhost:3001/mcp"]' npm run start # Verify: app loads, handlers fire, styling applies # Step 6: Stop server kill $SERVER_PID
bash# Handler-before-connect check # Find app.connect() and verify handlers are above it grep -n 'app\.connect\|\.ontoolinput\|\.ontoolresult\|\.onhostcontextchanged\|\.onteardown' src/main.ts # Text fallback check # Every tool handler should return content array grep -A5 'return {' src/server.ts | grep -c 'content:' # Resource URI linking grep 'resourceUri' src/server.ts grep "registerAppResource" src/server.ts # RESOURCE_MIME_TYPE usage (not hardcoded) grep 'RESOURCE_MIME_TYPE' src/server.ts grep "text/html;profile" src/server.ts # Should NOT match # CSS variable fallbacks grep -c 'var(--.*,' src/global.css # Count with fallbacks grep 'var(--' src/global.css | grep -v ',' # Flag missing fallbacks
bash# Server-side legacy patterns grep -rn 'openai/' src/ # Old metadata paths grep -rn 'text/html+skybridge' src/ # Old MIME type grep -rn "text/html;profile=mcp-app" src/ # Hardcoded (use RESOURCE_MIME_TYPE) grep -rn '_domains"' src/ # Snake_case CSP grep -rn "_domains:" src/ # Snake_case CSP # Client-side legacy patterns grep -rn 'window\.openai\.toolInput' src/ grep -rn 'window\.openai\.toolOutput' src/ grep -rn 'window\.openai' src/ # All should return ZERO matches
bash#!/bin/bash # mcp-app-verify.sh - Comprehensive MCP App verification ERRORS=0 echo "=== MCP App Verification ===" # 1. Build echo "[1/8] Building..." npm run build 2>&1 || { echo "FAIL: Build failed"; ERRORS=$((ERRORS+1)); } # 2. Single-file bundle echo "[2/8] Checking single-file bundle..." if [ ! -f dist/mcp-app.html ]; then echo "FAIL: dist/mcp-app.html not found" ERRORS=$((ERRORS+1)) fi # 3. No external references echo "[3/8] Checking for external references..." EXT_REFS=$(grep -cE 'src="(?!data:)[^"]+"|href="(?!data:)[^"]+\.css"' dist/mcp-app.html 2>/dev/null || echo "0") if [ "$EXT_REFS" -gt 0 ]; then echo "WARN: Found $EXT_REFS potential external references" fi # 4. Handler-before-connect echo "[4/8] Checking handler-before-connect..." CONNECT_LINE=$(grep -n 'app\.connect()' src/main.ts* 2>/dev/null | head -1 | cut -d: -f2) if [ -n "$CONNECT_LINE" ]; then LATE_HANDLERS=$(grep -n '\.on\(toolinput\|toolresult\|hostcontextchanged\|teardown\)' src/main.ts* 2>/dev/null | awk -F: -v cl="$CONNECT_LINE" '$2 > cl') if [ -n "$LATE_HANDLERS" ]; then echo "FAIL: Handlers registered after app.connect()" ERRORS=$((ERRORS+1)) fi fi # 5. Text fallback echo "[5/8] Checking text fallback..." # (manual review needed for complex cases) # 6. RESOURCE_MIME_TYPE echo "[6/8] Checking RESOURCE_MIME_TYPE usage..." HARDCODED=$(grep -rn "text/html;profile=mcp-app" src/ 2>/dev/null | wc -l) if [ "$HARDCODED" -gt 0 ]; then echo "FAIL: Hardcoded MIME type found (use RESOURCE_MIME_TYPE)" ERRORS=$((ERRORS+1)) fi # 7. CSS fallbacks echo "[7/8] Checking CSS variable fallbacks..." NO_FALLBACK=$(grep 'var(--' src/*.css 2>/dev/null | grep -v ',' | wc -l) if [ "$NO_FALLBACK" -gt 0 ]; then echo "WARN: $NO_FALLBACK CSS variables without fallback values" fi # 8. Legacy patterns (migration) echo "[8/8] Checking for legacy patterns..." LEGACY=$(grep -rn 'window\.openai\|text/html+skybridge\|_domains"' src/ 2>/dev/null | wc -l) if [ "$LEGACY" -gt 0 ]; then echo "FAIL: $LEGACY legacy patterns found" ERRORS=$((ERRORS+1)) fi echo "" if [ "$ERRORS" -eq 0 ]; then echo "PASS: All verification checks passed" else echo "FAIL: $ERRORS verification errors found" fi exit $ERRORS
dist/mcp-app.html exists and is self-contained single filevite-plugin-singlefile in devDependenciesapp.connect()content[] with text fallbackresourceUri matches a registered resourceRESOURCE_MIME_TYPE used (not hardcoded string)var(--name, fallback) patternonhostcontextchanged handler registeredresourceDomains / connectDomains / frameDomainscontents[] of registerAppResource read callbackwindow.openai referencestext/html+skybridge referencesopenai/ metadata paths_domains)text/html;profile=mcp-app (use RESOURCE_MIME_TYPE)ontoolinput fires with tool argumentsontoolresult fires with tool resultjavascriptconst mcpAppVerificationTask = defineTask({ name: 'mcp-app-verification', description: 'Run comprehensive MCP App verification', inputs: { projectDir: { type: 'string', required: true }, isMigration: { type: 'boolean', default: false }, migrationSource: { type: 'string', default: '' }, checkCsp: { type: 'boolean', default: true } }, outputs: { passed: { type: 'boolean' }, errors: { type: 'array' }, warnings: { type: 'array' }, artifacts: { type: 'array' } }, async run(inputs, taskCtx) { return { kind: 'skill', title: `Verify MCP App: ${inputs.projectDir}`, skill: { name: 'mcp-app-verification', context: { projectDir: inputs.projectDir, isMigration: inputs.isMigration, migrationSource: inputs.migrationSource, checkCsp: inputs.checkCsp, instructions: [ 'Build the application', 'Verify single-file bundle integrity', 'Check handler-before-connect invariant', 'Verify text fallback in all tools', 'Validate resource URI linking', 'Check CSS variable fallbacks', inputs.checkCsp ? 'Verify CSP completeness' : null, inputs.isMigration ? 'Search for legacy patterns' : null, 'Test with basic-host reference' ].filter(Boolean) } }, io: { inputJsonPath: `tasks/${taskCtx.effectId}/input.json`, outputJsonPath: `tasks/${taskCtx.effectId}/result.json` } }; } });
Other measured skills in the registry, with their headline benchmark lift.