A tool declaring an `outputSchema` returns its real payload in `structuredContent`; the `content[]` blocks usually only summarize it. v1 rendered that payload as its own inspectable JSON section — v2's ToolResultPanel only ever walked `result.content`, so the payload was dropped with no label, section, or hint that it existed. Adds a `StructuredOutputPanel` group: a collapsible "Structured Output" box (bordered like the existing "Resource Links" box) rendering the payload as pretty-printed, syntax-highlighted, copyable JSON, bounded so a large payload scrolls within itself. ToolResultPanel renders it below the content blocks — and also when `content` is empty (where "No results yet" was simply wrong) and below the alert on an error result, so it is never silently dropped. Adds a `list_items` test-server preset (nested payload, the issue's repro shape) and a `structured-output-http.json` showcase config, documented in the README. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SW1p8E2uiyyLx4RKwrwSrt
302 lines
8.8 KiB
TypeScript
302 lines
8.8 KiB
TypeScript
/**
|
|
* Preset registry for config-driven composable server
|
|
* Maps preset names to fixture factory functions
|
|
*/
|
|
|
|
import type {
|
|
ToolDefinition,
|
|
TaskToolDefinition,
|
|
ResourceDefinition,
|
|
PromptDefinition,
|
|
ResourceTemplateDefinition,
|
|
} from "./composable-test-server.js";
|
|
import {
|
|
createEchoTool,
|
|
createGetEnvTool,
|
|
createAddTool,
|
|
createGetSumTool,
|
|
createGetWeatherTool,
|
|
createInvalidHeaderTool,
|
|
createSpecErrorTriggerTool,
|
|
createWriteToStderrTool,
|
|
createCollectSampleTool,
|
|
createListRootsTool,
|
|
createCollectFormElicitationTool,
|
|
createMrtrTool,
|
|
createMrtrMultiRoundTool,
|
|
createMrtrRootsTool,
|
|
createMrtrSamplingTool,
|
|
createMrtrLoopTool,
|
|
createMrtrEdgeCaseTool,
|
|
createCollectUrlElicitationTool,
|
|
createUrlElicitationFormTool,
|
|
createSendNotificationTool,
|
|
createGetAnnotatedMessageTool,
|
|
createGetTempTool,
|
|
createGetTempExtraTool,
|
|
createListItemsTool,
|
|
createAddResourceTool,
|
|
createRemoveResourceTool,
|
|
createAddToolTool,
|
|
createRemoveToolTool,
|
|
createAddPromptTool,
|
|
createRemovePromptTool,
|
|
createUpdateResourceTool,
|
|
createSendProgressTool,
|
|
createNumberedTools,
|
|
createSimpleTaskTool,
|
|
createProgressTaskTool,
|
|
createElicitationTaskTool,
|
|
createSamplingTaskTool,
|
|
createOptionalTaskTool,
|
|
createForbiddenTaskTool,
|
|
createImmediateReturnTaskTool,
|
|
createMcpAppDemoTool,
|
|
createMcpAppDemoResource,
|
|
createArchitectureResource,
|
|
createTestCwdResource,
|
|
createTestEnvResource,
|
|
createTestArgvResource,
|
|
createNumberedResources,
|
|
createFileResourceTemplate,
|
|
createUserResourceTemplate,
|
|
createNumberedResourceTemplates,
|
|
createSimplePrompt,
|
|
createArgsPrompt,
|
|
createNumberedPrompts,
|
|
} from "./test-server-fixtures.js";
|
|
|
|
export type PresetType = "tool" | "resource" | "resourceTemplate" | "prompt";
|
|
|
|
export type PresetResult =
|
|
| ToolDefinition
|
|
| TaskToolDefinition
|
|
| ResourceDefinition
|
|
| PromptDefinition
|
|
| ResourceTemplateDefinition
|
|
| (ToolDefinition | TaskToolDefinition)[]
|
|
| ResourceDefinition[]
|
|
| ResourceTemplateDefinition[]
|
|
| PromptDefinition[];
|
|
|
|
function resolveToolPreset(
|
|
name: string,
|
|
params?: Record<string, unknown>,
|
|
):
|
|
| ToolDefinition
|
|
| TaskToolDefinition
|
|
| (ToolDefinition | TaskToolDefinition)[] {
|
|
const p = params ?? {};
|
|
const get = (k: string) => p[k] as unknown;
|
|
switch (name) {
|
|
case "echo":
|
|
return createEchoTool();
|
|
case "get-env":
|
|
case "get_env":
|
|
return createGetEnvTool();
|
|
case "add":
|
|
return createAddTool();
|
|
case "get_sum":
|
|
return createGetSumTool();
|
|
case "get_weather":
|
|
return createGetWeatherTool();
|
|
case "invalid_header_tool":
|
|
return createInvalidHeaderTool();
|
|
case "trigger_header_mismatch":
|
|
return createSpecErrorTriggerTool(
|
|
"trigger_header_mismatch",
|
|
"Returns -32020 HeaderMismatch (HTTP 400)",
|
|
);
|
|
case "trigger_missing_capability":
|
|
return createSpecErrorTriggerTool(
|
|
"trigger_missing_capability",
|
|
"Returns -32021 MissingRequiredClientCapability (HTTP 400)",
|
|
);
|
|
case "trigger_unsupported_version":
|
|
return createSpecErrorTriggerTool(
|
|
"trigger_unsupported_version",
|
|
"Returns -32022 UnsupportedProtocolVersion (HTTP 400)",
|
|
);
|
|
case "trigger_method_not_found":
|
|
return createSpecErrorTriggerTool(
|
|
"trigger_method_not_found",
|
|
"Returns -32601 MethodNotFound (HTTP 404)",
|
|
);
|
|
case "trigger_invalid_params":
|
|
return createSpecErrorTriggerTool(
|
|
"trigger_invalid_params",
|
|
"Returns a generic -32602 Invalid params (not an unknown tool)",
|
|
);
|
|
case "write_to_stderr":
|
|
return createWriteToStderrTool();
|
|
case "collect_sample":
|
|
return createCollectSampleTool();
|
|
case "list_roots":
|
|
return createListRootsTool();
|
|
case "collect_elicitation":
|
|
return createCollectFormElicitationTool();
|
|
case "mrtr_confirm":
|
|
return createMrtrTool();
|
|
case "mrtr_two_step":
|
|
return createMrtrMultiRoundTool();
|
|
case "mrtr_roots":
|
|
return createMrtrRootsTool();
|
|
case "mrtr_sample":
|
|
return createMrtrSamplingTool();
|
|
case "mrtr_loop":
|
|
return createMrtrLoopTool();
|
|
case "mrtr_edge":
|
|
return createMrtrEdgeCaseTool();
|
|
case "collect_url_elicitation":
|
|
return createCollectUrlElicitationTool();
|
|
case "url_elicitation_form":
|
|
return createUrlElicitationFormTool();
|
|
case "send_notification":
|
|
return createSendNotificationTool();
|
|
case "get_annotated_message":
|
|
return createGetAnnotatedMessageTool();
|
|
case "get_temp":
|
|
return createGetTempTool();
|
|
case "get_temp_extra":
|
|
return createGetTempExtraTool();
|
|
case "list_items":
|
|
return createListItemsTool();
|
|
case "add_resource":
|
|
return createAddResourceTool();
|
|
case "remove_resource":
|
|
return createRemoveResourceTool();
|
|
case "add_tool":
|
|
return createAddToolTool();
|
|
case "remove_tool":
|
|
return createRemoveToolTool();
|
|
case "add_prompt":
|
|
return createAddPromptTool();
|
|
case "remove_prompt":
|
|
return createRemovePromptTool();
|
|
case "update_resource":
|
|
return createUpdateResourceTool();
|
|
case "send_progress":
|
|
return createSendProgressTool(get("name") as string | undefined);
|
|
case "numbered_tools":
|
|
return createNumberedTools(Number(get("count")) || 5);
|
|
case "simple_task":
|
|
return createSimpleTaskTool(
|
|
get("name") as string | undefined,
|
|
Number(get("delayMs")) || undefined,
|
|
);
|
|
case "progress_task":
|
|
return createProgressTaskTool(
|
|
get("name") as string | undefined,
|
|
Number(get("delayMs")) || undefined,
|
|
Number(get("progressUnits")) || undefined,
|
|
);
|
|
case "elicitation_task":
|
|
return createElicitationTaskTool(get("name") as string | undefined);
|
|
case "sampling_task":
|
|
return createSamplingTaskTool(
|
|
get("name") as string | undefined,
|
|
get("samplingText") as string | undefined,
|
|
);
|
|
case "optional_task":
|
|
return createOptionalTaskTool(
|
|
get("name") as string | undefined,
|
|
Number(get("delayMs")) || undefined,
|
|
);
|
|
case "forbidden_task":
|
|
return createForbiddenTaskTool(
|
|
get("name") as string | undefined,
|
|
Number(get("delayMs")) || undefined,
|
|
);
|
|
case "immediate_return_task":
|
|
return createImmediateReturnTaskTool(
|
|
get("name") as string | undefined,
|
|
Number(get("delayMs")) || undefined,
|
|
);
|
|
case "mcp_app_demo":
|
|
return createMcpAppDemoTool();
|
|
default:
|
|
throw new Error(`Unknown tool preset: ${name}`);
|
|
}
|
|
}
|
|
|
|
function resolveResourcePreset(
|
|
name: string,
|
|
params?: Record<string, unknown>,
|
|
): ResourceDefinition | ResourceDefinition[] {
|
|
const p = params ?? {};
|
|
const get = (k: string) => p[k] as unknown;
|
|
switch (name) {
|
|
case "architecture":
|
|
return createArchitectureResource();
|
|
case "test_cwd":
|
|
return createTestCwdResource();
|
|
case "test_env":
|
|
return createTestEnvResource();
|
|
case "test_argv":
|
|
return createTestArgvResource();
|
|
case "numbered_resources":
|
|
return createNumberedResources(Number(get("count")) || 3);
|
|
case "mcp_app_demo_widget":
|
|
return createMcpAppDemoResource();
|
|
default:
|
|
throw new Error(`Unknown resource preset: ${name}`);
|
|
}
|
|
}
|
|
|
|
function resolveResourceTemplatePreset(
|
|
name: string,
|
|
params?: Record<string, unknown>,
|
|
): ResourceTemplateDefinition | ResourceTemplateDefinition[] {
|
|
const p = params ?? {};
|
|
const get = (k: string) => p[k] as unknown;
|
|
switch (name) {
|
|
case "file":
|
|
return createFileResourceTemplate();
|
|
case "user":
|
|
return createUserResourceTemplate();
|
|
case "numbered_resource_templates":
|
|
return createNumberedResourceTemplates(Number(get("count")) || 3);
|
|
default:
|
|
throw new Error(`Unknown resource template preset: ${name}`);
|
|
}
|
|
}
|
|
|
|
function resolvePromptPreset(
|
|
name: string,
|
|
params?: Record<string, unknown>,
|
|
): PromptDefinition | PromptDefinition[] {
|
|
const p = params ?? {};
|
|
const get = (k: string) => p[k] as unknown;
|
|
switch (name) {
|
|
case "simple_prompt":
|
|
return createSimplePrompt();
|
|
case "args_prompt":
|
|
return createArgsPrompt();
|
|
case "numbered_prompts":
|
|
return createNumberedPrompts(Number(get("count")) || 3);
|
|
default:
|
|
throw new Error(`Unknown prompt preset: ${name}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resolve a preset by type and name to definition(s)
|
|
*/
|
|
export function resolvePreset(
|
|
type: PresetType,
|
|
name: string,
|
|
params?: Record<string, unknown>,
|
|
): PresetResult {
|
|
switch (type) {
|
|
case "tool":
|
|
return resolveToolPreset(name, params);
|
|
case "resource":
|
|
return resolveResourcePreset(name, params);
|
|
case "resourceTemplate":
|
|
return resolveResourceTemplatePreset(name, params);
|
|
case "prompt":
|
|
return resolvePromptPreset(name, params);
|
|
default:
|
|
throw new Error(`Unknown preset type: ${type}`);
|
|
}
|
|
}
|