Skip to content

Add MCP annotations to tool definitions #45

@ghost

Description

Summary

The tool definitions registered via BaseTool.register() in src/utils/base-tool.ts don't include MCP annotations (readOnlyHint, destructiveHint). These are optional hints in the MCP spec that help LLMs understand the impact of each tool.

Currently server.tool() is called with only name, description, schema, and execute — no annotations are passed.

Suggested annotations

Tool Annotation Reason
create-ui destructiveHint: false Creates new components but doesn't delete/modify existing ones
refine-ui destructiveHint: false Modifies existing components — has side effects but isn't data-destructive
fetch-ui readOnlyHint: true Fetches component examples, no side effects
logo-search readOnlyHint: true Searches for logos, no side effects

Implementation

The @modelcontextprotocol/sdk supports annotations as a parameter to server.tool(). Update BaseTool:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import type { ToolAnnotations } from "@modelcontextprotocol/sdk/types.js";

export abstract class BaseTool {
  abstract name: string;
  abstract description: string;
  abstract schema: z.ZodObject<any>;
  annotations?: ToolAnnotations;

  register(server: McpServer) {
    server.tool(
      this.name,
      this.description,
      { ...this.schema.shape },
      this.execute.bind(this)
    );
    // Note: McpServer.tool() may need to be called with
    // annotations depending on SDK version
  }

  abstract execute(args: z.infer<typeof this.schema>): Promise<{
    content: Array<{ type: "text"; text: string }>;
  }>;
}

Then each tool subclass sets its annotations:

export class FetchUiTool extends BaseTool {
  name = "fetch-ui";
  description = "...";
  annotations = { readOnlyHint: true };
  // ...
}

Why this matters

Annotations help LLMs distinguish between tools that just fetch information (fetch-ui, logo-search) and tools that create or modify artifacts (create-ui, refine-ui). This is especially useful in agentic workflows where the LLM is deciding which tools to call autonomously.

Findings from the MCP Quality Benchmark. You can check tool definitions with the MCP Validator.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions