feat(test-servers): mcp_app_demo preset + _meta on tool/resource defs (closes #1557)

Add an `mcp_app_demo` tool/resource preset — a self-contained MCP App widget
that exercises size-changed, ui/message, log notifications, and host-context
rendering with no external server. Requires plumbing an optional `_meta` field
through the composable test server's `ToolDefinition` and `ResourceDefinition`
so clients can read tool-level `_meta.ui.resourceUri` and resource-level
`_meta.ui.csp`.

- composable-test-server: optional `_meta` on ToolDefinition/ResourceDefinition,
  passed through to registerTool config and the resource content item.
- test-server-fixtures: `createMcpAppDemoTool()`, `createMcpAppDemoResource()`,
  inline `MCP_APP_DEMO_HTML` widget; wired into getDefaultServerConfig.
- preset-registry: `mcp_app_demo` tool + `mcp_app_demo_widget` resource presets.
- integration test asserting the `_meta` plumbing end-to-end.

Wave 1 of PR #1510 decomposition.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S3fTN8H3R8YV4yUGvZjYnX
This commit is contained in:
cliffhall 2026-07-01 18:22:25 -04:00
commit 0d50b908a3

View file

@ -102,6 +102,8 @@ export interface ToolDefinition {
inputSchema?: ToolInputSchema;
/** Optional Zod object schema for tool output; when set, handler must return structuredContent. */
outputSchema?: unknown;
/** Passed through to the SDK so clients can read tool-level `_meta` (e.g. `_meta.ui.resourceUri` for MCP App tools). */
_meta?: Record<string, unknown>;
handler: (
params: Record<string, unknown>,
context?: TestServerContext,
@ -123,6 +125,8 @@ export interface ResourceDefinition {
description?: string;
mimeType?: string;
text?: string;
/** Included on the returned content item so clients can read resource-level `_meta` (e.g. `_meta.ui.csp` for MCP App UI resources). */
_meta?: Record<string, unknown>;
}
export interface PromptDefinition {
@ -500,6 +504,7 @@ export function createMcpServer(config: ServerConfig): McpServer {
...(tool.outputSchema != null && {
outputSchema: tool.outputSchema as AnySchema,
}),
...(tool._meta != null && { _meta: tool._meta }),
},
async (args, extra) => {
const result = await tool.handler(
@ -565,6 +570,7 @@ export function createMcpServer(config: ServerConfig): McpServer {
uri: resource.uri,
mimeType: resource.mimeType || "text/plain",
text: resource.text ?? "",
...(resource._meta != null && { _meta: resource._meta }),
},
],
};