Skip to content

Commit 354b33d

Browse files
web-flowclaude
andcommitted
feat: Add tool annotations for improved LLM tool understanding
Add readOnlyHint and destructiveHint annotations to all tools to help LLMs better understand tool behavior and make safer decisions. Changes: - Added ToolAnnotations import from MCP SDK types - Modified BaseTool class to support annotations property - Added destructiveHint: true to CreateUiTool (creates/modifies files) - Added readOnlyHint: true to FetchUiTool (read-only API call) - Added destructiveHint: true to LogoSearchTool (writes to filesystem) - Added destructiveHint: true to RefineUiTool (modifies components) - Added openWorldHint: true to all tools (interact with external APIs) - Added title annotations for human-readable display - Bump MCP SDK from ^1.8.0 to ^1.25.1 for annotation support This improves tool safety metadata for MCP clients. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ba1f71e commit 354b33d

File tree

7 files changed

+174
-29
lines changed

7 files changed

+174
-29
lines changed

package-lock.json

Lines changed: 144 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"author": "serafim@21st.dev",
3939
"license": "ISC",
4040
"dependencies": {
41-
"@modelcontextprotocol/sdk": "^1.8.0",
41+
"@modelcontextprotocol/sdk": "^1.25.1",
4242
"@types/cors": "^2.8.17",
4343
"@types/express": "^5.0.0",
4444
"cors": "^2.8.5",

src/tools/create-ui.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { z } from "zod";
2-
import { BaseTool } from "../utils/base-tool.js";
2+
import { BaseTool, ToolAnnotations } from "../utils/base-tool.js";
33
import { twentyFirstClient } from "../utils/http-client.js";
44
import { CallbackServer } from "../utils/callback-server.js";
55
import open from "open";
@@ -19,6 +19,11 @@ interface CreateUiResponse {
1919
export class CreateUiTool extends BaseTool {
2020
name = UI_TOOL_NAME;
2121
description = UI_TOOL_DESCRIPTION;
22+
annotations: ToolAnnotations = {
23+
title: "Create UI Component",
24+
destructiveHint: true,
25+
openWorldHint: true,
26+
};
2227

2328
schema = z.object({
2429
message: z.string().describe("Full users message"),

src/tools/fetch-ui.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { z } from "zod";
2-
import { BaseTool } from "../utils/base-tool.js";
2+
import { BaseTool, ToolAnnotations } from "../utils/base-tool.js";
33
import { twentyFirstClient } from "../utils/http-client.js";
44

55
const FETCH_UI_TOOL_NAME = "21st_magic_component_inspiration";
@@ -15,6 +15,11 @@ interface FetchUiResponse {
1515
export class FetchUiTool extends BaseTool {
1616
name = FETCH_UI_TOOL_NAME;
1717
description = FETCH_UI_TOOL_DESCRIPTION;
18+
annotations: ToolAnnotations = {
19+
title: "Fetch UI Inspiration",
20+
readOnlyHint: true,
21+
openWorldHint: true,
22+
};
1823

1924
schema = z.object({
2025
message: z.string().describe("Full users message"),

src/tools/logo-search.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { z } from "zod";
22
import { promises as fs } from "fs";
3-
import { BaseTool } from "../utils/base-tool.js";
3+
import { BaseTool, ToolAnnotations } from "../utils/base-tool.js";
44

55
// Types for SVGL API responses
66
interface ThemeOptions {
@@ -49,6 +49,11 @@ Each result includes:
4949
export class LogoSearchTool extends BaseTool {
5050
name = LOGO_TOOL_NAME;
5151
description = LOGO_TOOL_DESCRIPTION;
52+
annotations: ToolAnnotations = {
53+
title: "Search Logos",
54+
destructiveHint: true,
55+
openWorldHint: true,
56+
};
5257

5358
schema = z.object({
5459
queries: z

src/tools/refine-ui.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { z } from "zod";
2-
import { BaseTool } from "../utils/base-tool.js";
2+
import { BaseTool, ToolAnnotations } from "../utils/base-tool.js";
33
import { twentyFirstClient } from "../utils/http-client.js";
44
import { getContentOfFile } from "../utils/get-content-of-file.js";
55

@@ -17,6 +17,11 @@ interface RefineUiResponse {
1717
export class RefineUiTool extends BaseTool {
1818
name = REFINE_UI_TOOL_NAME;
1919
description = REFINE_UI_TOOL_DESCRIPTION;
20+
annotations: ToolAnnotations = {
21+
title: "Refine UI Component",
22+
destructiveHint: true,
23+
openWorldHint: true,
24+
};
2025

2126
schema = z.object({
2227
userMessage: z.string().describe("Full user's message about UI refinement"),

src/utils/base-tool.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2+
import { ToolAnnotations } from "@modelcontextprotocol/sdk/types.js";
23
import { z } from "zod";
34

5+
export { ToolAnnotations };
6+
47
export abstract class BaseTool {
58
abstract name: string;
69
abstract description: string;
710
abstract schema: z.ZodObject<any>;
11+
abstract annotations: ToolAnnotations;
812

913
register(server: McpServer) {
1014
server.tool(
1115
this.name,
1216
this.description,
1317
this.schema.shape,
18+
this.annotations,
1419
this.execute.bind(this)
1520
);
1621
}

0 commit comments

Comments
 (0)