Skip to content

Support MCP tool annotations for composite tools #6192

Description

@danbarr

Problem

Composite tools don't expose a way to set MCP tool annotations — readOnlyHint, destructiveHint, idempotentHint, openWorldHint. Clients that use these hints to gate confirmation prompts or filter destructive actions have no signal for composite tools, even when the workflow author knows the semantics (e.g. a composite tool that only reads data, or one that deletes resources).

The vmcp.Tool.Annotations type already models all four hints (pkg/vmcp/types.go), and regular backend/aggregated tools can already override annotations via ToolAnnotationsOverride in the aggregation config (pkg/vmcp/aggregator/tool_adapter.go, manual_resolver.go, priority_resolver.go). Composite tools never wire into this path.

Current behavior

  • CompositeToolConfig (pkg/vmcp/config/config.go:682-720) has no annotations field.
  • ConvertWorkflowDefsToTools (pkg/vmcp/internal/compositetools/workflow_converter.go:121-143) builds each vmcp.Tool with only Name, Description, InputSchema, and optionally OutputSchemaAnnotations is left nil.
  • The operator CRD VirtualMCPCompositeToolDefinitionSpec (cmd/thv-operator/api/v1beta1/virtualmcpcompositetooldefinition_types.go) embeds CompositeToolConfig inline, so it inherits the same gap.

Proposed change

  • Add an Annotations *vmcp.ToolAnnotations (or equivalent) field to CompositeToolConfig, settable in the workflow YAML/CRD, for explicit author-provided annotations.
  • Populate tool.Annotations in ConvertWorkflowDefsToTools from this field.
  • When no explicit annotation is provided, derive a safe default per hint from the workflow's underlying step tools:
    • readOnlyHint: AND across steps — true only if every step tool sets readOnlyHint: true. A step with the hint unset or false makes the composite non-read-only.
    • destructiveHint: OR across steps — true if any step is destructive or its destructiveness is unknown (unset). One destructive write anywhere in the chain taints the whole workflow.
    • openWorldHint: OR across steps, same reasoning — one call to an unpredictable external system makes the composite open-world too.
    • idempotentHint: don't auto-derive. All-steps-idempotent doesn't imply the workflow is idempotent as a whole (e.g. step 2 branches on step 1's output and behaves differently on retry). Leave unset unless the author explicitly opts in.
  • Add a validation guardrail for explicit overrides: reject (at config load/admission time) any explicit annotation that contradicts the derived floor — e.g. readOnlyHint: true while any step carries destructiveHint: true or lacks readOnlyHint.
  • Regenerate CRD manifests and deepcopy code (task operator-generate).
  • Update composite tool docs/examples to show how to set annotations.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestneeds-triageIssue needs initial triage by a maintainervmcpVirtual MCP Server related issues

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions