Skip to content

Commit 84275d8

Browse files
committed
docs(skill): add UI support check and data handling gotchas
1 parent f6ee5d5 commit 84275d8

1 file changed

Lines changed: 52 additions & 0 deletions

File tree

  • plugins/mcp-apps/skills/create-mcp-app

plugins/mcp-apps/skills/create-mcp-app/SKILL.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,34 @@ Host calls tool → Server returns result → Host renders resource UI → UI re
4141
- Register tools and resources
4242
- Configure build system with `vite-plugin-singlefile`
4343

44+
### Checking Host UI Support
45+
46+
Not all hosts support MCP Apps. Use `hasUiSupport()` to conditionally register UI-enabled tools:
47+
48+
```typescript
49+
import { hasUiSupport, registerAppTool } from "@modelcontextprotocol/ext-apps/server";
50+
51+
server.oninitialized = ({ clientCapabilities }) => {
52+
if (hasUiSupport(clientCapabilities)) {
53+
// Register tool with UI
54+
registerAppTool(server, "weather", {
55+
description: "Get weather with interactive dashboard",
56+
_meta: { ui: { resourceUri: "ui://weather/dashboard" } },
57+
}, weatherHandler);
58+
} else {
59+
// Register text-only fallback for hosts without UI support
60+
server.registerTool("weather", {
61+
description: "Get weather as text",
62+
}, textWeatherHandler);
63+
}
64+
};
65+
```
66+
67+
**Key points:**
68+
- Check `clientCapabilities` in `oninitialized` callback
69+
- `hasUiSupport()` checks both `experimental` and `extensions` fields
70+
- Provide text-only fallback for non-UI hosts
71+
4472
## Getting Reference Code
4573

4674
Clone the SDK repository for working examples and API documentation:
@@ -312,6 +340,30 @@ See `examples/shadertoy-server/` for complete implementation.
312340
6. **No text fallback** - Always provide `content` array for non-UI hosts
313341
7. **Hardcoded styles** - Use host CSS variables for theme integration
314342
8. **No streaming for large inputs** - Use `ontoolinputpartial` to show progress during generation
343+
9. **Binary/large data in `content` or `structuredContent`** - Use `_meta` to avoid polluting model context
344+
345+
## Data Handling: content vs structuredContent vs _meta
346+
347+
| Field | Goes to model? | Use for |
348+
|-------|---------------|---------|
349+
| `content` | ✅ YES | Text summary for model |
350+
| `structuredContent` | ✅ YES | Structured data for model + UI |
351+
| `_meta` | ❌ NO | Binary data, large blobs, UI-only data |
352+
353+
**Critical**: Binary/large data MUST go in `_meta` to avoid wasting tokens and confusing the model.
354+
355+
```typescript
356+
// ❌ WRONG - base64 pollutes model context
357+
return {
358+
content: [{ type: "image", data: base64Image, mimeType: "image/png" }]
359+
};
360+
361+
// ✅ CORRECT - model gets summary, UI gets data from _meta
362+
return {
363+
content: [{ type: "text", text: "Generated QR code for: example.com" }],
364+
_meta: { imageData: base64Image, mimeType: "image/png" }
365+
};
366+
```
315367

316368
## Testing
317369

0 commit comments

Comments
 (0)