Refactoring: Rename Tool -> ToolInterface, TypeSafeTool -> Tool

This commit is contained in:
Dominik Jain 2025-09-11 16:13:13 +02:00
parent e714caaef2
commit 472dcd7890
4 changed files with 22 additions and 25 deletions

View File

@ -22,9 +22,9 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { CallToolRequestSchema, CallToolResult, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js"; import { CallToolRequestSchema, CallToolResult, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import { WebSocketServer, WebSocket } from "ws"; import { WebSocketServer, WebSocket } from "ws";
import { Tool } from "./interfaces/Tool.js"; import { ToolInterface } from "./interfaces/Tool.js";
import { HelloWorldTool } from "./tools/HelloWorldTool.js"; import { HelloWorldTool } from "./tools/HelloWorldTool.js";
import { ToolPrintText } from "./tools/ToolPrintText.js"; import { PrintTextTool } from "./tools/PrintTextTool";
/** /**
* Main MCP server implementation for Penpot integration. * Main MCP server implementation for Penpot integration.
@ -34,7 +34,7 @@ import { ToolPrintText } from "./tools/ToolPrintText.js";
*/ */
class PenpotMcpServer { class PenpotMcpServer {
private readonly server: Server; private readonly server: Server;
private readonly tools: Map<string, Tool>; private readonly tools: Map<string, ToolInterface>;
private readonly wsServer: WebSocketServer; private readonly wsServer: WebSocketServer;
private readonly connectedClients: Set<WebSocket> = new Set(); private readonly connectedClients: Set<WebSocket> = new Set();
private app: any; // Express app private app: any; // Express app
@ -65,7 +65,7 @@ class PenpotMcpServer {
} }
); );
this.tools = new Map<string, Tool>(); this.tools = new Map<string, ToolInterface>();
this.wsServer = new WebSocketServer({ port: 8080 }); this.wsServer = new WebSocketServer({ port: 8080 });
this.setupMcpHandlers(); this.setupMcpHandlers();
@ -80,7 +80,7 @@ class PenpotMcpServer {
* the internal registry for later execution. * the internal registry for later execution.
*/ */
private registerTools(): void { private registerTools(): void {
const toolInstances: Tool[] = [new HelloWorldTool(), new ToolPrintText(this.connectedClients)]; const toolInstances: ToolInterface[] = [new HelloWorldTool(), new PrintTextTool(this.connectedClients)];
for (const tool of toolInstances) { for (const tool of toolInstances) {
this.tools.set(tool.definition.name, tool); this.tools.set(tool.definition.name, tool);

View File

@ -5,12 +5,12 @@ import "reflect-metadata";
import { ToolResponse } from "./ToolResponse"; import { ToolResponse } from "./ToolResponse";
/** /**
* Defines the contract for MCP tool implementations. * Base interface for MCP tool implementations.
* *
* This interface maintains compatibility with the MCP protocol while * This interface maintains compatibility with the MCP protocol.
* supporting both type-safe and traditional implementations. * Most implementations should extend the Tool abstract class instead.
*/ */
export interface Tool { export interface ToolInterface {
/** /**
* The tool's unique identifier and metadata definition. * The tool's unique identifier and metadata definition.
*/ */
@ -37,12 +37,12 @@ interface PropertyMetadata {
/** /**
* Base class for type-safe tools with automatic schema generation and validation. * Base class for type-safe tools with automatic schema generation and validation.
* *
* This class directly implements the Tool interface while providing type safety * This class provides type safety through automatic validation and strongly-typed
* through automatic validation and strongly-typed protected methods. * protected methods. All tools should extend this class.
* *
* @template TArgs - The strongly-typed arguments class for this tool * @template TArgs - The strongly-typed arguments class for this tool
*/ */
export abstract class TypeSafeTool<TArgs extends object> implements Tool { export abstract class Tool<TArgs extends object> implements ToolInterface {
private _definition: MCPTool | undefined; private _definition: MCPTool | undefined;
constructor(private ArgsClass: new () => TArgs) {} constructor(private ArgsClass: new () => TArgs) {}
@ -81,7 +81,7 @@ export abstract class TypeSafeTool<TArgs extends object> implements Tool {
} }
// Call the type-safe implementation // Call the type-safe implementation
return await this.executeTypeSafe(argsInstance); return await this.executeCore(argsInstance);
} catch (error) { } catch (error) {
if (error instanceof Error) { if (error instanceof Error) {
throw error; throw error;
@ -201,12 +201,9 @@ export abstract class TypeSafeTool<TArgs extends object> implements Tool {
protected abstract getToolDescription(): string; protected abstract getToolDescription(): string;
/** /**
* Executes the tool with strongly-typed, pre-validated arguments. * Executes the tool's core logic.
* *
* This method receives fully validated and typed arguments, providing * @param args - The (typed) tool arguments
* complete type safety without any casting or manual validation.
*
* @param args - The validated, strongly-typed arguments
*/ */
protected abstract executeTypeSafe(args: TArgs): Promise<ToolResponse>; protected abstract executeCore(args: TArgs): Promise<ToolResponse>;
} }

View File

@ -1,5 +1,5 @@
import { IsNotEmpty, IsString } from "class-validator"; import { IsNotEmpty, IsString } from "class-validator";
import { TypeSafeTool } from "../interfaces/Tool.js"; import { Tool } from "../interfaces/Tool.js";
import "reflect-metadata"; import "reflect-metadata";
import type { ToolResponse } from "../interfaces/ToolResponse.js"; import type { ToolResponse } from "../interfaces/ToolResponse.js";
import { TextResponse } from "../interfaces/ToolResponse.js"; import { TextResponse } from "../interfaces/ToolResponse.js";
@ -22,7 +22,7 @@ export class HelloWorldArgs {
* This tool directly implements the Tool interface while maintaining full * This tool directly implements the Tool interface while maintaining full
* type safety through the protected executeTypeSafe method. * type safety through the protected executeTypeSafe method.
*/ */
export class HelloWorldTool extends TypeSafeTool<HelloWorldArgs> { export class HelloWorldTool extends Tool<HelloWorldArgs> {
constructor() { constructor() {
super(HelloWorldArgs); super(HelloWorldArgs);
} }
@ -43,7 +43,7 @@ export class HelloWorldTool extends TypeSafeTool<HelloWorldArgs> {
* *
* @param args - The validated HelloWorldArgs instance * @param args - The validated HelloWorldArgs instance
*/ */
protected async executeTypeSafe(args: HelloWorldArgs): Promise<ToolResponse> { protected async executeCore(args: HelloWorldArgs): Promise<ToolResponse> {
return new TextResponse( return new TextResponse(
`Hello, ${args.name}! This greeting was generated with full type safety and automatic validation.` `Hello, ${args.name}! This greeting was generated with full type safety and automatic validation.`
); );

View File

@ -1,5 +1,5 @@
import { IsNotEmpty, IsString } from "class-validator"; import { IsNotEmpty, IsString } from "class-validator";
import { TypeSafeTool } from "../interfaces/Tool.js"; import { Tool } from "../interfaces/Tool.js";
import { PluginTaskPrintText, PluginTaskPrintTextParams } from "../interfaces/PluginTask.js"; import { PluginTaskPrintText, PluginTaskPrintTextParams } from "../interfaces/PluginTask.js";
import type { ToolResponse } from "../interfaces/ToolResponse.js"; import type { ToolResponse } from "../interfaces/ToolResponse.js";
import { TextResponse } from "../interfaces/ToolResponse.js"; import { TextResponse } from "../interfaces/ToolResponse.js";
@ -23,7 +23,7 @@ export class PrintTextArgs {
* This tool sends a PluginTaskPrintText to connected plugin instances, * This tool sends a PluginTaskPrintText to connected plugin instances,
* instructing them to create and position text elements in the canvas. * instructing them to create and position text elements in the canvas.
*/ */
export class ToolPrintText extends TypeSafeTool<PrintTextArgs> { export class PrintTextTool extends Tool<PrintTextArgs> {
private connectedClients: Set<any>; // WebSocket clients private connectedClients: Set<any>; // WebSocket clients
/** /**
@ -52,7 +52,7 @@ export class ToolPrintText extends TypeSafeTool<PrintTextArgs> {
* *
* @param args - The validated PrintTextArgs instance * @param args - The validated PrintTextArgs instance
*/ */
protected async executeTypeSafe(args: PrintTextArgs): Promise<ToolResponse> { protected async executeCore(args: PrintTextArgs): Promise<ToolResponse> {
try { try {
// Create the plugin task // Create the plugin task
const taskParams = new PluginTaskPrintTextParams(args.text); const taskParams = new PluginTaskPrintTextParams(args.text);