Skip to content

feat(mcp): add ToolCapability metadata to MCPToolDefinition #14

@shaun0927

Description

@shaun0927

Summary

Add a ToolCapability dataclass to MCPToolDefinition that describes the semantic properties of each tool — enabling the engine to understand what a tool does, not just its name.

Background

Currently MCPToolDefinition (src/ouroboros/mcp/types.py:90) only has:

  • name, description, parameters, server_name

The engine treats all tools equally — it cannot distinguish Read (safe, idempotent) from Bash (potentially destructive, non-idempotent). This is the "hammer, knife, ruler" problem identified by the maintainer (JQ) in the AS-IS architecture discussion.

Proposed Design

# src/ouroboros/mcp/types.py

class SideEffect(StrEnum):
    NONE = "none"              # Pure computation (no external state)
    READ = "read"              # Reads external state (WebSearch, ListFiles)
    WRITE = "write"            # Modifies external state (Edit, CreateFile)
    DESTRUCTIVE = "destructive"  # Hard to reverse (Delete, Bash rm)

class ApprovalLevel(StrEnum):
    AUTO = "auto"              # Execute without confirmation
    SUGGEST = "suggest"        # Log warning, proceed
    REQUIRED = "required"      # Block until explicit approval

@dataclass(frozen=True, slots=True)
class ToolCapability:
    """Semantic metadata for tool policy decisions."""
    side_effect: SideEffect = SideEffect.NONE
    parallel_safe: bool = True
    approval: ApprovalLevel = ApprovalLevel.AUTO
    idempotent: bool = True

Add to MCPToolDefinition:

@dataclass(frozen=True, slots=True)
class MCPToolDefinition:
    name: str
    description: str
    parameters: tuple[MCPToolParameter, ...] = field(default_factory=tuple)
    server_name: str | None = None
    capability: ToolCapability | None = None  # NEW — optional for backward compat

Why These 4 Fields

Following ttaco's community feedback: "Start with a small set of enforceable fields... then expand only after validating against real usage."

Field Answers Example
side_effect "Does this tool change external state?" Bash(rm) → destructive
parallel_safe "Can multiple instances run concurrently?" DB write → false
approval "Does this need human confirmation?" delete_branch → required
idempotent "Is re-execution safe?" Read → yes, POST → no

Files to Modify

  • src/ouroboros/mcp/types.py — Add SideEffect, ApprovalLevel, ToolCapability, extend MCPToolDefinition
  • tests/unit/mcp/test_types.py — Unit tests for new types
  • Handler definitions (each handler's .definition property) — Annotate with appropriate capability

Acceptance Criteria

  • ToolCapability dataclass defined with 4 fields
  • MCPToolDefinition.capability is optional (backward compatible)
  • All existing tests pass without modification
  • At least Ouroboros' own 21 handlers annotated with capabilities
  • to_input_schema() unaffected (capability is metadata, not input schema)

Dependencies

None — this is the foundation for Policy Plane (#mid-term-1) and Role Envelope (#mid-term-3).

Priority

Short-term — Can be implemented immediately with no architectural changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions