Skip to content

Use types for tool annotations to reduce confusion #927

@kentcdodds

Description

@kentcdodds

Is your feature request related to a problem? Please describe.

The way that tool annotations work is confusing because some of the properties only matter if you have read-only set to false.

Describe the solution you'd like

I would like to have type warnings if I am setting destructiveHint or idempotentHint to anything when readOnly is set to false.

Something like this:

Implement a discriminated union type that:

  1. Enforces the read-only constraint: When readOnlyHint: true, destructiveHint and idempotentHint cannot be specified
  2. Prevents redundant defaults: Only allows specifying properties when they differ from their default values
  3. Uses defaults: destructiveHint: true, idempotentHint: false, openWorldHint: true, readOnlyHint: false

Proposed Type Definition:

type ToolAnnotations = 
  | {
      readOnlyHint: true;
      openWorldHint?: boolean;
    }
  | {
      destructiveHint?: false;  // Only allow false (default is true)
      idempotentHint?: true;   // Only allow true (default is false)  
      openWorldHint?: false;   // Only allow false (default is true)
    };

Benefits:

  • Cleaner configurations: No need to specify default values
  • Type safety: Prevents invalid combinations at compile time
  • Explicit intent: Only specify what differs from defaults
  • Constraint enforcement: Cannot set destructive/idempotent on read-only tools

Examples:

type ToolAnnotations = 
  | {
      readOnlyHint: true;
      openWorldHint?: boolean;
    }
  | {
      destructiveHint?: false;  // Only allow false (default is true)
      idempotentHint?: true;   // Only allow true (default is false)  
      openWorldHint?: false;   // Only allow false (default is true)
    };

// ✅ Clean - all defaults
const defaultTool: ToolAnnotations = {};

// ✅ Only specify non-defaults
const nonDestructiveTool: ToolAnnotations = {
  destructiveHint: false  // Only specify when false (default is true)
};

// ✅ Read-only tool
const readOnlyTool: ToolAnnotations = {
  readOnlyHint: true,
  openWorldHint: false
};

// ❌ TypeScript error - cannot specify defaults
const invalidDefaults: ToolAnnotations = {
  destructiveHint: true,  // Error: Type 'true' is not assignable to type 'false'
  idempotentHint: false,   // Error: Type 'false' is not assignable to type 'true'
  openWorldHint: true      // Error: Type 'true' is not assignable to type 'false'
};

// ❌ TypeScript error - cannot set destructive/idempotent on read-only
const invalidReadOnly: ToolAnnotations = {
  readOnlyHint: true,
  destructiveHint: true  // Error: Property 'destructiveHint' does not exist
};

Describe alternatives you've considered

The status quo is me being pretty confused 😅

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Moderate issues affecting some users, edge cases, potentially valuable featureenhancementRequest for a new feature that's not currently supportedready for workEnough information for someone to start working on

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions