|
| 1 | +# Advanced MCP Server Patterns |
| 2 | + |
| 3 | +This document demonstrates advanced design patterns implemented in the Backstage MCP Server for enhanced tool templating, type safety, and extensibility. |
| 4 | + |
| 5 | +## 🎯 Implemented Patterns |
| 6 | + |
| 7 | +### 1. Generic Base Classes (`BaseTool<TParams, TResult>`) |
| 8 | + |
| 9 | +**Location:** `src/utils/tools/base-tool.ts` |
| 10 | + |
| 11 | +Provides type-safe tool implementation with automatic schema validation: |
| 12 | + |
| 13 | +```typescript |
| 14 | +export abstract class BaseTool<TParams = Record<string, unknown>, TResult = unknown> implements ITool { |
| 15 | + protected abstract readonly paramsSchema: z.ZodSchema<TParams>; |
| 16 | + abstract executeTyped(params: TParams, context: IToolExecutionContext): Promise<TResult>; |
| 17 | + protected abstract formatResult(result: TResult): CallToolResult; |
| 18 | +} |
| 19 | +``` |
| 20 | + |
| 21 | +**Benefits:** |
| 22 | +- ✅ Full TypeScript IntelliSense |
| 23 | +- ✅ Automatic parameter validation |
| 24 | +- ✅ Type-safe result formatting |
| 25 | +- ✅ Consistent error handling |
| 26 | + |
| 27 | +### 2. Enhanced Decorator System |
| 28 | + |
| 29 | +**Location:** `src/decorators/enhanced-tool.decorator.ts` |
| 30 | + |
| 31 | +Advanced decorators with automatic categorization and metadata: |
| 32 | + |
| 33 | +```typescript |
| 34 | +@ReadTool({ |
| 35 | + name: 'get-entity', |
| 36 | + description: 'Retrieve entity data', |
| 37 | + paramsSchema: entitySchema, |
| 38 | + cacheable: true, |
| 39 | + tags: ['entity', 'read'] |
| 40 | +}) |
| 41 | +export class GetEntityTool extends BaseTool<EntityParams, Entity> { |
| 42 | + // Fully type-safe implementation |
| 43 | +} |
| 44 | +``` |
| 45 | + |
| 46 | +**Decorator Types:** |
| 47 | +- `@ReadTool` - GET operations with caching |
| 48 | +- `@WriteTool` - POST/PUT with confirmation |
| 49 | +- `@AuthenticatedTool` - Requires authentication |
| 50 | +- `@BatchTool` - Batch operations with size limits |
| 51 | + |
| 52 | +### 3. Strategy Pattern for Execution Contexts |
| 53 | + |
| 54 | +**Location:** `src/utils/tools/execution-strategies.ts` |
| 55 | + |
| 56 | +Different execution strategies for various scenarios: |
| 57 | + |
| 58 | +```typescript |
| 59 | +// Standard execution |
| 60 | +const standardTool = ToolFactory.create() |
| 61 | + .withStrategy(new StandardExecutionStrategy()) |
| 62 | + .build(); |
| 63 | + |
| 64 | +// Cached execution |
| 65 | +const cachedTool = ToolFactory.create() |
| 66 | + .withStrategy(new CachedExecutionStrategy(5 * 60 * 1000)) // 5 min TTL |
| 67 | + .build(); |
| 68 | + |
| 69 | +// Batched execution |
| 70 | +const batchTool = ToolFactory.create() |
| 71 | + .withStrategy(new BatchedExecutionStrategy()) |
| 72 | + .build(); |
| 73 | +``` |
| 74 | + |
| 75 | +### 4. Middleware Pipeline Pattern |
| 76 | + |
| 77 | +**Location:** `src/utils/tools/middleware.ts` |
| 78 | + |
| 79 | +Extensible middleware system for cross-cutting concerns: |
| 80 | + |
| 81 | +```typescript |
| 82 | +export const AuthenticatedTool = ToolFactory |
| 83 | + .create() |
| 84 | + .use(new AuthenticationMiddleware()) |
| 85 | + .use(new ValidationMiddleware()) |
| 86 | + .use(new LoggingMiddleware()) |
| 87 | + .build(); |
| 88 | +``` |
| 89 | + |
| 90 | +**Built-in Middleware:** |
| 91 | +- `AuthenticationMiddleware` - Handles auth requirements |
| 92 | +- `ValidationMiddleware` - Input validation |
| 93 | +- `CachingMiddleware` - Response caching |
| 94 | + |
| 95 | +### 5. Builder Pattern for Tool Configuration |
| 96 | + |
| 97 | +**Location:** `src/utils/tools/tool-builder.ts` |
| 98 | + |
| 99 | +Fluent API for tool creation and configuration: |
| 100 | + |
| 101 | +```typescript |
| 102 | +export const MyTool = ToolFactory |
| 103 | + .createReadTool() |
| 104 | + .name('my-tool') |
| 105 | + .description('A powerful tool') |
| 106 | + .schema(mySchema) |
| 107 | + .version('1.0.0') |
| 108 | + .tags('category', 'type') |
| 109 | + .cacheable(true) |
| 110 | + .requiresConfirmation(false) |
| 111 | + .use(new ValidationMiddleware()) |
| 112 | + .withStrategy(new CachedExecutionStrategy()) |
| 113 | + .withClass(MyToolImplementation) |
| 114 | + .build(); |
| 115 | +``` |
| 116 | + |
| 117 | +### 6. Plugin Architecture |
| 118 | + |
| 119 | +**Location:** `src/utils/plugins/plugin-manager.ts` |
| 120 | + |
| 121 | +Extensible plugin system for server enhancements: |
| 122 | + |
| 123 | +```typescript |
| 124 | +export class MyPlugin implements IMcpPlugin { |
| 125 | + name = 'my-plugin'; |
| 126 | + version = '1.0.0'; |
| 127 | + |
| 128 | + async initialize(context: IToolRegistrationContext): Promise<void> { |
| 129 | + // Register tools, add middleware, etc. |
| 130 | + } |
| 131 | + |
| 132 | + async destroy(): Promise<void> { |
| 133 | + // Cleanup resources |
| 134 | + } |
| 135 | +} |
| 136 | +``` |
| 137 | + |
| 138 | +## 🚀 Usage Examples |
| 139 | + |
| 140 | +### Basic Tool with Type Safety |
| 141 | + |
| 142 | +```typescript |
| 143 | +import { BaseTool } from '../utils/tools/base-tool.js'; |
| 144 | +import { ReadTool } from '../decorators/enhanced-tool.decorator.js'; |
| 145 | + |
| 146 | +const paramsSchema = z.object({ |
| 147 | + entityRef: z.string(), |
| 148 | + fields: z.array(z.string()).optional(), |
| 149 | +}); |
| 150 | + |
| 151 | +@ReadTool({ |
| 152 | + name: 'get-entity', |
| 153 | + description: 'Get entity by reference', |
| 154 | + paramsSchema, |
| 155 | + cacheable: true, |
| 156 | +}) |
| 157 | +export class GetEntityTool extends BaseTool<z.infer<typeof paramsSchema>, Entity> { |
| 158 | + protected readonly paramsSchema = paramsSchema; |
| 159 | + |
| 160 | + async executeTyped(params: z.infer<typeof paramsSchema>, context: IToolExecutionContext): Promise<Entity> { |
| 161 | + // params.entityRef is fully typed - IntelliSense works! |
| 162 | + return await context.catalogClient.getEntityByRef(params.entityRef); |
| 163 | + } |
| 164 | + |
| 165 | + protected formatResult(result: Entity): CallToolResult { |
| 166 | + return JsonToTextResponse({ status: ApiStatus.SUCCESS, data: result }); |
| 167 | + } |
| 168 | +} |
| 169 | +``` |
| 170 | + |
| 171 | +### Advanced Tool with Middleware and Strategy |
| 172 | + |
| 173 | +```typescript |
| 174 | +export const AdvancedTool = ToolFactory |
| 175 | + .createWriteTool() |
| 176 | + .name('advanced-tool') |
| 177 | + .description('Advanced tool with full feature set') |
| 178 | + .schema(advancedSchema) |
| 179 | + .requiresConfirmation(true) |
| 180 | + .requiresScopes('write', 'admin') |
| 181 | + .use(new AuthenticationMiddleware()) |
| 182 | + .use(new ValidationMiddleware()) |
| 183 | + .use(new AuditMiddleware()) |
| 184 | + .withStrategy(new CachedExecutionStrategy(10 * 60 * 1000)) |
| 185 | + .withClass(AdvancedToolImpl) |
| 186 | + .build(); |
| 187 | +``` |
| 188 | + |
| 189 | +### Plugin-Based Extensions |
| 190 | + |
| 191 | +```typescript |
| 192 | +export class MetricsPlugin implements IMcpPlugin { |
| 193 | + name = 'metrics-plugin'; |
| 194 | + version = '1.0.0'; |
| 195 | + |
| 196 | + async initialize(context: IToolRegistrationContext): Promise<void> { |
| 197 | + // Add metrics middleware to all tools |
| 198 | + context.toolRegistrar.register( |
| 199 | + ToolFactory.create() |
| 200 | + .use(new MetricsMiddleware()) |
| 201 | + .build() |
| 202 | + ); |
| 203 | + } |
| 204 | +} |
| 205 | +``` |
| 206 | + |
| 207 | +## 📊 Benefits Achieved |
| 208 | + |
| 209 | +| Pattern | Benefit | Implementation | |
| 210 | +|---------|---------|----------------| |
| 211 | +| **Generics** | Type safety, IntelliSense | `BaseTool<TParams, TResult>` | |
| 212 | +| **Decorators** | Metadata, categorization | `@ReadTool`, `@WriteTool` | |
| 213 | +| **Strategy** | Execution flexibility | `CachedExecutionStrategy` | |
| 214 | +| **Middleware** | Cross-cutting concerns | Pipeline architecture | |
| 215 | +| **Builder** | Fluent configuration | `ToolFactory.create()` | |
| 216 | +| **Plugin** | Extensibility | `PluginManager` | |
| 217 | + |
| 218 | +## 🔄 Migration Guide |
| 219 | + |
| 220 | +### From Legacy Tools |
| 221 | + |
| 222 | +```typescript |
| 223 | +// Before (Legacy) |
| 224 | +export class LegacyTool { |
| 225 | + static async execute(request, context) { |
| 226 | + // Manual validation, no type safety |
| 227 | + return result; |
| 228 | + } |
| 229 | +} |
| 230 | + |
| 231 | +// After (Modern) |
| 232 | +@ReadTool({ |
| 233 | + name: 'legacy-tool', |
| 234 | + description: 'Modernized legacy tool', |
| 235 | + paramsSchema: legacySchema, |
| 236 | +}) |
| 237 | +export class ModernTool extends BaseTool<LegacyParams, LegacyResult> { |
| 238 | + // Full type safety, automatic validation |
| 239 | +} |
| 240 | +``` |
| 241 | + |
| 242 | +### Using Migration Helper |
| 243 | + |
| 244 | +```typescript |
| 245 | +import { ToolMigrationHelper } from './utils/tools/migration-helper.js'; |
| 246 | + |
| 247 | +const modernTool = ToolMigrationHelper.migrateLegacyTool( |
| 248 | + LegacyTool, |
| 249 | + legacyMetadata, |
| 250 | + { addCaching: true, addValidation: true } |
| 251 | +); |
| 252 | +``` |
| 253 | + |
| 254 | +## 🎯 Best Practices |
| 255 | + |
| 256 | +1. **Use BaseTool for new implementations** - Provides type safety and consistency |
| 257 | +2. **Leverage decorators** - Automatic categorization and metadata |
| 258 | +3. **Apply middleware strategically** - Authentication, validation, caching |
| 259 | +4. **Choose execution strategies** - Standard, cached, or batched based on needs |
| 260 | +5. **Use builder pattern** - Fluent, readable tool configuration |
| 261 | +6. **Create plugins for extensions** - Keep core server clean and extensible |
| 262 | + |
| 263 | +## 🔧 Configuration |
| 264 | + |
| 265 | +### Environment Variables |
| 266 | + |
| 267 | +```bash |
| 268 | +# Enable advanced patterns |
| 269 | +ENABLE_ADVANCED_PATTERNS=true |
| 270 | + |
| 271 | +# Cache settings |
| 272 | +TOOL_CACHE_TTL=300000 |
| 273 | +TOOL_CACHE_MAX_SIZE=1000 |
| 274 | + |
| 275 | +# Plugin settings |
| 276 | +PLUGIN_PATH=./plugins |
| 277 | +ENABLE_PLUGIN_AUTO_LOAD=true |
| 278 | +``` |
| 279 | + |
| 280 | +### Server Configuration |
| 281 | + |
| 282 | +```typescript |
| 283 | +const server = new McpServer({ |
| 284 | + // ... server config |
| 285 | +}); |
| 286 | + |
| 287 | +// Register advanced patterns |
| 288 | +const pluginManager = new PluginManager(); |
| 289 | +pluginManager.register(new MetricsPlugin()); |
| 290 | +pluginManager.register(new SecurityPlugin()); |
| 291 | + |
| 292 | +// Use advanced tool factory |
| 293 | +const advancedTool = ToolFactory.createReadTool() |
| 294 | + .withStrategy(new CachedExecutionStrategy()) |
| 295 | + .build(); |
| 296 | +``` |
| 297 | + |
| 298 | +This implementation provides a solid foundation for scalable, maintainable, and extensible MCP server development with modern TypeScript patterns. |
0 commit comments