Skip to content

sub(#250) Phase 3: MCP tool result rendering with schema-based views #275

@mmogr

Description

@mmogr

Summary

Add renderer support for MCP tool results, using schema-based rendering when tool output schemas are available and generic structured rendering otherwise.

Context

MCP tools are dynamically registered from external servers. Unlike built-in tools, their output format is only known at runtime (if the MCP server declares an output schema) or not at all. This phase extends the rendering system to handle MCP tools gracefully.

Proposed Changes

1. Schema-based MCP result rendering

When an MCP tool declares an output JSON schema, auto-generate a renderer:

// src/services/tools/renderers/McpSchemaRenderer.tsx

function McpSchemaRenderer({ data, schema }: Props) {
  // Use the JSON Schema to render a structured view:
  // - Objects: key-value table
  // - Arrays of objects: data table with sortable columns
  // - Strings with format "uri": clickable links
  // - Strings with format "date-time": formatted dates
  // - Numbers: formatted with locale
  return <SchemaBasedView data={data} schema={schema} />;
}

2. Extend MCP registration to capture output schemas

// src/services/tools/mcpIntegration.ts

async function registerMcpTools(serverId: string, tools: McpToolDef[]) {
  for (const tool of tools) {
    registry.register({
      name: `mcp_${serverId}_${tool.name}`,
      // ... existing fields ...
      renderer: tool.outputSchema 
        ? createSchemaRenderer(tool.outputSchema)
        : undefined,
      outputSchema: tool.outputSchema, // preserve for later use
    });
  }
}

3. Generic MCP fallback renderer

For MCP tools without output schemas, improve the generic renderer:

function McpGenericRenderer({ data, toolName }: Props) {
  // Smart heuristics:
  // - If data is a string that looks like markdown → render as markdown
  // - If data is an array of objects with consistent keys → render as table
  // - If data contains 'url' or 'href' keys → render as clickable links
  // - Otherwise → pretty-printed JSON with syntax highlighting
  return <SmartDataView data={data} />;
}

4. MCP tool result caching for re-render

Since MCP tool calls can be expensive, cache the rendered result:

// Memoize rendered results by tool call ID
const renderedResults = useMemo(() => {
  return new Map<string, React.ReactNode>();
}, []);

Files to Create/Modify

File Change
src/services/tools/renderers/McpSchemaRenderer.tsx New: schema-based renderer
src/services/tools/renderers/McpGenericRenderer.tsx New: heuristic-based generic renderer
src/services/tools/mcpIntegration.ts Capture output schemas, attach renderers
src/services/tools/types.ts Add outputSchema to ToolRegistration
src/services/tools/renderers/SchemaBasedView.tsx New: JSON Schema → React component

Dependencies

Acceptance Criteria

  • MCP tools with output schemas get auto-generated structured renderers
  • Array-of-objects data renders as a sortable table
  • URL fields render as clickable links
  • MCP tools without schemas use smart heuristic rendering
  • Markdown-like string content renders as markdown
  • Rendered results are memoized to avoid re-computation
  • Works with all existing MCP servers (no regressions)
  • Schema renderer handles nested objects (at least 2 levels deep)

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions